HTML and CSS for Python Developers

HTML and CSS for Python Developers

by Philipp Acsany Sep 07, 2022 basics django flask front-end web-dev

When you want to build websites as a Python programmer, there’s no way around HTML and CSS. Almost every website on the Internet is built with HTML markup to structure the page. To make a website look nice, you can style HTML with CSS.

If you’re interested in web development with Python, then knowing HTML and CSS will help you understand web frameworks like Django and Flask better. But even if you’re just getting started with Python, HTML and CSS can enable you to create small websites to impress your friends.

In this tutorial, you’ll learn how to:

  • Structure a basic HTML file
  • View and inspect HTML in your browser
  • Insert images and page links
  • Style a website with CSS
  • Format HTML with accessibility in mind
  • Use Python to write and parse HTML code

You’ll get an introduction to HTML and CSS that you can follow along with. Throughout this tutorial, you’ll build a website with three pages and CSS styling:

While creating the web project, you’ll craft a boilerplate HTML document that you can use in your upcoming web projects. You may find that the source code will come in handy when you’re working on future projects. You can download it here:

After learning the basics of HTML and CSS, you’ll find ideas on how to continue your journey at the end of the tutorial.

Create Your First HTML File

Think of any website that you’ve recently visited. Maybe you read some news, chatted with friends, or watched a video. No matter what kind of website it was, you can bet that its source code has a basic <html> tag at the beginning.

HTML stands for HyperText Markup Language. HTML was created by Tim Berners-Lee, whose name might also ring a bell for you as the inventor of the World Wide Web.

The hypertext part of HTML refers to building connections between different HTML pages. With hyperlinks, you can jump between pages and surf the Web.

You use markup to structure content in a document. In contrast to formatting, the markup defines the meaning of content and not how it looks. In this section, you’ll learn about HTML elements and their roles.

Writing semantic HTML code will make your documents accessible for a wide range of visitors. After all, you want to enable everybody to consume your content, whether they’re visiting your page with a browser or using screen reading tools.

For each HTML element, there’s a standard that defines its intended use. Today, the standards of HTML are defined by the Web Hypertext Application Technology Working Group (WHATWG). The WHATWG plays a similar role for HTML as the Python Steering Council does for Python.

Approximately 95 percent of websites use HTML, so you’ll be hard-pressed to avoid it if you want to do any web development work in Python.

In this section, you’ll start by creating your first HTML file. You’ll learn how to structure your HTML code to make it readable for your browser and for humans.

The HTML Document

In this section, you’ll create a basic HTML file. The HTML file will contain the base structure that most websites are built with.

To start things off, create a file named index.html with some text:

 1<!-- index.html -->
 2
 3Am I HTML already?

Traditionally, the first file of your website is called index.html. You can think of the index.html page as akin to the main.py or app.py file in a Python project.

So far, the only content of index.html is a plain Am I HTML already? string. You haven’t added any HTML syntax yet, except an HTML comment on line 1. Similar to the Python interpreter not executing comments in your Python code, the browser won’t render the contents of your HTML comments. Still, go ahead and open index.html in your browser:

Plain text HTML page.

Your browser displays the text without complaining. It seems the browser can handle an HTML file, even if its only cue is the extension. That’s good to know, but this behavior also has a downside.

Browsers will always try to render HTML documents, even when the HTML syntax of your document is not valid. Very seldomly, the browser itself will show you something like a SyntaxError, similar to what Python does when you try to run invalid code. This means that you may not notice if you’ve shipped invalid code, which can cause issues for your website visitors.

Update index.html and create a minimal valid HTML document by adding the code below:

 1<!-- index.html -->
 2
 3<!DOCTYPE html>
 4<html lang="en">
 5<head>
 6    <meta charset="utf-8">
 7    <title>Am I HTML already?</title>
 8</head>
 9</html>

