Semantic markup for the little ones

There are the three pillars of any web page: HTML, CSS and JavaScript.

CSS is a style sheet language used for describing presentation of web pages and JavaScript is used to control behavior of it. And at last not least, HTML represents structure and content of web pages. In other words, HTML is skeleton, then CSS is its skin and JavaScript is its brain.

In a nutshell, semantic markup is markup that introduces meaning and structure to web pages rather than just its appearance. Semantic markup is not about using only HTML5 tags such as <header>, <footer> or <article>. Adding <header> to a web page will not make it immediately semantically correct. What shall we do then? Let's find out 🧐

Firefox
Firefox
Header
Main
Section
Section
Section

Table of contents

What is semantic markup and why should you write it?

There are two types of elements in HTML:

  1. Non-semantic: tell nothing about its content. Examples of non-semantic elements: <div> and <span>
  2. Semantic: clearly define its content. Examples of semantic elements: <h1>, <a>, <li>, etc.

Thus, semantic markup is just a markup with semantic elements or in other words a markup with a meaning. What does it mean?

By using HTML elements properly you can create pages that impart more information than if you simply surround everything with <div> or <span> tags. With semantic markup users, machines and developers will be able to easily understand content structure, relationship among elements and nature of content. Also semantic markup is easier to maintain, understand in debugging and developing after all.

With regards to accessibility, semantic markup tell users with screen reader where they are and how they can interact with a web page.

Check out examples below for further clarity. Non-semantic element <div> tells nothing about the content below. With some effort you can improve it just by using special HTML element for unordered lists <ul> instead of using non-semantic <div>. Now users with screen readers, search engines and developers who saw the markup for the first time would immediately understand that the element below represents a list of something.

Keep reading to learn the basics of semantic markup. Some things would seem obvious, but I have seen too much incorrect using of markup in my practice so it inspired me to write this guide.

There are no tips like «don't forget about closing paired tags» or «write tags name in lowercase instead uppercase». These kinds of mistakes are resolved nowadays in our code editors.

Let's go!

Do not use <div> for everything

There are a lot of various semantic tags in HTML. There are six tags fonly or headings. There are dozen tags for text formatting. Tables, inputs, lists... After all HTML5 was presented us even more new tags: for headers, navs, footers, sections, articles... There are plenty to choose from. It will need to write a separate article only about all HTML tags.

It may seem like too much tags so sometimes it seems easier to use divs for everything. Of course, it will work fine with using only divs, but you will drown in divs hell. Do you want it?

Stairway to hell.html
1                                                                                                                        </div>
2                                                                                                                    </div>
3                                                                                                                </div>
4                                                                                                            </div>
5                                                                                                        </div>
6                                                                                                    </div>
7                                                                                                </div>
8                                                                                            </div>
9                                                                                        </div>
10                                                                                    </div>
11                                                                                </div>
12                                                                            </div>
13                                                                        </div>
14                                                                    </div>
15                                                                </div>
16                                                            </div>
17                                                        </div>
18                                                    </div>
19                                                </div>
20                                            </div>
21                                        </div>
22                                    </div>
23                                </div>
24                            </div>
25                        </div>
26                    </div>
27                </div>
28            </div>
29        </div>
30    </div>
31</div>

In this example below is used only divs elements. Nothing is clear when you first look at this markup. In addition, you'll have to use unnecessary JavaScript code with this markup to make this fake links clickable.

index.html
1<div>
2  <div>Hello</div>
3  <div>
4    <div>
5      <div>
6        <div>Home</div>
7      </div>
8      <div>
9        <div>About</div>
10      </div>
11      <div>
12        <div>Blog</div>
13      </div>
14    </div>
15  </div>
16</div>

In this example is used semantic tags. It's clear to see that is going on here: that's a header with a nav with links. There are no additional JavaScript because HTML tag <a> does all the work for us by creating all links.

