Share options

Links to related pages

Essays about code. Essays about connection. Essays about context. Critiques of coding practices.

Responsive by default

Until we use CSS to blow it.

Time to read

, 1534 words, 3rd grade

Many developers believe that it is tricky to ensure responsiveness in web design. And that achieving a design that works on any screen resolution or aspect ratio is difficult.

Too many developers are not willing to make that effort. The consequence? Poorly-coded websites everywhere you look.

Unresponsive? Whereʼs a defibrillator when you need one?

Anyone who uses a smart phone to surf the internet encounters such sites daily. Unless like most people you hate the public sphere and spend all your time on Big Tech sites such as F**k or Instagram.

But here is a secret that many web developers have forgotten, if we ever knew it:

HTML is responsive by default.

What that means is this:

More often than not, we use CSS to destroy responsiveness rather than to maintain or enhance it.
Craft Code

Itʼs not intentional, of course. Few realize that thatʼs what weʼre doing even as we do it. And this is because we start construction with the roof instead of the foundation.

First we use CSS to destroy responsiveness. Then we add a few media query hacks to try to get back some semblance of it. HTML is often an afterthought. All we need are <div> and <span> elements, right? Lots of ʼem.

It is like designing a car by building the skin first, then trying to force the engine, drivetrain, etc. to fit. You can do it that way, but it wonʼt be comfortable, safe, or maintainable.

Better to build it from the wheels up for performance and safety, and then to find an attractive body to fit over it. Why not do it right from the outset?

We can make our sites both responsive and attractive by following a simple approach. Donʼt code outside-in. Code inside-out.

Start with the foundation

Begin by creating your component, page, or even the whole site in semantic HTML. No CSS at all. No JavaScript.

Add the <!DOCTYPE>, the <html> (donʼt forget the lang attribute), <head>, and <body> elements. Then add the viewport and charset <meta> elements and a <title> to the <head> element:

Here is your page foundation.
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta
      content="width=device-width, initial-scale=1"
      name="viewport"
    />
    <title>Responsive by default</title>
  </head>
  <body></body>
</html>

This example shows our boilerplate HTML — the HTML with which we start every HTML page. At the top is the document type declaration that letʼs the browser know that this is HTML5 markup.

Then we have our html element with the lang attribute set to en … because our page is in English.

Inside the html element we have the standard head and body elements. The body element is currently empty. This is where our page content goes.

The element contains three children so far. The first is a meta element with the charset attribute set to “utf-8”. Next, a meta element with name “viewport” and content set to “width=device-width, initial-scale=1”.

Finally, the head element contains a title element with the content “Responsive by default”.

Now youʼre ready to be responsive by default.

Build the body next. Start with the landmark elements. At the top level is <main>. Note how all the virtual DOM libraries screw this up by putting a <div> at the top. They donʼt care about correct HTML. But coding by hand we can get it right.

Add the other landmark elements as needed: <header> and <footer> and optionally a <nav> element. Nest these in <main> if you prefer.

Hundreds of articles and tutorials have explained how to nest heading elements. Itʼs easy! Yet more than half of all web sites still get it wrong. Why? Craft Coders get this right.

Moving on, you may want an <article> element with nested <section> elements. And, of course, properly nested <h1> to <h6> elements. How about an <aside>? Is there a <form>? Be sure that your use of each is correct and standards compliant.

How do you know if youʼve done this right? Many HTML tools will allow you to see your page hierarchy. Here is the Craft Code home page. But possibly the quickest way is to use the HTML5 outliner extension. Here is what the HTML5 outline of the Craft Code home page looks like:

A proper page hierarchy with correctly-nested heading elements.
The HTML5 Outliner shows a text outline of the page with properly nested headings.

The best resource for HTML help that weʼve found is Mozilla Developer Network (MDN). Of course, the final arbiter is the HTML standard itself.

Work your way down through your page hierarchy. Use the correct semantic element for the type of content. For example, an <address> element for a street address.

Parse through the text mentally and ask, What is this? And, Is there a way to make clear to the browser the type of this content with a semantic HTML element?

How many of these do you know? How many do you use regularly?

  • <p> for paragraphs, <a> for links, <button> for buttons.
  • <details> and <summary> for text that might not be of interest. We can hide it but keep it available to the user.
  • <ol> with <li> for ordered lists — lists in which the order of elements matters.
  • <ul> with <li> for unordered lists — lists in which the order of elements doesnʼt matter.
  • <dl>, <dt>, and <dd> with <dfn> (if a definition) for description lists or glossaries.
  • <figure> with <figcaption> for figures. They are more common than you might think. Great way to caption images, charts, graphs, etc.
  • <form>, <fieldset>, <legend>, <label>, <input>, <textarea>, <select>, <option>, <optgroup>, <datalist>, and <button> for forms. Do you know what all these do? Why not use them properly?
  • <table>, <caption>, <thead>, <tbody>, <tfoot>, <colgroup>, <col>, <tr>, <th>, <td> for tabular data. And only for tabular data. You will rarely need a table. Avoid when possible.
  • <picture>, <source>, and <img> for your images. Or <img> with srcset. Donʼt forget the alt attribute. Consider wrapping these in <figure>.
  • There are many other worthwhile flow elements, such as:
    • <code> for programming code.
    • <pre> for pre-formatted text.
    • <mark> for highlighted text. (Great with search results.)
    • <ins> and <del> for insertions and deletions.
    • <abbr> for abbreviations. Use the title attribute for the expansion of the abbreviation.
    • <em> and <strong> for emphasis.
    • <q> and <blockquote> for quotations.
    • <cite> for citations. Have you ever used this one? You must have cited someone at some time.
    • <sub> and <sup> for subscript and superscript letters (great for footnotes).
    • <time> for dates and times. Again, ever used it?
    • a few more obscure elements: <kbd> for keyboard input. <samp> for sample output (from a computer program). <var> for mathematical variables.