This code is the most minimal valid HTML document that you can get away with. Strictly speaking, you could even ditch the lang attribute in line 4. But adding the right language subtag is recommended to declare which natural language your document contains.

At its root, any HTML document that you build will probably follow the structure of the example above. But there’s one important HTML element missing. Open index.html and add <body> below <head>:

 1<!-- index.html -->
 2
 3<!DOCTYPE html>
 4<html lang="en">
 5<head>
 6    <meta charset="utf-8">
 7    <title>Am I HTML already?</title>
 8</head>
 9<body>
10Yes,<br>I am!
11</body>
12</html>

Any valid HTML file must start with a doctype declaration. In this tutorial, you’ll be using <!DOCTYPE html>, which tells the browser that the document contains HTML5 code and should render your page in standard mode:

If a browser finds an outdated, incomplete or missing doctype at the start of the page, they use “quirks mode”, which is more backwards compatible with old practices and old browsers. (Source)

After the doctype declaration, you have an opening <html> tag. In line 12, you can find the corresponding closing </html> tag. Most elements in HTML have an opening tag, some content in between, and a closing tag at the end. These parts can even be on the same line, like the <title> element in line 7.

Other elements, like <meta> in line 6, don’t have a matching closing tag, so they don’t contain any content. These empty elements are so-called void elements. They stand independently and may not even contain attributes. One such example is <br> in line 10, which creates a line break.

HTML tags start with an angle bracket (<) and end with an angle bracket (>). The tag names in between the angle brackets are usually pretty descriptive and state what the HTML element is meant for. A good example is <title> in line 7, in which the content defines the title of your page.

The <body> block contains the mass of your content. You can think of <body> as the part of the HTML document that you can interact with in your browser.

Sometimes the tag names are abbreviated, like the line break element <br> in line 10. To get an overview of other HTML tag names, visit Mozilla’s HTML elements reference.

Once you’ve familiarized yourself with the structure of your HTML document, reload index.html in your browser and check out how your website looks:

Screenshot of a basic HTML page.

Awesome, you’re now displaying the content of your first proper website!

There’s a good chance that you’ll start any web project with a structure like the one that you’ve built in this section. To save yourself some work in the future, you can download the HTML boilerplate code by clicking the link below:

In the next section, you’ll improve the base structure that you’ve created so far. To explore why HTML is called a markup language, you’ll add content and structure to your website.

Whitespace and Text Formatting

The only markup that your HTML document has so far is the base skeleton of your website. Now it’s time to dive in deeper and structure some real content. To have something to work with, add the text below to the <body> block of index.html:

 1<!-- index.html -->
 2
 3<!DOCTYPE html>
 4<html lang="en">
 5<head>
 6    <meta charset="utf-8">
 7    <title>Am I HTML already?</title>
 8</head>
 9<body>
10Hello, World Wide Web!
11This is my first website.
12
13About me
14
15I'm a Python programmer and a bug collector.
16
17Random facts
18
19I don't just like emoji,
20I love emoji!
21
22My most-used emoji are:
23    1. 🐞
24    2. 🐍
25    3. 👍
26
27Links
28
29My favorite websites are:
30    * realpython.com
31    * python.org
32    * pypi.org
33</body>
34</html>

When you open the website in your browser, it seems that the browser didn’t recognize any whitespace at all. Although you distributed your content on multiple lines inside <body>, the browser displays everything as one continuous line:

Screenshot of a HTML page without any markup elements.

As a Python developer, you know that whitespace is a vital ingredient in writing beautiful Python code. The indentation of your Python code makes a difference in how Python executes your code.

Without any additional adjustments, browsers collapse multiple spaces, line breaks, or indentation to one space character. To format your content differently, you must provide further information to the browser. Go ahead and structure index.html by adding HTML tags to your content:

 1<!-- index.html -->
 2
 3<!DOCTYPE html>
 4<html lang="en">
 5<head>
 6    <meta charset="utf-8">
 7    <title>Am I HTML already?</title>
 8</head>
 9<body>