index.html
1<header>
2  <h1>Hello</h1>
3  <nav>
4    <ul>
5      <li>
6        <a href='/home'>Home</a>
7      </li>
8      <li>
9        <a href='/about'>About</a>
10      </li>
11      <li>
12        <a href='/blog'>Blog</a>
13      </li>
14    </ul>
15  </nav>
16</header>

What follows from this? Use <div> element only to structure layout, for the rest you should use appropriate semantic elements.

Use headings

HTML provides us special elements for headings: <h1>, <h2>, <h3>, <h4>, <h5> and <h6>. Whoa, that is a lot! Why not use them?

As you can see, these elements have a level given by the number in their name. The heading level corresponds to the levels of nested sections. Tag <h1> is for a top-level headings, <h2> for a second-level headings, etc.

Of course, you can use again only divs elements and it will work fine. This tip is similar to the previous one. Headings give structure to a web page. Nothing is clear when you first look at the markup on the left, that's just a bunch of divs. In addition, search engines use headings to index structure and content of web pages.

index.html
1<div>
2  <div>The best cinnamon rolls recipe</div>
3  <div>Ingredients</div>
4  <div>Tools</div>
5  <div>Instructions</div>
6  <div>Step 1</div>
7  <div>Step 2</div>
8  <div>Step 3</div>
9  <div>Tips</div>
10</div>
index.html
1<section>
2  <h1>The best cinnamon rolls recipe</h1>
3  <h2>Ingredients</h2>
4  <h2>Tools</h2>
5  <h2>Instructions</h2>
6  <h3>Step 1</h3>
7  <h3>Step 2</h3>
8  <h3>Step 3</h3>
9  <h2>Tips</h2>
10</section>

There are a few tips that will help you use headings like a pro:

  1. Avoid skipping heading levels: always start from <h1>, followed by <h2>, then the less important <h3>, and so on.
  2. Use only one <h1> heading per a web page, and that <h1> should succinctly represent the content on that page. Using more than one <h1> is allowed by the HTML specification, but is not considered as a best practice.
  3. Browsers have default styles for headings. Don't use headings and their default styles to make your text looks big or bold. Instead of it use CSS properties, e.g. font-size or font-weight.

Format text judiciously and thoughtfully

Let's continue talking about texts. There are many elements in HTML for formatting text and some of them have the same meaning at first glance. It happened because modern browsers different default styles which they apply to different html-elements and according to this built-in styles, <b>/<strong> and <i>/<em> look the same.

In the example below there are no any custom styles, there are using only built-in styles for all tags. Pay attention that each pair of tags looks the same:

Choose your fighter
<b> vs. <strong>
<i> vs. <em>

This raises the one of the most frequently asked questions about HTML: what's the difference between <b> and <strong> or <i> and <em> if they look alike? Let's find out.

The first thing that you must find is that when it comes to formatting text there is distinction between visual formatting and meaning formatting. For a while before HTML5 came in, web-developers didn't think about meaning, they thought only about appearance. If they needed to make fancy text, they just made fancy text.

Let's look at an example. <b> and <i> elements are used to draw attention to text. <i> tag represents an idiomatic text and <b> tag brings attention to element. However these elements are better known as <b> for bold and <i> for italic. Key point of these tags is that they are used to draw the reader' attention to the element' contents, which are not otherwise granted special importance. These tags are about visual formatting.

On the other side, <strong> and <em> tags indicate that its contents have special meaning.<strong> element indicates storng importance and <em> element indicates stress emphasis. These tags are about meaning or semanitc formatting.

Examples of the use formatting tags
Examples of using:
  1. <strong>: please turn off lights when you leave
  2. <b>: this article about semantic HTML. I wrote it while my cat was sleeping next to me
  3. <em>: when my dog tries to eat something off the ground I tell him loudly NO! DROP IT!
  4. <i>: «You're saying it wrong», Harry heard Hermione snap. «It's leviOsa, not levioSA

