HTML Building Blocks

Overview

HTML elements are the building blocks from which web pages are built. And, just as there are different kinds of building block, there are different kinds of HTML element. Before we use an HTML element, we need to know what kind of HTML element it is in order to determine what kind of content it may contain, how it may be used with other HTML elements, and what CSS rules can be applied to it. In this page, we will look at how HTML elements have been categorised in the past, and what has changed with the arrival of HTML 5.

Before HTML 5 came along, most HTML elements were classed as being either block-level elements or inline elements, depending on how they were rendered by a user agent. A small number of HTML elements, including the root element (html) and the document metadata elements (base, head, link, meta, style, and title) do not fall into either of these categories because they are not defined within the main body of the HTML document and are thus not rendered by the user agent.

You may also have encountered the term "replaced element". It refers to an HTML element whose purpose is to embed an external resource such as an image, video clip, or browser plugin within an HTML document. Although not officially categorised as either block-level or inline, replacement elements behave like inline elements in most respects, and are thus often considered to be inline elements.

The current HTML 5 specification has largely abandoned the concept of inline versus block-level elements in favour of a somewhat more complex system of content categorisation, although many texts and online sources still frequently refer to HTML element as being either block-level or inline elements, and the default CSS display property of many HTML elements is set to either "block" or "inline".

We will therefore start by examining the traditional view of HTML elements as either block-level or inline elements. We will attempt to highlight the differences between them, and explain how they are treated by user agents. We will then look at the new content categories defined by W3C for HTML 5 elements, together with the concept of content models.

Block level elements

A block level element is rendered by the browser as if there are line breaks both before and after it in the HTML code, and by default will take up the full width of its parent container. Examples include the paragraph element (<p>), the heading elements (<h1> - <h6>), and the header (<header>) and footer (<footer>) elements.

The height of a block-level HTML element will, by default, be determined by its contents, which may consist of other block-level elements, inline elements, text, or data (or any combination thereof). Block level elements are typically used to group together other HTML elements.

We can change the default value of any property of a block-level element by applying CSS to it. We can, for example, set the height and width of a block-level element. We can also set the size of its left, right, top and bottom margins, and we can set the style, width, and colour of its left, right, top and bottom borders (by default, even though a block-level element sits inside a bounding rectangle, its border will be both invisible and dimensionless).

The following HTML code creates a simple web page, using only block-level elements:

<!doctype html>