10<h1>Hello, World Wide Web!</h1>
11<p>This is my first website.</p>
12
13<h2>About me</h2>
14<p>I'm a Python programmer and a bug collector.</p>
15
16<h3>Random facts</h3>
17<p>I don't just <em>like</em> emoji,<br>
18I <strong>love</strong> emoji!</p>
19<p>My most-used emoji are:</p>
20<ol>
21    <li>🐞</li>
22    <li>🐍</li>
23    <li>👍</li>
24</ol>
25
26<h2>Links</h2>
27<p>My favorite websites are:</p>
28<ul>
29    <li>realpython.com</li>
30    <li>python.org</li>
31    <li>pypi.org</li>
32</ul>
33</body>
34</html>

By wrapping your text in HTML blocks, you give the browser additional information about your intentions for the content. First, have a look at the HTML elements that wrap bigger chunks of text:

Line HTML Element Description
10 <h1> Main headline of your website
11 <p> Paragraph, to structure text and related content
13 <h2> Second-level headline, nested below <h1>
16 <h3> Third-level headline, nested below <h2>
20 <ol> Ordered list, typically rendered as a numbered list
28 <ul> Unordered list, typically rendered with bullets (•)

You can nest headline elements six levels deep. While you usually only have one <h1> element, you may have multiple <h2> to <h6> tags. Headline elements section your HTML document and are vitally important for screen readers. For example, readers may want to jump from headline to headline to navigate your content.

To write valid and accessible HTML, you must ensure that you don’t skip a headline level in your code. You can think of the headline tags like doors that open onto different floors of a building. One floor can have multiple exits to other floors. But remember, you can’t build a third floor if you don’t have a second floor yet. In other words, there can never be an <h3> element on your page unless you’ve first declared <h2>.

Some of the HTML elements that you used above contain text only. Others contain additional HTML elements that structure the content further:

Line HTML Element Description
17 <em> Emphasizes content
18 <strong> Indicates important content
21 <li> List item, must be contained in a list element

All HTML tags convey meaning. Therefore, it’s vitally important to carefully choose which markup you use for portions of your content. When you use the right semantics, then you enable everybody to consume your content the way that you intended. You make your website accessible for all:

The Web is fundamentally designed to work for all people, whatever their hardware, software, language, location, or ability. When the Web meets this goal, it is accessible to people with a diverse range of hearing, movement, sight, and cognitive ability. (Source)

Some HTML elements are pretty straightforward. For paragraphs, you use <p>. Other elements are a bit harder to grasp:

Kushagra Gour provides a great summary in his blog entry Strong vs Em:

If it’s just visual importance, you want strong. If it alters the sentence meaning, use em.

In other words, em means that you would emphasize the word while speaking. For example, if someone said, “You don’t look bad,” you might wonder, “But do I smell bad?” The placement of emphasis is key to the meaning of the sentence.

If you simply want to draw the reader’s attention to a piece of vocabulary, for example, then you’d probably want to use strong instead.

When in doubt, don’t hesitate to search for HTML names on the Web. You’ll find discussions and usage notes about any HTML element.

Additionally, your browser’s default styling of HTML can give a decent impression by styling elements differently:

Screenshot of an HTML page with default browser styling.

With markup, you add meaning to your website’s content. Writing semantically correct HTML is important for understanding your content.

Using proper semantics in your HTML document isn’t just helpful for the browser. It also makes the rendered HTML page accessible for users who consume your content with text-to-speech software.

If you want to learn more about modern HTML, then HTML5 Doctor is a great resource. To learn more about accessibility, you can check out Google’s course on making the Web accessible to all.

Jumping from one website to another is an essential part of the Internet. These references are called hyperlinks, commonly referred to as links. Without links, websites would exist in a silo, and you could only access them if you knew the web address.