It turns out that <b>/<strong> and <i>/<em> actually don't have the same meaning. They're all different elements, although they have a slight difference that you always have to keep in your head.

Remember: you should use the CSS properties for styling text instead of using tags, e.g. use font-weight property to create boldface text instead of adding <b> or <strong> element to your markup.

Another cornerstone of formating text is a line break element <br>. This empty and self-closing element has one and well-defined purpose to create a line break in a block of text.

We are not going round and around, separating paragraphs of text using <br> is a bad practice! Here's the example of what not to do:

index.html
1<section>
2  <h1>Tips for making the best cinnamon rolls</h1>
3  Don't overheat your milk. It should be between 105-115 degrees F<br/>
4  Make sure to use room temperature butter for the filling<br/>
5  Rub the brown sugar into the butter<br/>
6  Make sure you flour your work surface and the rolling pin<br/>
7  Use a room temperature egg in the dough<br/>
8</section>

Tips for making the best cinnamon rolls

Don't overheat your milk. It should be between 105-115 degrees F
Make sure to use room temperature butter for the filling
Rub the brown sugar into the butter
Make sure you flour your work surface and the rolling pin
Use a room temperature egg in the dough

Use HTML paragraph element <p> together with CSS properties such as margin to separate text instead of using line breaks. This code will be easier to maintain later and markup will be more concise as a result. Here's the example:

index.html
1<section>
2  <h1>Tips for making the best cinnamon rolls</h1>
3  <p>Don't overheat your milk. It should be between 105-115 degrees F</p>
4  <p>Make sure to use room temperature butter for the filling</p>
5  <p>Rub the brown sugar into the butter</p>
6  <p>Make sure you flour your work surface and the rolling pin</p>
7  <p>Use a room temperature egg in the dough</p>
8</section>

Tips for making the best cinnamon rolls

Don't overheat your milk. It should be between 105-115 degrees F

Make sure to use room temperature butter for the filling

Rub the brown sugar into the butter

Make sure you flour your work surface and the rolling pin

Use a room temperature egg in the dough

Furthermore, do not use a line break to define a list. If you put <br> tag after every listed item it'll be an incorrect use of the tag. Check out examples below of incorrect usage line breaks and its corrections with explanations.

There's nothing wrong with using <br> inside listed items, but never do the following if you need to create lists:

index.html
1<h3>Ingredients</h3>
2<div>
3  Milk<br/>
4  Sugar<br/>
5  Quick rise yeast<br/>
6  Butter<br/>
7  Egg + egg yolk<br/>
8  Bread flour<br/>
9  Cinnamon<br/>
10</div>

If you use special HTML lists tags, you don't need to break lines after listed items as it is automatically inserted:

index.html
1<h3>Ingredients</h3>
2<ul>
3  <li>Milk</li>
4  <li>Sugar</li>
5  <li>Quick rise yeast</li>
6  <li>Butter</li>
7  <li>Egg + egg yolk</li>
8  <li>Bread flour</li>
9  <li>Cinnamon</li>
10</ul>

There is another way to use line breaks wrong. You'll get validation error element <br> not allowed as child of element <br> in this context.

index.html
1<h3>Ingredients</h3>
2<ul>
3  <li>Milk</li>
4  <li>Sugar</li>
5  <li>Quick rise yeast</li>
6  <br/>
7  <br/>
8  <li>Butter</li>
9  <li>Egg + egg yolk</li>
10  <li>Bread flour</li>
11  <li>Cinnamon</li>
12</ul>

If you need extra gaps between listed items you should use for example CSS properties such as padding or margin instead of using line breaks between items. Also you can use CSS pseudo-classes such as :nth-child(), :first-child, :last-child, etc, to add additional gap some elements.

index.html
1<h3>Ingredients</h3>
2<ul>
3  <li>Milk</li>
4  <li>Sugar</li>
5  <li>Quick rise yeast</li>
6  <li>Butter</li>
7  <li>Egg + egg yolk</li>
8  <li>Bread flour</li>
9  <li>Cinnamon</li>
10</ul>