Why is it that so many of us try to represent the semantics of these data with CSS alone? We can encode the semantics right into the HTML with ease and then add the visuals with CSS by tag name.

But most devs — letʼs be honest — who want to apply a style to a time will add a <span> element and a utility class. The <time> element? Never heard of it.

Or weʼll mark up a quotation by adding quotation marks rather than using the <q> element. Donʼt we know that the <q> element can add the quotation marks for us? And that we can use CSS to choose the quote style?

Setting the quotation mark style for the <q> element.
body {
  quotes: "“" "”" "‘" "’";
}

This code example shows the quotes property set on the body element. The values are themselves enclosed in double quotation marks. The first two are the outer quotation marks and the second two are the inner quotation marks. In the example, the first two are the left and right double curly quotation marks and the second two are the left and right single curly quotation marks.

And how many of us have remembered to cite the source?

It is so easy to do things the right way … if we care enough.
<q cite="https://craft-code.dev/essays/code/responsive-by-default">
  <abbr title="HyperText Markup Language">HTML</abbr>
  is responsive by default.
</q>

The example shows the correct use of the q element. We have set the cite attribute to the URL of the reference. In this case, the quotations is “HTML is responsive by default” and the cite attribute points to this page. We also use the abbr element properly on the HTML abbreviation. Just for fun.

When we ignore the semantic aspects of HTML we squander all the potential benefits. Such as machine-readability, accessibility, sustainability. And, often, responsiveness.

And all for naught because semantic HTML doesnʼt prevent us from doing whatever we want with CSS. It helps us.

Wouldnʼt it be nice if we didnʼt turn around and use CSS to mess everything up?

An example page

What does this look like in practice? Well, here is a simplified example:

Example of responsive-by-default HTML.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta
      name="description"
      content="This here page is responsive by default! Wee hoo!"
    >
    <title>Responsive by default</title>
  </head>
  <body>
    <header role="banner">
      <h2>I be responsive by default</h2>
      <a href="#main">Skip to main content</a>
    </header>
    <nav
      aria-labelledby="main-navigation-label"
      role="navigation"
    >
      <h2 id="main-navigation-label">Main navigation</h1>
      <ul role="presentation">
        <li>
          <a href="/about">About us</a>
        </li>
        <li>
          <a href="/contact-us">Contact us</a>
        </li>
        <li>
          <a href="/terms-of-use">Terms of use</a>
        </li>
      </ul>
    </nav>
    <main id="main-content" role="main">
      <article>
        <header>
          <h1>Here be the main content</h1>
        </header>
        <!-- main content here -->
      </article>
    </main>
    <footer role="contentinfo">
      <p>&copy; 2023 by Really Smart Devs.</p>
    </footer>
  </body>
</html>

This somewhat long example starts with the HTML boilerplate we described above. It adds a meta element with name “description” and content set to “This here page is responsive by default! Wee hoo!” to to the head element.

We are silly. So sue us.

Then, in the body element we add four landmark elements: header, nav, main, and footer. Following recommended practice, we set the role attributes redundantly to “banner”, “navigation”, “main”, and “contentinfo”, respectively.

The header element contains an h2 element and a skip link to the main content.

The nav element contains an h2 element and an unordered list (ul) element with four list items (li), each with an anchor (a) element. This is our page menu.

The main element contains an article element with a header element containing a single h1 element for the title of the article. The main element has the id attribute set to “main-content” to provide the target for the skip link.

The footer element contains only a paragraphg with copyright info for the page.

But how does an actual page look? OK, Iʼve added one here. It is the essay on just-in-time coding, simplified a bit to make the html easier to follow.

Is it ugly as sin? You bet. But is it usable? Iʼd argue yes. More importantly, is it responsive? Well, here it is on my phone. Try it on yours.

Ugly, true. But usable on any screen or screen reader.
Our plain HTML page is easy to read and fully usable by smart phone.

We can also take a look at the page using the Lynx text-only browser. No CSS. No JS. No images. Nothing but text. So does it work? Take a look:

Works on Lynx.
The responsive HTML-only page is perfectly usable on the Lynx text-only browser.

Performance

So. How does this score in Lighthouse?

Hmm. Not too bad. We can fix the SEO with CSS.
Lighthouse says 100% on performance, accessibility, and best practices, but 88% on SEO. Urk.

So thatʼs looking pretty g… whoa! What the heck is up with that 88?

Well, partly it is because we have added the <meta content="noindex" name="robots"> element to the <head>. This prevents search engines from indexing the page. We donʼt want users landing on this example page thinking that it is an actual site page! But if we remove that, we still achieve only a 95%. What gives?

This is actually a problem with the browser. Chromeʼs default stylesheet does not enforce a minimum “tap size” for links and buttons. The links in the unordered lists are too closely spaced (by browser default). Chrome oughta give more room for fat fingers. Like mine.

But users can zoom, we will fix it with CSS, and it is hard to imagine a phone user without CSS. So weʼll leave it. (We could wrap the links in <p> elements to get that space, but thatʼs a hack, so weʼll avoid it.)

There we have it. Responsiveness is not something we add to our web pages. It is something we destroy — if weʼre not careful and thoughtful as we code. Keep it responsive.

Next: progressive enhancement.

Links to related pages

Essays about code. Essays about connection. Essays about context. Critiques of coding practices.

Get notified form

Get notified of site updates
Button bar

Carbon emissions for this page

Cleaner than 97% of pages tested
0.068g on first visit; then on return visits 0.010g
QR Code

Scan this code to open this page on another device.