Also, you wouldn’t be able to navigate among multiple pages of a website if you didn’t have links that connected the pages. To connect the HTML documents that you’ve created so far, add a navigation menu to your HTML source code:

<!-- index.html-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Am I HTML already?</title>
</head>
<body>
<nav>
    <a href="emoji.html">Emoji</a>
</nav>
<!-- ... -->
</body>
</html>

With the <nav> element, you declare a section that provides navigation. Inside of <nav>, you add a link with an <a> tag, which is short for anchor. The href attribute stands for Hypertext Reference, containing the link’s target.

With relative links, you can reference files in your directory tree. You may expect to see a URL whenever you have a link, but that’s not the case with relative links.

In this case, you link to a file named emoji.html. The browser understands that it can find emoji.html in the same directory and completes the full URL for you. That way, you don’t need to worry about changing any absolute paths when you decide to deploy your web project at some point.

So far, emoji.html doesn’t exist. To fix this, create a new file named emoji.html next to index.html:

<!-- emoji.html-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>My favorite emoji</title>
</head>
<body>
<nav>
    <a href="index.html">Home</a>
</nav>
<h1>My favorite emoji</h1>
<p>I don't just <em>like</em> emoji,<br>
I <strong>love</strong> emoji!</p>
<p>Here's a list of my most-used emoji:</p>
<ol>
    <li>🐞</li>
    <li>🐍</li>
    <li>👍</li>
</ol>
</body>
</html>

The structure of emoji.html is similar to index.html. The content of <body> in emoji.html is almost identical to the random facts section of index.html, except that you changed the headline and moved it up one level to be <h1>.

At the top of <body>, you also have a <nav> element. This time, however, you’re linking to index.html.

Next, create a new folder named images/ inside of your project directory and add a file named gallery.html:

 1<!-- images/gallery.html -->
 2
 3<!DOCTYPE html>
 4<html lang="en">
 5<head>
 6    <meta charset="utf-8">
 7    <title>Image gallery</title>
 8</head>
 9<body>
10<nav>
11    <a href="../index.html">Home</a>
12    <a href="../emoji.html">Emoji</a>
13</nav>
14<h1>Image gallery</h1>
15</body>
16</html>

You’ll add some images to gallery.html in a moment. But first, have a look at lines 11 and 12, where you link to your other pages.

Because index.html and emoji.html are one folder above gallery.html, you must prefix the link target with two dots (..) and a slash (/).

For more convenient access, you can also add a link to your gallery in the navigation menu of index.html:

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Am I HTML already?</title>
</head>
<body>
<nav>
    <a href="emoji.html">Emoji</a>
    <a href="images/gallery.html">Gallery</a>
</nav>
<!-- ... -->

You can also link to your gallery in emoji.html:

<!-- emoji.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>My favorite emoji</title>
</head>
<body>
<nav>
    <a href="index.html">Home</a>
    <a href="images/gallery.html">Gallery</a>
</nav>
<!-- ... -->

If you add a link to an HTML page, then you always have to think about navigating there from the file that you’re in right now. The gallery.html file is one directory below index.html in a folder named images/. So when you’re linking to gallery.html, then you need to include the subfolder in the link, which you’ve done above.

Relative links are useful for linking pages of your website. When you want to add external links, then you use absolute links:

<!-- index.html -->

<!-- ... --->
<h2>Links</h2>
<p>My favorite websites are:</p>
<ul>
    <li><a href="https://www.realpython.com">realpython.com</a></li>
    <li><a href="https://www.python.org">python.org</a></li>
    <li><a href="https://www.pypi.org">pypi.org</a></li>
</ul>
<!-- ... --->

Instead of linking to HTML files, you’re linking to absolute web addresses in your list of favorite websites. These links are the same ones that you’d type into your browser’s address bar.

Hop to the browser and navigate around your website with the links that you just added:

Links aren’t just handy for connecting the pages of your website—they’re a vital part of the Internet’s infrastructure. If you want to learn more about links, then check out this HTML anchors tutorial.

Another vital element of the Web is images. Without the ability to share vacation pictures and cat GIFs, the Internet would be dull.

You attach images to your HTML document with an <img> element that contains an src attribute. Just like with href in a link, you reference the image source in src. Additionally, you should always use the alt attribute to add alternative text that describes the image. That way, you make your website accessible to people using screen readers.

Update gallery.html and link to three images:

<!-- images/gallery.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Image Gallery</title>
</head>
<body>
<nav>
    <a href="../index.html">Home</a>
    <a href="../emoji.html">Emoji</a>
</nav>
<h1>Image Gallery</h1>
<img src="sky_1.png" alt="Cloudy sky.">
<img src="sky_2.png" alt="Sun shining through a cloudy sky.">
<img src="sky_3.png" alt="Sky with almost no clouds.">
</body>
</html>

You’ll find the sky images inside of the images/ folder after downloading the materials by clicking the code below:

If you use your own images, then you need to adjust the filenames accordingly. Don’t forget to also update the alt text to describe the content of the pictures to make your images accessible.

The alt text is broadly comparable to docstrings in Python. While a docstring may describe the purpose of an object, the alt text describes the content of an image. Just like a docstring, an alt text should end with a dot (.).

Adding additional information to your images is extra work, but it’s worth doing. If there’s a cute dog in a picture, everybody deserves to know that there’s a cute dog in the picture. In case you need any convincing, head over to Alt-texts: The Ultimate Guide on axess lab.

When you open gallery.html in the browser, your page should look similar to this:

Screenshot of an image gallery with default browser styling.

Images are a great way to make your website more visually appealing. However, the image gallery is a bit all over the place, and without any additional styling, the website looks rather old-school. It’s time to change that!

In the next section, you’ll add styling rules to your HTML and gain better control over how the elements on your website look.

Style Your Content With CSS

When you open a plain HTML file in the browser, the browser adds some styling by default. That’s why you were able to differentiate the elements in the previous section although you didn’t add any styling yourself.

That’s basically a service from the browser to you as a human. But strictly speaking, when you write HTML, you only define the markup of your website. Pure HTML doesn’t provide any styling for the elements on your page. To style elements, you need to add CSS.

CSS stands for Cascading Style Sheets. As you’ll see later, you can combine and nest your CSS styling rules, hence the name cascading style sheets.

Just like HTML, it’s a cornerstone technology of the Internet. It helps you to separate the look of your website from the actual content:

In addition to having good semantics and an attractive layout, your content should make logical sense in its source order — you can always place it where you want using CSS later on, but you should get the source order right to start with, so what screen reader users get read out to them will make sense. (Source)

In this section, you’ll learn how to take control of your website’s styling by adding CSS.

Add Color to Your Website

So far, you’ve only used the browser to load your HTML file. But web browsers are powerful tools, and they can help you tremendously when you develop a website.

You can investigate any website with the developer tool pane of your browser. Especially when you work with CSS, your browser’s developer tools come in handy:

Note that the changes in your developer tools don’t persist. When you reload your page, all changes are gone. So once you’re happy with your style adjustments, you need to copy and paste the code into a <style> tag in your HTML file.

Open index.html and add the <style> element inside of <head>:

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Am I HTML already?</title>
    <style>
        body {
            background-color: rgb(20, 40, 60);
            color: rgb(240, 248, 255);
        }

        a {
            color: rgb(255, 111, 111);
        }
    </style>
</head>

<body>
    <!-- ... -->
</body>
</html>

With the <style> element, you can add CSS code to your HTML document. Although browsers aren’t strict about it, you should place the <style> element inside of <head> only. Otherwise, the browser might try to render elements before applying any CSS rules, which can cause a flash of unstyled content.

The content of <style> isn’t HTML code, but CSS. With CSS, you define rules on how to style elements on the page.