You'll learn more about how to create lists in HTML below

But do not rush to give up on <br> element. No one forbids you to use line breaks. Line breaks can be useful for properly formating addresses and poetry. Check out examples below.

Pay attention to the <address> tag below. This element indicates that its content provides some contact information.

It can be email addresses, addresses of web pages, physical addresses, geographic coordinates, phone numbers, social media links, etc.

index.html
1<address>
2  Santa Claus<br/>
3  123 Elf Road<br/>
4  North Pole<br/>
5  88888
6</address>
Santa Claus
123 Elf Road
North Pole
88888

HTML tag <br> is also useful for writing poems as mentioned above. Pay attention to the <blockquote> tag below. This element indicates that its content quoted from another source.

Don't settle for this implementation. There are many ways for creating quotes, using <blockquote> is just one of them.

index.html
1<blockquote>
2  Roses are red<br/>
3  Violets are blue<br/>
4  Sugar is sweet<br/>
5  And so are you
6</blockquote>
Roses are red
Violets are blue
Sugar is sweet
And so are you

Regarding accessibility: don't worry about it, <br> will cause screen readers to put in a small pause.

Do not make unclickable elements clickable

One of the most common anti-pattern is adding click event listeners to HTML elements that aren't usually clickable. For example, there are a lot of guides how to make divs clickable. To be honest, there is no need to reinvent the wheel because HTML provides us clickable elements under the hood such as buttons and links. Buttons allow users to interact with web content and links allow users to discover more content between pages.

index.html
1<div
2  class="button"
3  onclick="doSomething()">
4  I'm a button!
5</div>
index.html
1<button
2  class="button"
3  onclick="doSomething()">
4  No, I'm a button!
5</button>

Technically both examples above do the same thing and look the same, but it's not that easy. What's the difference if the fake button works? Yes, you can make everything from divs, but you'll lose a lot of the benefits of using a semantically correct clickable elements. They are not obvious, but they are like an iceberg hidden under water. At first, you'll lose accessibility, embed keyboard control and user experience. At second, you'll have to use additional JavaScript code to make divs interactive.

Many articles have been written on this subject, you can find some interesting, in my view, at the end of the page

Use required attributes

Some HTML tags have required attributes. There aren't a lot of them but they are there and developers often forget about them or even don't know. Alternative text attribute alt of HTML image <img> tag is probably the most neglected attribute.

Sometimes it happens that browser might not display images. In these cases browser may replace missing image with text of alternate text attribute. This attribute describes context of an image. For these reasons you should provide useful value for alt whenever possible.

Alternative text also helps users on a screen reader or with a slow Internet connection to decide whether or not the image is important.

The most important rule about alternative text is that it needs to describe its image as concisely as possible. At first do not use keywords as alternate text e.g. for the image of my dog below: 'Dog, corgi, smile, flowers, nature, lake, green'. Instead of this try to describe an image as I did in the example below:

index.html
1<img
2  src='kesha.jpg'
3  alt='A happy smiling dog breed corgi
4  lying in a flower field on a hill
5  with a small pond in the background' />
GALLERYkesha.jpg
A happy smiling dog breed corgi lying in a flower field on a hill with a small pond in the background

Another important requierd attribute is href of already mentioned above HTML element <a> which is used to link from one page to another. This attribute indicates a link destination. If you'll use <a> tag for creating buttons, href obviously will be useless. As it was mentioned above, don't make unclickable elements clickable.

Hint: if you set alt attribute to an empty string it will be indicate that its image is not a key part of content, for example it's decorative. An image with an empty alternative text attribute is not the same as having no alt attribute. If there is no alt attribute on the <img> element, screen readers will announce full name of the image file, which may not make any sense to users.

Avoid using deprecated HTML