<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>Block Level Demo</title>
    <style>
      body { border: solid 1px; }
      div, header, main, footer, section, h1, p {
        border: solid 1px #000000;
        margin: 10px 2px;
      }
      header, footer {
        height: 100px;
        background: #eeeeff;
        font-size: 2em;
        text-align: center;
      }
      p { background: #eeeeff; }
      h1 {
        background: #cccccc;
        text-align: center;
      }
      .padded { padding: 2em 4em; }
      .blue { color: blue; border: solid blue; }
    </style>
  </head>

  <body>

    <header>
      This is a header
    </header>

    <main class="blue">
      <h1>This is a Level 1 Heading</h1>
      Here is a hard return (hr): ⤵
      <hr>
      <p>
        This is a paragraph
      </p>
      Here is a paragraph with padding: ⤵
      <p class="padded">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed blandit libero sit amet nunc ultricies, eu feugiat diam placerat. Phasellus tincidunt nisi et lectus pulvinar, quis tincidunt lacus viverra. Phasellus in aliquet massa. Integer iaculis massa id dolor venenatis scelerisque. Morbi non eros a ex interdum molestie in eget leo. Proin pulvinar facilisis eros, sed porta ante imperdiet ut. Suspendisse tincidunt facilisis metus non faucibus. Integer posuere vehicula congue. Sed pharetra felis sapien, at imperdiet diam lacinia quis. Sed pharetra turpis et dui aliquam, in rhoncus elit ornare. Quisque posuere consequat nunc in rutrum. Praesent leo nibh, porta et arcu quis, placerat tincidunt turpis.
      </p>

      <div>
          Here is an empty paragraph: ⤵
        <p>
        </p>
      </div>

    </main>

    <footer>
      This is a footer
    </footer>

  </body>
</html>

Copy and paste this code into a new file in your HTML editor, save the file as block-level-demo.html, and open the file in a web browser. You should see something like the illustration below. Note that we have given each element a solid border so that you can clearly see how it occupies the available space.


This web page contains only block-level HTML elements

This web page contains only block-level HTML elements


By default, block-level elements flow from top to bottom within their parent container. Each new block-level element will sit below the previous block-level component. In the above example, the <body> element contains a <header> element, a <main> element and a <footer> element, in that order.

Within the <main> element we find a level 1 heading (<h1>), a hard return (<hr>), two paragraphs (<p>), and a <div> element with another (empty) paragraph inside it. These elements are stacked vertically within their parent <main> element. What conclusions can we draw from looking at how the browser has rendered our code?

First of all, it clearly demonstrates that, by default, the browser will display each block-level element on its own line, and that each block-level element will take up all of the available width within its container (note that for the sake of clarity, and with the exception of the hard return, we have set margins on all of the elements in our internal style sheet to create a space between adjacent borders).

Another thing to note is that, apart from the header and footer (for both of which we specified a height of 100 pixels), the height of each block level element will be restricted to the height of its contents. In the case of the empty paragraph tag, as you can see, there is no space at all between the top and bottom borders, which have merged to form a solid bar.

You can also see that some of the properties of a parent container will be inherited by its child elements. The <main> container in the example has its color property set to "blue". This means that any text appearing directly within the <main> container will be blue. As we can see, however, the text inside all of its child elements is also blue, because the color property is inherited from the parent element by default.

You might like to experiment with the example by changing the values in the style sheet to see what effect the changes have on the appearance of the page. Try removing or changing the margin, padding, and height properties in the style sheet, for example, to see what happens. You could also try setting the width of one or more elements to various values.

The table below briefly summarises the HTML 5 elements traditionally considered to be block-level elements. The elements are organised according to the currently defined W3C element types, and are otherwise listed alphabetically.


HTML Block-Level Elements
HTML 5 Element Type Elements
Sections address, article, aside, body, footer, h1, h2, h3, h4,h5, h6, header, main, nav, section
Grouping Content blockquote, dd, dialog, dl, dt, hr, li, ol, p, pre, ul
Embedded Content figure
Tabular Data table, tbody, td, tfoot, th, thead, tr
Forms fieldset, form
Interactive Elements detail
Miscellaneous Elements div, figcaption, legend

Inline elements

An inline element, as the name suggests, is rendered in line with text and other inline HTML elements. Unlike a block-level element, an inline element does not need to be displayed on a new line, and does not expand to fill the width of its parent container. Examples of inline elements include all of HTML 5's text level semantic elements (for example <b>, <cite>, <code>, <em>, <i>, <mark>, <span>, <strong>, <sub>, <sup>, and <u>).

Inline elements can and frequently do appear inside other HTML elements, including other inline HTML elements. They can appear inside a block of text, in the middle of a sentence, or even in the middle of a word. They can contain text, data and other inline elements - but not block-level HTML elements.

Unlike block-level elements, the size of the bounding rectangle of an inline element is, by default, determined entirely by the space required to display its contents. You can try setting the width and height properties for a (non-replaceable) inline element using CSS if you like. It won't break your code, but it won't have any effect either.

Setting a value for any of the margin or padding properties of a non-replaceable inline element can have an effect, although precisely what effect it has (or whether it will have an effect) will depend on which margin or padding properties you set. The following table summarises what you can expect to see happening if you set a value of 1em for any of the margin or padding properties of an inline element:


Margin and Padding Properties
Property Value Result
margin 1em A horizontal margin of 1em is inserted between the inline element and its neighbours to left and right (the inline element is shifted to the right by 1em, and everything to the right of it is shifted to the right by 2em).
margin-top 1em No effect.
margin-bottom 1em No effect.
margin-left 1em A horizontal margin of 1em is inserted between the inline element and its neighbours to the left (the inline element and everything to the right of it are shifted to the right by 1em).
margin-right 1em A horizontal margin of 1em is inserted between the inline element and its neighbours to the right (everything to the right of the inline element is shifted to the right by 1em).
padding 1em The distance between the contents of the inline element and its top, bottom, left-hand and right-hand borders increases by 1em (the inline element effectively becomes 2em wider, and everything to the right of it is shifted to the right by 2em).
padding-top 1em The inline element's top border will be shifted upwards by 1em. The position of the inline element will not change, nor will that of any of its neighbours.
padding-bottom 1em The inline element's bottom border will be shifted downwards by 1em. The position of the inline element will not change, nor will that of any of its neighbours.
padding-left 1em The distance between the inline element and its left-hand border will increase by 1em (the inline element effectively becomes 1em wider, and everything to the right of it is shifted to the right by 1em).
padding-right 1em The distance between the inline element and its right-hand border will increase by 1em (the inline element effectively becomes 1em wider, and everything to the right of it is shifted to the right by 1em).

Note that, unless the inline element has a visible border, changing the value of one of the padding properties has exactly the same effect as applying the same change to the corresponding margin property. Increasing the value of padding-left, for example, would have the same effect as increasing the value of margin-left by the same amount. Note also that any elements, including the inline element itself, that are pushed beyond the right-hand boundary of their container will "wrap" to the next line.

The <span> element is one of the most versatile inline elements currently available because it can be used to group other inline elements together. On its own, it does absolutely nothing at all. When used together with CSS, however, it can be extremely useful. The HTML code below creates a web page that describes the way in which electron shells in an atom are filled. Only inline HTML elements and text have been used within the document's <body> element.

<!doctype html>

<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>Inline Demo</title>
    <style>
      .main {
        font-size: 150%;
        font-family: sans-serif;
      }
      .formula {
        font-size: 200%;
        font-weight: bold;
        font-style: italic;
        font-family: serif;
      }
      .serif { font-family: serif; }
      span.title {
        font-weight: bold;
        font-size: 2em;
      }
      span.first {
        font-weight: bold;
        font-size: 1.5em;
        font-style: italic;
      }
      span.outline { border: solid 1px; }
      span.margin_1em {
        margin: 1em;
        background: #ccccff;
        border: solid 1px;
      }
      span.padding_1em {
        padding: 1em;
        background: rgba(204, 204, 255, 0.5);
        border: solid 1px;
      }
    </style>
  </head>

  <body>
    <span class="main">
      <span class="title">Electron Shells</span><br><br>
      <span class="first">A</span>toms tend to assume the <em>most stable configuration</em> and the <em>lowest energy level</em> possible. For that reason, the electron shells in an atom are (usually) filled in strict order, starting with the lowest energy level.<br><br>
      Each of the electron shells (<span class="serif"><em>n</em>1</span> to <span class="serif"><em>n</em>7</span>, or <strong>K</strong> to <strong>Q</strong>) can hold a <span class="outline">maximum number of electrons</span> determined by the formula:<br><br>
      <span class="formula">electron capacity = 2n <sup>2</sup></span><br><br>
      where <span class="serif"><i>n</i></span> is the electron shell number.<br><br>
      Note, however, that the <mark><u>maximum number of electrons actually seen</u></mark> in an electron shell to date is thirty-two (32).
    </span>
  </body>
</html>

Copy and paste this code into a new file in your HTML editor, save the file as inline-demo.html, and open the file in a web browser. You should see something like the illustration below.


This web page contains only inline HTML elements and text

This web page contains only inline HTML elements and text


Note that line breaks only occur where we have used the break element (<br>) to explicitly create one. Otherwise, text wraps to the next line in the usual way, i.e. at the right-hand page boundary. We'd like to draw your attention now to the following piece of code, which appears in amongst all the other HTML code:

<span class="outline">maximum number of electrons</span>

We have used the <span> element here, together with the class selector class="outline" to put a visible border around the words "maximum number of electrons". We did this simply to demonstrate that, as we stated above, the bounding rectangle of an inline element is determined purely by the size of its contents.

Note that the content of an inline element will include any added padding, but will not include any margins we set for the element (although as we saw from the table above, setting a margin of 1em on a border has the same effect as setting the padding inside that border to 1em in terms of how it affects the position of any neighbouring elements).

We can easily demonstrate the effect of setting a margin on an inline element. Go back into your HTML code and change the code fragment shown above to the following:

<span class="margin_1em">maximum number of electrons</span>

Save the file, and reopen or refresh the page in your browser. You should now see something like this:


Left and right margins of 1em have been added to the text 'maximum number of electons'

Left and right margins of 1em have been added to the text 'maximum number of electons'


As predicted, the left and right margins for the <span> element have been increased (from 0 to 1em), and both the <span> element and the content to the right of it have been repositioned accordingly. Note however that the <span> element's border remains exactly as it was before in relation to the enclosed text.

What would happen if, instead of setting the value of the margin property to 1em, we set the value of the padding property to 1em instead? As before, it is easy enough to demonstrate the effect this will have. Go back into your HTML code and change the code once more, this time to the following:

<span class="padding_1em">maximum number of electrons</span>

Save the file, and reopen or refresh the page in your browser. You should now see something like this:


All four borders have been set at a distance of 1em from the text 'maximum number of electons'

All four borders have been set at a distance of 1em from the text 'maximum number of electons'


As you can see, both the <span> element and the content to the right of it have been repositioned to exactly the same extent as before, when we set the margin property. This time, however, the <span> element's top, bottom, left and right borders have all been moved away from the text by a distance of 1em.

We have deliberately set the background colour for the <span> element to be semi-transparent, so that you can see that it now partially overlays the text above it, but is in turn partially overlaid by the text below it.

The above highlights two things:

  1. Inline elements and their contents are rendered from left to right, and are only displayed on a new line if the current line is not long enough to accommodate them, or if they appear after a break element (<br>) in the HTML code.
  2. Setting values for the top and bottom padding or margin properties of an inline element does not usually serve any useful purpose.

The table below briefly summarises the HTML 5 elements traditionally considered to be inline elements. The elements are organised according to the currently defined W3C element types, and are otherwise listed alphabetically.


HTML Inline Elements
HTML 5 Element Type Elements
Scripting noscript, script
Grouping Content br
Text-Level Semantics a, abbr, b, bdi, bdo, cite, code, dfn, em, i, kbd, mark, meter, progress, q, ruby, s, samp, small, span, strong, sub, sup, time, u, var
Edits del, ins
Embedded Content area, audio, canvas, datalist, embed, iframe, img, map, object, param, video
Forms button, input, label, output, select, textarea

Content categories

Although there are still countless online articles and tutorials that refer to HTML elements as being either "block-level" or "inline", W3C's HTML 5 specification (the latest version of which can be found here) defines a somewhat more sophisticated - and inevitably more complex - content architecture. W3C have thrown two new terms into the mix - content models and content categories.

Every HTML element in the HTML 5 specification has a content model. The content model determines what kind of content the HTML element is expected to contain, which in most cases comes down to which other HTML elements (if any) may be nested within it. Each HTML element will also belong to zero or more content categories. A content category groups together HTML elements that have similar characteristics. The HTML 5 specification defines the following seven content categories:

* The word paragraph in this context refers to "a run of phrasing content that forms a block of text", which essentially means it can refer to a block of text inside any HTML element and not just text inside a paragraph element.

The diagram below shows the relationship between the main HTML content categories. As you can see from the diagram, sectioning content, heading content, phrasing content, embedded content, and interactive content are all types of flow content. Some metadata content (i.e. metadata content that appears in the body of the HTML document rather than the head) is also flow content. Some metadata and interactive content is also phrasing content. All embedded content is also phrasing content, and some embedded content is also interactive content.


A Venn diagram showing the relationships between the main HTML content categories

A Venn diagram showing the relationships between the main HTML content categories


Some HTML elements fall into other content categories that we have not so far mentioned. Form controls, for example, have their own set of fairly specialised categories. Script-supporting elements (like the <script> element) may appear within the body of an HTML document. They are not rendered by the browser, but are used to support scripts that provide functionality to users. There are also a small number of HTML elements have very special and unique requirements, and do not fall into any particular category.

There is another fairly broad content category called palpable content, about which the HTML 5 specification has this to say:

"A content is palpable when it is neither empty nor hidden. Elements whose content model allows any flow content or phrasing content should have at least one node in its contents that is palpable content and that does not have the hidden attribute specified . . . Palpable content makes an element non-empty by providing either some descendant non-empty text. It can also provide something users can hear (<audio> elements), view (<video>, <img>, or <canvas> elements), or otherwise interact with (e.g., interactive form controls)."

The table below lists the HTML elements according to the content category (or categories) to which they belong.


HTML Elements by Content Category
Content Category HTML Elements
Metadata content base, link, meta, noscript, script, style, template, title
Flow content a, abbr, address, area (if a descendant of a map element), article, aside, audio, b, bdi, bdo, blockquote, br, button, canvas, cite, code ,data, datalist, del, details, dfn ,dialog ,div, dl, em, embed, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hr, i, iframe, img, input, ins, kbd, label, link (if allowed in the body), main, map, mark, math, meter, nav, noscript, object, ol, output, p, picture, pre, progress, q, ruby, s, samp, script, section, select, small, span, strong, style, sub, sup, svg, table, template, textarea, time, u, ul, var, video, wbr
Sectioning content article, aside, nav, section
Heading content h1, h2, h3, h4, h5, h6
Phrasing content a, abbr, area (if a descendant of a map element), audio, b, bdi, bdo, br, button, canvas, cite, code, data, datalist, del, dfn, em, embed, i, iframe, img, input, ins, kbd, label, link (if allowed in the body), map, mark, math, meter, noscript, object, output, picture, progress, q, ruby, s, samp, script, select, small, span, strong, sub, sup, svg, template, textarea, time, u , var, video, wbr
Embedded content audio, canvas, embed, iframe, img, math, object, picture, svg, video
Interactive content a (if the href attribute is present), audio (if the controls attribute is present), button, details, embed, iframe, img (if the usemap attribute is present), input (if the value of the type attribute is not set to "hidden"), label, select, textarea, video (if the controls attribute is present)
Palpable content a, abbr, address, article, aside, audio (if controls attribute is present), b, bdi, bdo, blockquote, button, canvas, cite, code, data, details, dfn, div, dl (if element's children include at least one name-value group), em, embed, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, i, iframe, img, input (if value of type attribute not set to "hidden"), ins, kbd, label, main, map, mark, math, meter, nav, object, ol (if element's children include at least one li element), output, p, pre, progress, q, ruby, s, samp, section, select, small, span, strong, sub, sup, svg, table, textarea, time, u, ul (if element's children include at least one li element), var, video

Content models

We said above that every HTML 5 element has a content model that determines what kind of content it is expected to contain. The HTML 5 specification provides detailed information for every HTML element, including the content categories to which it belongs and, of course, its content model. Paragraph 4.4.1. of the HTML 5.3 W3C Working Draft, 18 October 2018 describes the paragraph element thus:

4.4.1. The p element
  Categories:
    Flow content.
    Palpable content.
  Contexts in which this element can be used:
    Where flow content is expected.
  Content model:
    Phrasing content.
        • • •
         • • •
          • • •

As you can see, the content model for the paragraph element is Phrasing content, which tells us that it is allowed to contain text and any HTML elements that belong to the content category Phrasing content. There are of course, as we know, HTML elements that don't contain any content - the break element (<br>), for example. According to the HTML 5 specification, the break element has a content model of "Nothing". Elements that have a content model of "Nothing" (they are sometimes described as being "void elements") have an opening tag but no closing tag, and cannot contain any content.

You will also frequently encounter HTML elements that have a "transparent" content model. This essentially means that the element does not have a specific content model. Instead, it derives its content model from its parent element. Putting this another way, an element whose content model is "transparent" is expected to contain the same kind of content as its parent element.

If transparent elements are nested inside each other, the content model is derived from the first ancestor element that does not have a transparent content model. In other words, if the parent element of a transparent element is also transparent, then look at the content model of the parent element's parent element . . . and so on.

Some final thoughts

Most of the information in this page is based on the HTML 5.3 W3C Working Draft, 18 October 2018. We would offer the comment that some of the definitions offered in that document in respect of content categories and content models are somewhat ambiguous and at times - depending of course on how you choose to interpret them, contradictory. As a case in point, we quote the following note, taken from paragraph 3.2.8.2.5. (phrasing content):

"Most elements that are categorized as phrasing content can only contain elements that are themselves categorized as phrasing content, not any flow content."

This statement appears to state that phrasing content elements may contain other phrasing elements, but not flow content elements. However, since all phrasing content elements are also flow content elements (as are nearly all HTML elements, in fact - see above), this doesn't make much sense.

We have assumed that this statement will be corrected - or at least clarified - at some future date, since this document has "working draft" status, although the exact same statement also appears in paragraph 3.2.4.2.5. of the HTML 5.2 W3C Recommendation, 14 December 2017.

In similar vein, we quote the HTML 5.3 W3C Working Draft, 18 October 2018, paragraph 3.2.8.3. (transparent content models), whose final statement reads as follows:

"When a transparent element has no parent, then the part of its content model that is 'transparent' must instead be treated as accepting any flow content."

We are experiencing some difficulty in seeing how an HTML element used in accordance with the specification generally could ever manage to be parentless, since all HTML elements other than <html>, <head> and <body> must be either children or descendants of either the <head> element or the <body> element, which are themselves children of the <html> element.

The <html> element, being the root element of an HTML document, is the only element that does not have a parent, and according to the specification it does not have a transparent content model (its content model is actually defined as "A <head> element followed by a <body> element."