├── .DS_Store ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md └── en ├── .DS_Store ├── images ├── .DS_Store ├── .keep ├── banner.png ├── flask-app-link.png ├── flask-app-with-colour.png ├── flask-cakes.png ├── flask-hello-paul.png ├── flask-hello-world.png ├── flask-template.png ├── html-file.png ├── idle-css.png ├── idle-html.png ├── open-terminal.png ├── open-text-editor.png ├── pi-run-web-app.png └── solution.png ├── meta.yml ├── resources └── .keep ├── solutions └── webapp.zip ├── step_1.md ├── step_2.md ├── step_3.md ├── step_4.md ├── step_5.md ├── step_6.md ├── step_7.md └── step_8.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/.DS_Store -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All contributions are assumed to be licensed under the same licence as the source, i.e. [CC BY-SA](http://creativecommons.org/licenses/by-sa/4.0/). This licence must remain in all derivatives of this work. 4 | 5 | ## Issues 6 | 7 | If you find a mistake, bug or other problem, please [open an issue](https://github.com/raspberrypilearning/web-server-flask/issues) in this repository. 8 | 9 | ## Pull Requests 10 | 11 | If you fix a mistake, bug or problem or have something to contribute, please create a pull request for each modification. Please consider grouping modifications sensibly, e.g. don't bundle typo fixes in the same pull request as code changes, instead file them separately. 12 | 13 | Please note that sometimes things are done for pedagogical reasons so changes which make sense from a software engineering perspective (reducing duplication or making use of more advanced programming language features) may not be suitable to maintain the intended educational value. 14 | 15 | ## Derivatives 16 | 17 | The licence must remain in all derivatives of this work. 18 | 19 | ## Licence 20 | 21 | Unless otherwise specified, everything in this repository is covered by the following licence: 22 | 23 | [![Creative Commons Attribution 4.0 International Licence](http://i.creativecommons.org/l/by-sa/4.0/88x31.png)](http://creativecommons.org/licenses/by-sa/4.0/) 24 | 25 | ***Python Web Server with Flask*** by [Paul Hallett](https://github.com/phalt) the [Raspberry Pi Foundation](https://www.raspberrypi.org/) is licensed under a [Creative Commons Attribution 4.0 International Licence](http://creativecommons.org/licenses/by-sa/4.0/). 26 | 27 | Based on a work at https://github.com/raspberrypilearning/python-web-server-with-flask 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Licence 2 | 3 | Unless otherwise specified, everything in this repository is covered by the following licence: 4 | 5 | [![Creative Commons Attribution 4.0 International Licence](http://i.creativecommons.org/l/by-sa/4.0/88x31.png)](http://creativecommons.org/licenses/by-sa/4.0/) 6 | 7 | ***Python Web Server with Flask*** by [Paul Hallett](https://github.com/phalt) the [Raspberry Pi Foundation](https://www.raspberrypi.org/) is licensed under a [Creative Commons Attribution 4.0 International Licence](http://creativecommons.org/licenses/by-sa/4.0/). 8 | 9 | Based on a work at https://github.com/raspberrypilearning/python-web-server-with-flask 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build a Python Web Server with Flask 2 | 3 | Install the lightweight web framework Flask and set up a basic web server with different pages using Python, HTML, and CSS. 4 | 5 | ![Python Web Server with Flask](/en/images/banner.png) 6 | 7 | Find the project online at [projects.raspberrypi.org/en/projects/python-web-server-with-flask](https://projects.raspberrypi.org/en/projects/python-web-server-with-flask) 8 | 9 | ## Resources 10 | For solutions and project materials, see [en/resources](https://github.com/raspberrypilearning/python-web-server-with-flask/tree/master/en/resources) 11 | 12 | ## Contributing 13 | See [CONTRIBUTING.md](CONTRIBUTING.md) 14 | 15 | ## Licence 16 | See [LICENSE.md](LICENSE.md) -------------------------------------------------------------------------------- /en/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/.DS_Store -------------------------------------------------------------------------------- /en/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/.DS_Store -------------------------------------------------------------------------------- /en/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/.keep -------------------------------------------------------------------------------- /en/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/banner.png -------------------------------------------------------------------------------- /en/images/flask-app-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/flask-app-link.png -------------------------------------------------------------------------------- /en/images/flask-app-with-colour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/flask-app-with-colour.png -------------------------------------------------------------------------------- /en/images/flask-cakes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/flask-cakes.png -------------------------------------------------------------------------------- /en/images/flask-hello-paul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/flask-hello-paul.png -------------------------------------------------------------------------------- /en/images/flask-hello-world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/flask-hello-world.png -------------------------------------------------------------------------------- /en/images/flask-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/flask-template.png -------------------------------------------------------------------------------- /en/images/html-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/html-file.png -------------------------------------------------------------------------------- /en/images/idle-css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/idle-css.png -------------------------------------------------------------------------------- /en/images/idle-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/idle-html.png -------------------------------------------------------------------------------- /en/images/open-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/open-terminal.png -------------------------------------------------------------------------------- /en/images/open-text-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/open-text-editor.png -------------------------------------------------------------------------------- /en/images/pi-run-web-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/pi-run-web-app.png -------------------------------------------------------------------------------- /en/images/solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/images/solution.png -------------------------------------------------------------------------------- /en/meta.yml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Build a Python Web Server with Flask 3 | hero_image: images/banner.png 4 | description: Install the Python web framework Flask and set up a basic web server 5 | with different pages 6 | original_url: https://raspberrypi.org/learning/python-web-server-with-flask 7 | theme: yellow 8 | duration: 2 9 | listed: true 10 | ingredient: false 11 | copyedit: true 12 | curriculum: 3, design-0, programming-3, phys-comp-0, manufacture-0, community-0 13 | interests: '' 14 | technologies: python, html-css-javascript 15 | site_areas: projects 16 | hardware: '' 17 | software: python, html-css-javascript 18 | version: 4.1 19 | last_tested: 2018-08-02 20 | steps: 21 | - title: What you will make 22 | - title: Create the app 23 | completion: 24 | - engaged 25 | - title: Add a new page 26 | - title: Create a HTML template 27 | - title: Use CSS styles 28 | completion: 29 | - internal 30 | - title: Dynamic content 31 | completion: 32 | - external 33 | - title: 'Challenge' 34 | challenge: true 35 | - title: What can you do now? -------------------------------------------------------------------------------- /en/resources/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/resources/.keep -------------------------------------------------------------------------------- /en/solutions/webapp.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypilearning/python-web-server-with-flask/03370b6bc11a4de8c422d1db7d4a8ed763d2e833/en/solutions/webapp.zip -------------------------------------------------------------------------------- /en/step_1.md: -------------------------------------------------------------------------------- 1 | ## What you will make 2 | 3 | Set up a web server and create a simple website using Flask, Python, and HTML/CSS. 4 | The web server will be able to react to the dynamic content that the user inputs. 5 | 6 | ![A web browser open on a page with blue text on a beige background. The text says 'My website' and has a link to 'Hi Paul'.](images/flask-app-link.png) 7 | 8 | 9 | ### You will need: 10 | - A Raspberry Pi with the latest Raspberry Pi OS 11 | 12 | --- collapse --- 13 | --- 14 | title: Installing Flask 15 | --- 16 | 17 | `Flask` should be pre-installed as part of Raspberry Pi OS, so you shouldn't need to do anything. 18 | 19 | You can install it manually with the command: 20 | 21 | --- code --- 22 | --- 23 | language: bash 24 | line_numbers: false 25 | --- 26 | sudo apt install python3-flask 27 | --- /code --- 28 | --- /collapse --- -------------------------------------------------------------------------------- /en/step_2.md: -------------------------------------------------------------------------------- 1 | ## Create the app 2 | 3 | --- task --- 4 | Open a terminal and use the `mkdir` command to create a new directory inside your documents folder called `webapp`. 5 | 6 | --- code --- 7 | --- 8 | language: bash 9 | line_numbers: false 10 | --- 11 | mkdir ~/Documents/webapp 12 | --- /code --- 13 | 14 | --- /task --- 15 | 16 | --- task --- 17 | 18 | Use the 'change directory' command `cd` to open the new directory. 19 | 20 | --- code --- 21 | --- 22 | language: bash 23 | line_numbers: false 24 | --- 25 | cd ~/Documents/webapp 26 | --- /code --- 27 | --- /task --- 28 | 29 | --- task --- 30 | From the **Programming** menu, open **Thonny**. 31 | --- /task --- 32 | --- task --- 33 | 34 | Add this Python code into the blank file. 35 | 36 | --- code --- 37 | --- 38 | language: python 39 | line_numbers: false 40 | --- 41 | from flask import Flask 42 | 43 | app = Flask(__name__) 44 | 45 | @app.route('/') 46 | def index(): 47 | return 'Hello world' 48 | 49 | if __name__ == '__main__': 50 | app.run(debug=True, host='0.0.0.0') 51 | --- /code --- 52 | --- /task --- 53 | 54 | --- task --- 55 | Save the new file with the name `app.py` inside the `webapp` folder you just created. 56 | --- /task --- 57 | 58 | 59 | --- task --- 60 | Go back to your terminal window and run the script you just wrote: 61 | 62 | --- code --- 63 | --- 64 | language: bash 65 | line_numbers: false 66 | --- 67 | python3 app.py 68 | --- /code --- 69 | 70 | --- /task --- 71 | 72 | If everything is working correctly, the window should show you output similar to this: 73 | 74 | ![pi run web app](images/pi-run-web-app.png) 75 | 76 | --- task --- 77 | From your Raspberry Pi's menu, open **Internet** > **Chromium web browser** 78 | --- /task --- 79 | 80 | --- task --- 81 | In the address bar, type `localhost:5000` and press Enter. You should see the welcome page. 82 | 83 | --- /task --- 84 | 85 | ![Flask Hello world](images/flask-hello-world.png) 86 | 87 | 88 | -------------------------------------------------------------------------------- /en/step_3.md: -------------------------------------------------------------------------------- 1 | ## Add a new page 2 | 3 | To add a new page to your web app, you create a new **route**. 4 | 5 | --- collapse --- 6 | --- 7 | title: What is a route? 8 | --- 9 | 10 | In the code you already have, there is a single route: 11 | 12 | ```python 13 | @app.route('/') 14 | def index(): 15 | return 'Hello world' 16 | ``` 17 | 18 | This route is made up of three parts: 19 | 20 | - `@app.route('/')`: what you add to the web address to access this route - `/` 21 | - `def index()`: the name of the route - `index` 22 | - `return 'Hello world'`: the contents the user will see - `Hello world` 23 | 24 | --- /collapse --- 25 | 26 | --- task --- 27 | 28 | Add the code for a new route to `app.py` and **save** the file. 29 | 30 | --- code --- 31 | --- 32 | language: python 33 | line_numbers: true 34 | line_number_start: 5 35 | line_highlights: 9-11 36 | --- 37 | @app.route('/') 38 | def index(): 39 | return 'Hello world' 40 | 41 | @app.route('/cakes') 42 | def cakes(): 43 | return 'Yummy cakes!' 44 | --- /code --- 45 | 46 | --- /task --- 47 | 48 | --- task --- 49 | 50 | In the **Chromium web browser**, type `localhost:5000/cakes` in the address bar. 51 | 52 | You should see a web page with the text "Yummy cakes!" on it. 53 | 54 | ![Yummy Cakes](images/flask-cakes.png) 55 | 56 | --- /task --- 57 | -------------------------------------------------------------------------------- /en/step_4.md: -------------------------------------------------------------------------------- 1 | ## Create a HTML template 2 | 3 | You can use a **template** to give your page a style. The template will use **HyperText Markup Language (HTML)**. 4 | 5 | 6 | --- task --- 7 | Go to your terminal and press Ctrl + C to stop your flask server. 8 | --- /task --- 9 | 10 | --- task --- 11 | Create a `templates` directory in your `webapp` directory: 12 | 13 | --- code --- 14 | --- 15 | language: bash 16 | line_numbers: false 17 | --- 18 | mkdir templates 19 | --- /code --- 20 | 21 | --- /task --- 22 | 23 | --- task --- 24 | 25 | Go back to **Thonny** and create a new file. Save this file as `index.html` inside your `templates` folder. 26 | 27 | --- /task --- 28 | 29 | --- task --- 30 | Add this code to `index.html` and **save** your changes. 31 | 32 | --- code --- 33 | --- 34 | language: html 35 | line_numbers: true 36 | --- 37 | 38 | 39 |

My website

40 | 41 | 42 | --- /code --- 43 | 44 | ![A new file called index.html containing the code above](images/html-file.png) 45 | 46 | --- /task --- 47 | 48 | --- task --- 49 | 50 | 51 | 52 | --- /task --- 53 | 54 | --- task --- 55 | 56 | Return to your `app.py` file and change the first line of code: 57 | 58 | --- code --- 59 | --- 60 | language: python 61 | line_numbers: true 62 | --- 63 | from flask import Flask, render_template 64 | --- /code --- 65 | 66 | --- /task --- 67 | 68 | --- task --- 69 | Change the `index()` route to use your `index.html` HTML template: 70 | 71 | --- code --- 72 | --- 73 | language: python 74 | line_numbers: true 75 | line_number_start: 5 76 | line_highlights: 7 77 | --- 78 | @app.route('/') 79 | def index(): 80 | return render_template('index.html') 81 | --- /code --- 82 | 83 | --- /task --- 84 | 85 | --- task --- 86 | 87 | Save `app.py` then go back to the terminal and run it to restart your server: 88 | 89 | --- code --- 90 | --- 91 | language: bash 92 | line_numbers: false 93 | --- 94 | python3 app.py 95 | --- /code --- 96 | 97 | --- /task --- 98 | 99 | --- task --- 100 | 101 | Go to `localhost:5000/` page in **Chromium** to see your new HTML template displayed. 102 | 103 | ![A web browser pointed at localhost:5000 with the text 'My website' in a large header font](images/flask-template.png) 104 | 105 | --- /task --- 106 | 107 | -------------------------------------------------------------------------------- /en/step_5.md: -------------------------------------------------------------------------------- 1 | ## Use CSS styles 2 | 3 | **Cascading Style Sheets (CSS)** are rules to tell a browser how to display HTML content. 4 | 5 | --- task --- 6 | 7 | Open a new terminal window, so that you can leave the Flask web server running in the other one. 8 | 9 | --- /task --- 10 | 11 | --- task --- 12 | 13 | Make sure you are in the `webapp` directory using this command: 14 | 15 | --- code --- 16 | --- 17 | language: bash 18 | line_numbers: false 19 | --- 20 | cd ~/Documents/webapp 21 | --- /code --- 22 | 23 | --- /task --- 24 | 25 | --- task --- 26 | 27 | Create a new directory called `static`. 28 | 29 | --- code --- 30 | --- 31 | language: bash 32 | line_numbers: false 33 | --- 34 | mkdir static 35 | --- /code --- 36 | 37 | --- /task --- 38 | 39 | --- task --- 40 | 41 | Go back to **Thonny** and create a new file. Save this file as `style.css` inside your `static` folder. 42 | 43 | --- /task --- 44 | 45 | --- task --- 46 | 47 | Add the following CSS rules to `style.css` then **save** the file. This is your stylesheet. 48 | 49 | --- code --- 50 | --- 51 | language: css 52 | line_numbers: true 53 | --- 54 | body { 55 | background: beige; 56 | color: blue; 57 | } 58 | --- /code --- 59 | 60 | --- /task --- 61 | 62 | --- task --- 63 | 64 | Now modify your `index.html` HTML template to include the CSS stylesheet: 65 | 66 | --- code --- 67 | --- 68 | language: css 69 | line_numbers: true 70 | line_number_start: 1 71 | line_highlights: 2-4 72 | --- 73 | 74 | 75 | 76 | 77 | 78 |

My website

79 | 80 | 81 | --- /code --- 82 | --- /task --- 83 | 84 | --- task --- 85 | 86 | Save the changes to `index.html` then go back to **Chromium** and refresh the browser. You should see a colourful version of your web app! 87 | 88 | ![Flask app with colour](images/flask-app-with-colour.png) 89 | 90 | --- /task --- 91 | 92 | --- collapse --- 93 | --- 94 | title: I can't see the colours 95 | --- 96 | 97 | If your web app doesn't look right, your CSS file might not be in the right directory. 98 | 99 | Make sure your `webapp` project directory contains the following files and has the following structure: 100 | 101 | ``` 102 | ├── app.py 103 | ├── static 104 | │   └── style.css 105 | └── templates 106 | └── index.html 107 | └── cakes.html 108 | ``` 109 | --- /collapse --- -------------------------------------------------------------------------------- /en/step_6.md: -------------------------------------------------------------------------------- 1 | ## Dynamic content 2 | 3 | Websites like Facebook, YouTube and BBC News have dynamic content: these websites show different content within the same template. 4 | 5 | Now you will create a new route on your website so that the page will show you a personalised greeting. 6 | 7 | --- task --- 8 | 9 | Open `app.py` and add a new route to your application: 10 | 11 | --- code --- 12 | --- 13 | language: python 14 | line_numbers: true 15 | line_number_start: 5 16 | line_highlights: 9-11 17 | --- 18 | @app.route('/') 19 | def index(): 20 | return render_template('index.html') 21 | 22 | @app.route('/hello/') 23 | def hello(name): 24 | return render_template('page.html', name=name) 25 | --- /code --- 26 | 27 | --- /task --- 28 | 29 | --- task --- 30 | 31 | Create a new HTML template in the templates folder called `page.html`, and add the following HTML code to it: 32 | 33 | --- code --- 34 | --- 35 | language: html 36 | line_numbers: true 37 | --- 38 | 39 | 40 |

Hello {{ name }}!

41 | 42 | 43 | --- /code --- 44 | 45 | --- /task --- 46 | 47 | --- task --- 48 | 49 | Save both files, then visit `localhost:5000/hello/Paul` in the **Chromium browser**. 50 | 51 | The page you see should look like this: 52 | 53 | ![A website displaying the text 'Hello Paul!'](images/flask-hello-paul.png) 54 | 55 | Try replacing `Paul` in the address bar with a different name! 56 | 57 | --- /task --- 58 | 59 | --- task --- 60 | Open your `index.html` template and add a link to the hello page under the heading. 61 | 62 | --- code --- 63 | --- 64 | language: html 65 | line_numbers: true 66 | line_number_start: 6 67 | line_highlights: 7 68 | --- 69 |

My website

70 | Hi Paul 71 | --- /code --- 72 | 73 | --- /task --- 74 | 75 | --- task --- 76 | 77 | Save the changes to `index.html`, and then open `localhost:5000` to see the updated version. 78 | 79 | ![A website with blue text on a beige background. The text reads 'My website' in a header font and then a link to 'Hi Paul'](images/flask-app-link.png) 80 | 81 | --- /task --- 82 | 83 | --- collapse --- 84 | --- 85 | title: How does this route work? 86 | --- 87 | 88 | - `@app.route('/hello/')`: the `` part passes the text written in the URL into the `hello` function as a variable called `name`. 89 | - `def hello(name)`: this is the function that determines what content is shown. Here, the function takes the given name as a parameter. 90 | - `return render_template('page.html', name=name)`: this code looks up the template `page.html` and passes in the variable `name` from the URL so that the template can use it. 91 | 92 | 93 | Flask uses `jinja`, a Python library for rendering templates. Look at this code with the braces (curly brackets): 94 | 95 | ```html 96 |

Hello {{ name }}!

97 | ``` 98 | 99 | This code tells the template to use the variable `name` that was passed in the route function `hello`. 100 | 101 | Visiting `localhost:5000/hello/` without a name creates an error. 102 | 103 | --- /collapse --- -------------------------------------------------------------------------------- /en/step_7.md: -------------------------------------------------------------------------------- 1 | ## Challenge 2 | 3 | --- task --- 4 | Add another route for your website. 5 | --- /task --- 6 | 7 | --- task --- 8 | Look up some **hex codes** for other colours you could use in your CSS. 9 | --- /task --- 10 | 11 | --- task --- 12 | Look up some more HTML tags to use in your templates. 13 | --- /task --- 14 | 15 | --- task --- 16 | Use dynamic content in another way in your website. 17 | --- /task --- -------------------------------------------------------------------------------- /en/step_8.md: -------------------------------------------------------------------------------- 1 | ## What can you do now? 2 | 3 | Try our [Introduction to web](https://projects.raspberrypi.org/en/pathways/web-intro) project pathway where you will learn how to structure and style webpages with images, lists, fonts, quotes, links, and animation. 4 | 5 | --- print-only --- 6 | 7 | ![Completed project](images/solution.png) 8 | 9 | --- /print-only --- 10 | 11 | --- no-print --- 12 | 13 | 14 | 15 | --- /no-print --- 16 | 17 | Or, why not try out another [HTML and CSS](https://projects.raspberrypi.org/en/projects?software%5B%5D=html-css-javascript) project. --------------------------------------------------------------------------------