HTML is designed as much as possible to be backward compatible with existing web browsers. However, there are a few deprecated HTML tags and attributes. Most of these deprecated tags have equivalent tag or alternate CSS option. Though some browsers might still support deprecated tags, it may have already been removed from the relevant web standards, may be in the process of being dropped or may only be kept for compatibility purposes so that's why you should avoid using it or use with caution.

For example, <center> paired tag is a deprecated and not supported since HTML4. As you might guess from the name, it displays its contents centered horizontally within its containing element.

index.html
1<center>Yay</center>

Instead of using <center> tag use CSS property text-align: center, you'll get the same result.

index.html
1<div class="centered">Yay</div>
index.html
1.centered {
2  text-align: center;
3}

Here is the list of deprecated tags:

  • <applet>
  • <basefont>
  • <center>
  • <dir>
  • <embed>
  • <font>
  • <isindex>
  • <menu>
  • <noembed>
  • <s>
  • <strike>
  • <u>

Most of deprecated attributes also have alternate CSS option. For example, instead of HTML attribute bgcolor that defines background color for an element, you can use CSS property background-color that does the same.

Do not use block elements inside inline

This tip is related to nestings of elements. HTML tags <span> and <div> are both generic elements that group together related parts of a web page. There are slight difference between them. The first one is an inline element, while the second one is a block. Okay, so... What does it mean?

Inline elements don't break content flow i.e. don't start on a new line. Also you can't set height and width to inline elements. If you try to set any width and height it will have no effects. Here are a few elements that have a default inline property:

  1. <span>
  2. <img>
  3. <a>
  4. <label>

Also most of formatting tags are inherently inline: <i>, <b>, <strong>, <em>.

On the other hand, block elements break flow by staring on a new line and take up whole width of it. Also you can easily set height and width values to block elements. Here are a few elements that have a default block property:

  1. <div>
  2. All headings <h1>-<h6>
  3. <p>

Now that we've figured out the difference between inline and block elements it's time to learn important rule: do not use block elements inside inline. Remember: inline elements may contain only data and other inline elements.

If you'll use block elements inside inline you'll end up with validation errors like Element div not allowed as child of element span in this context

index.html
1<span>
2  <div>Yay</div>
3</span>

In the example below the inline element <span> is located inside the block element <div>. There are no errors, there no problems, how wonderful!

index.html
1<div>
2  <span>Yay</span>
3</div>

Exception: inline HTML links tag <a> may contain block elements such as <div>.

Use appropriate markup for lists

Lists are very useful way to organize content. They help perceive and understand an information in web pages.

Of course, HTML supports lists. Seems like there are not a lot of lists in web pages, but actually there are. For example, any navigation is logically list of links. Take a look below at the navigation I've been using myself:

index.html
1<nav>
2  <ul>
3    <li>
4      <a href='/'>Home</a>
5    </li>
6    <li>
7      <a href='/about'>About</a>
8    </li>
9    <li>
10      <a href='/projects'>Projects</a>
11    </li>
12    <li>
13      <a href='/blog'>Blog</a>
14    </li>
15  </ul>
16</nav>

There are two types of lists in HTML: mentioned above <ul> element is for unordered lists and <ol> for ordered. The first is typically rendered as a bulleted list, the second one is typically rendered as a numbered list. HTML element <li> is used to represent an item in all types of lists. The browser's default styling dictates that unordered lists <ul> have bullets and ordered lists <ol> have numbers. However, using CSS properties like list-style-type you may change this default styles.

index.html
1<h3>Ingredients</h3>
2<ul>
3  <li>Milk</li>
4  <li>Sugar</li>
5  <li>Quick rise yeast</li>
6  <li>Butter</li>
7  <li>Egg + egg yolk</li>
8  <li>Bread flour</li>
9  <li>Cinnamon</li>
10</ul>