With selectors, you define which elements you want to target, followed by a declaration block. In the CSS code above, you’re using type selectors to target <body> and all <a> elements. You’ll use some other kinds of CSS selectors later in the tutorial. If you want to learn more about CSS selectors already, then head over to Mozilla’s CSS selectors page.

The declaration block is delimited by an opening brace ({) and a closing brace (}). You separate the declarations inside a block with semicolons (;). The declaration itself is structured in two parts:

  1. Property: The identifier defining the feature
  2. Value: The description of how the feature should be handled

The property and the value are separated by a colon (:). In the example above, you’re changing the background color of <body> to a dark blue and the text to a very light gray by specifying their RGB values. In the second CSS ruleset, you’re coloring all links in a modern salmon hue.

Colors are an important part of controlling the look and feel of your website. In CSS, you have multiple ways of describing a color. You can check out Smashing Magazine’s guide to modern CSS colors to expand your knowledge about the use of colors in CSS.

Besides the selection of colors, you can change the face of your website with fonts. You already changed the color of the text. Next, adjust the text size of body with the font-size property:

<!-- index. html -->

<!-- ... -->
<style>
    body {
        background-color: rgb(20, 40, 60);
        color: rgb(240, 248, 255);
        font-size: 1.3em;
    }

    a {
        color: rgb(255, 111, 111);
    }
</style>
<!-- ... -->

With font-size: 1.3em; you tell the browser to display the text 1.3 times bigger than the font size of the parent element. The parent element of <body> is <html>, so the text will be displayed 1.3 times larger than the default font size in a browser. The default font size is usually sixteen pixels, so the text will be displayed at a size of around twenty-one pixels.

You could define the font size with pixels directly. However, it’s common to use either percentages or em for text sizes:

Named after the letter “M,” the em unit has a long-standing tradition in typography where it has been used to measure horizontal widths. (Source)

Back when you had to cast letters into metal blocks, the letter M usually took the whole horizontal width of the cast block. In CSS, you can use em for vertical lengths too, and it’s a good unit for creating scalable designs. That means your users can zoom in on your website without breaking the design. This is important when users want to increase the font size to better read your content or when they visit your website from a mobile device.

Pixels and em are only two of many length units in CSS that you can use. When you start focusing on designing your website, it’s worth having a look at these units and playing around with different types of units.

Besides the size of the text, the font that you’re displaying the text in is another cornerstone that impacts the design of your website tremendously.

Change the Font

Fonts are a phenomenal tool for changing the character of your documents. When using fonts on your website, you have two options:

  1. Rely on the fonts your visitor has installed on their system.
  2. Load custom web fonts from either your server or external resources.

With either option, it’s a good idea to define a font stack. When you list more than one font for font-family, the browser then tries to load the fonts from left to right:

<!-- index. html -->

<!-- ... -->
<style>
    body {
        background-color: rgb(20, 40, 60);
        color: rgb(240, 248, 255);
        font-family: "Helvetica", "Arial", sans-serif;
        font-size: 1.3em;
    }

    a {
        color: rgb(255, 111, 111);
    }
</style>
<!-- ... -->

When you declare a font stack as shown above, the browser first tries to load the Helvetica typeface. If the browser can’t find a font in the font stack, then it continues by trying to load the next fallback font. In this case, the browser will load any sans-serif font if neither Helvetica nor Arial is present.

Choosing the right font for your project is a good start to making your content comprehensible. But keep in mind that besides the font, there are other factors that influence the legibility of your texts. You can play around with the look and feel of your web typography by adjusting the font size, line height, and colors. The more readable your texts are, the more accessible they are for everyone!

Open index.html in your browser and have a look at which font displays for you:

Screenshot of an HTML page with styling.

You can use your browser’s developer tools to investigate which font was loaded. What if it’s not Helvetica or Arial? Hop to the comments below and let the Real Python community know which font your system loads!