Styling ======= At present the application is functional, but needs styling and making the application more user friendly. The input for both the quiz name and question have poor feedback, it is difficult to tell whether the text input is ready to be used. Whenever a fault is made the user requires better feedback on what is the problem. As far as possible make the styling in css files placed under the folder *static/css*. Flash Messaging --------------- Flask has a feedback system called *flash*. These have optional categories success, error, info and warning. A message is generated within the application and is then displayed at the relevant template. An error or warning message displays at the template where the problem arises, but a success or info message will often occur at the next template, depending on the application logic. Since all templates might display a message the mechanism to display can be delegated to *base.html*. Flash has to be imported into *bird.py* and requires a hidden key, this is already covered by our *config.py*. To make the messages standout apply a style. This can be part of a general style file. If we treated all messages alike as errors, say, then our template needs a Jinja method to display::

Flashing messages

{% for message in get_flashed_messages() %}
Error: {{ message }}
{% endfor %} and we only need one method in our styling file, place this in *base.html* just before the call for {% block content %}:: .alert-error { background-color: red; color: white; } Since we wish to have different categories we need to change our methods in *base.html*:: {% for category, message in get_flashed_messages(with_categories=True) %}
Message: {{ message }}
{% endfor %} and our styling becomes:: .alert { display: inline-block; padding: 12px; border-radius: 3px; font-size: 1.2rem; margin-bottom: 16px; border-width: 2px; border-style: solid; } .alert-error { display: inline-block; border-color: darkred; background-color: red; color: white; } .alert-warning { display: inline-block; border-color: orange; background-color: yellow; color: black; } .alert-info { display: inline-block; border-color: blue; background-color: cyan; color: black; } Create a style sheet applicable to all templates, place it in the *static* folder in its own sub-folder *css*. The first entry of *all.css* will style the flash messages. By now your files should be as follows:: Flask ├──static │ ├──css │ │ └──all.css │ │ │ └──songs │ ├──Common Cuckoo.wav │ ├──Common Wood Pigeon.wav │ ├──Eurasian Blue Tit.mp3 │ ├──Eurasian Skylark.mp3 │ └──European Green Woodpecker.mp3 │ ├──templates │ ├──index.html │ ├──base.html │ ├──quiz.html │ ├──result.html │ ├──final.html │ └──account.html │ ├──bird.py ├──venv ├──config.py └──quizbird.csv Another change to *base.html* is to add a link to our newly made style file *all.css*, put it in the section, use the Jinja format to point to the stylesheet:: Modern Font ----------- Let's ensure that all the fonts are of a modern unified look, load up the google *Inter* font. Put the following lines into *base.html* just before the link to the stylesheet link:: Now we can use the font in our stylesheet, *all.css*:: /* // : Use a value from 100 to 900 // : Use a unique and descriptive class name // when in css file keep all the types (h1..h3) separate, // can join when used in html page // keep the types in size order */ h1 { font-family: "Inter", sans-serif; font-optical-sizing: auto; font-weight: 500; font-style: normal; text-align: center; font-size: 40px; } h2 { font-family: "Inter", sans-serif; font-optical-sizing: auto; font-weight: 400; font-style: normal; text-align: center; } h3 { font-family: "Inter", sans-serif; font-optical-sizing: auto; font-weight: 500; font-style: normal; text-align: center; font-size: 20px; } p { font-family: "Inter", sans-serif; font-optical-sizing: auto; font-weight: 400; font-style: normal; text-align: center; } So that *index.html* is a bit more eyecatching put a shadow behind the lettering, use class "shadow", remove the inline styling :

Welcome to the Bird Song Quiz.


How good are you on bird songs.

Now add the *h1.shadow* and *h3.shadow* to *all.css*:: h1.shadow { font-family: "Inter", sans-serif; font-optical-sizing: auto; font-weight: 500; font-style: normal; text-align: center; font-size: 40px; text-shadow: 3px 3px 3px #ccff02; color: #ff073a; } h3.shadow { font-family: "Inter", sans-serif; font-optical-sizing: auto; font-weight: 500; font-style: normal; text-align: center; font-size: 20px; color: #ff073a; text-shadow: 2px 2px 2px #ccff02; } If we were to run the application the *Flash* messaging would be in a default font style, adapt the stylesheet as follows:: .alert { display: inline-block; padding: 12px; border-radius: 3px; font-family: "Inter", sans-serif; font-optical-sizing: auto; font-weight: 900; font-style: normal; font-size: 1.2rem; margin-bottom: 16px; border-width: 2px; border-style: solid; } Buttons instead of Links ------------------------ A good looking button is better than an html link. The button's pattern is borrowed from mdn Mozilla. Use a blue button for sequential links and a grey button for the reset/return to the home page, add to *all.css*:: .button { border: 0; height: 75 px; line-height: 2.5; padding: 0 20px; font-size: 1rem; text-align: center; color: #fff; cursor: pointer; text-shadow: 1px 1px 1px #000; border-radius: 10px; background-color: rgba(87, 153, 230, 1); /* blue */ background-image: linear-gradient( to top left, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2) 30%, rgba(0, 0, 0, 0) ); box-shadow: inset 2px 2px 3px rgba(255, 255, 255, 0.6), inset -2px -2px 3px rgba(0, 0, 0, 0.6); } .blue { background-color: rgba(87, 153, 230, 1); color: white; height: 75 px; } .blue:hover { background-color: rgba(71, 97, 229, 1); } .blue:active { box-shadow: inset -2px -2px 3px rgba(255, 255, 255, 0.6), inset 2px 2px 3px rgba(0, 0, 0, 0.6); } .grey { background-color: rgba(110, 117, 125, 1); color: white; } .grey:hover { background-color: rgba(44, 65, 102, 1); } .grey:active { box-shadow: inset -2px -2px 3px rgba(255, 255, 255, 0.6), inset 2px 2px 3px rgba(0, 0, 0, 0.6); } .. |home| image:: ../figures/home_07style.png :width: 150 :height: 39 :alt: home page .. |dupl| image:: ../figures/dupl_07style.png :width: 136 :height: 46 :alt: account duplicate name .. |acc| image:: ../figures/user_07style.png :width: 136 :height: 45 :alt: account .. |quiz| image:: ../figures/quiz_07style.png :width: 140 :height: 53 :alt: quiz .. |corr| image:: ../figures/correct_07style.png :width: 118 :height: 37 :alt: correct result .. |incorr| image:: ../figures/wrong_07style.png :width: 126 :height: 40 :alt: incorrect result .. |final| image:: ../figures/final_07style.png :width: 150 :height: 41 :alt: final +---------+---------+-----------+ | |home| | |acc| | |dupl| | +---------+---------+-----------+ | index | account | duplicate | +---------+---------+-----------+ +--------+--------+----------+---------+ | |quiz| | |corr| | |incorr| | |final| | +--------+--------+----------+---------+ | quiz | right | wrong | final | +--------+--------+----------+---------+ Much of the styling is in place, but we can see odd bits are not centralised nor is the input in the forms user friendly. The buttons could be better positioned to each other and against the text of each template. Let's see what we can do.