Ingredients

  • Milk
  • Sugar
  • Quick rise yeast
  • Butter
  • Egg + egg yolk
  • Bread flour
  • Cinnamon
index.html
1<h3>Tips for making the best cinnamon rolls</h3>
2<ol>
3  <li>Don't overheat your milk</li>
4  <li>Use room temperature butter</li>
5  <li>Rub the sugar into the butter</li>
6  <li>Use a room temperature egg</li>
7  <li>Use bread flour</li>
8  <li>Mix the dough with a wooden spoon</li>
9  <li>Flour your work surface</li>
10</ol>

Tips for making the best cinnamon rolls

  1. Don't overheat your milk
  2. Use room temperature butter
  3. Rub the sugar into the butter
  4. Use a room temperature egg
  5. Use bread flour
  6. Mix the dough with a wooden spoon
  7. Flour your work surface

But in fact, there is third type of HTML lists: <dl>. What does it mean? This element encloses a list of groups of terms specified using the <dt> element and descriptions provided by <dd> elements. The main reason for description lists is to preserve semantic connection for term-value pairs which would get lost if we just used unordered or ordered lists. Description lists also have default browser's style, check it out in the example below.

index.html
1<h3>Ingredients</h3>
2<dl>
3  <dt>Milk</dt>
4  <dd>- 2% or whole milk</dd>
5  <dt>Yeast</dt>
6  <dd>- quick rise or instant yeast</dd>
7  <dt>Butter</dt>
8  <dd>- salted or unsalted</dd>
9  <dt>Sugar</dt>
10  <dd>- dark brown sugar</dd>
11</dl>

Ingredients

Milk
Yeast
Butter
Sugar

Let's be honest, descriptions are not the most popular kind of HTML lists, but feel free to use it because there are not any restrictions for its usage.

And not to forget about one of the most important feature of using lists: every list can be nested into another. Lists may be nested as deeply as desired. Nesting lists allow us to structurize web pages content and create nested dropdown navigations.

index.html
1<h3>Ingredients</h3>
2<ul>
3  <li>
4    For the dough
5    <ul>
6      <li>¾ cup warm milk</li>
7      <li>2 ¼ teaspoons yeast</li>
8      <li> ¼ cup sugar</li>
9      <li>1 egg + 1 egg yolk</li>
10      <li>¼ cup butter</li>
11      <li>3 cups flour</li>
12      <li>3/4 teaspoon salt</li>
13    </ul>
14  </li>
15  <li>
16    For the filling
17    <ul>
18      <li>2/3 cup brown sugar</li>
19      <li>1 ½ tablespoons cinnamon </li>
20      <li>¼ cup butter</li>
21    </ul>
22  </li>
23</ul>

Ingredients

  • For the dough
    • ¾ cup warm milk
    • 2 ¼ teaspoons yeast
    • ¼ cup sugar
    • 1 egg + 1 egg yolk
    • ¼ cup butter
    • 3 cups flour
    • 3/4 teaspoon salt
  • For the filling
    • 2/3 cup brown sugar
    • 1 ½ tablespoons cinnamon
    • ¼ cup butter

And that's all!

By the way...

How to check a markup validity?

The easiest and fastest way to validate your markup is use W3C Markup Validation Service. This validator checks a markup validity in different markup languages including HTML. You can validate by URI, by file upload or by direct input your markup.

Unfortunately, you can't validate a markup running in localhost, but you can use any web tunnel to share your local server e.g. ngrok.

Summary

Semantic HTML is just a well-written HTML. Well, just write HTML well.

Read more

  1. The best cinnamon rolls recipe
  2. W3C Markup Validation Service
  3. An accessibility visualization toolkit
  4. An article about inline, block and (WHOA) inline-block behaivor of HTML elements
  5. Depricated HTML tags
  6. List of deprecated HTML attributes
  7. Image caption generator
  8. Alternative texts guide
  9. How (not) to build a button
  10. When is a button not a button?
  11. Lists in HTML