Reponsive by default
Tags: webdev, a11y, responsive, semantichtml
Published: 2023-11-14 03:01:01

Until we use CSS to wreck it, that is.

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 many 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.

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 <code>&lt;div&gt;</code> and <code>&lt;span&gt;</code> 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 <code>&lt;!DOCTYPE&gt;</code> and the <code>&lt;html&gt;</code> (donʼt forget the <code>lang</code> attribute), <code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code> elements. Then add the <code>viewport</code> and <code>charset</code> <code>&lt;meta&gt;</code> elements and a <code>&lt;title&gt;</code> to the <code>&lt;head&gt;</code> element.

Here, then, is your page foundation:

```html
<!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>
    <!-- content goes here -->
  </body>
</html>
```

Now youʼre ready to be **responsive by default**.

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

Add the other landmark elements as needed: <code>&lt;header&gt;</code> and <code>&lt;footer&gt;</code> and optionally a <code>&lt;nav&gt;</code> element. Nest these in <code>&lt;main&gt;</code> 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 <code>&lt;section&gt;</code> elements. And, of course, **properly nested** <code>&lt;h1&gt;</code> to <code>&lt;h6&gt;</code> elements. How about an <code>&lt;aside&gt;</code>? Is there a <code>&lt;form&gt;</code>? Be sure that your use of each is correct and [standards compliant](https://validator.w3.org/).

How do you know if youʼve done this right? Many [HTML tools](https://www.wmtips.com/tools/html-analyzer/) will allow you to see your page hierarchy. Here is the [Craft Code home page](https://www.wmtips.com/tools/html-analyzer/#https://craft-code.dev/). But possibly the quickest way is to use the [HTML5 outliner extension](https://chrome.google.com/webstore/detail/html5-outliner/afoibpobokebhgfnknfndkgemglggomo). Here is what the HTML5 outline of the Craft Code home page looks like:

![The HTML5 Outliner shows a text outline of the page with properly nested headings.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nk1xq31ud7g16qucufec.png)

You can see that it is a proper page hierarchy with correctly-nested heading elements.

The best resource for HTML help that weʼve found is [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) (MDN). Of course, the final arbiter is the [HTML standard itself](https://html.spec.whatwg.org/multipage/).

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

Parse through the text mentally and ask, What is this? 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?

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

Or weʼll mark up a **quotation** by adding quotation marks rather than using the <code>&lt;q&gt;</code> element. Donʼt we know that the <code>&lt;q&gt;</code> element can add the quotation marks for us? And that we can use CSS to choose the [quote style](https://developer.mozilla.org/en-US/docs/Web/CSS/quotes)?

```css
body {
  quotes: "“" "”" "‘" "’";
}
```

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

```html
<q
  cite="https://craft-code.dev/essays/code/responsive-by-default"
>
  <abbr title="HyperText Markup Language">HTML</abbr>
  is responsive by default.
</q>
```

But how does an actual page look? Iʼve created a [responsive-by-default example](https://craft-code.dev/essays/code/responsive-by-default/example) to illustrate.

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.

![Our plain HTML page is easy to read and fully usable by smart phone.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6808frlp37tloeqipees.png)

Ugly, true. But usable on any screen or screen reader.

We can also take a look at the page using the [Lynx text-only browser](https://craft-code.dev/essays/code/responsive-by-default). No CSS. No JS. No images. Nothing but text. So does it work? Take a look:


![The responsive HTML-only page is perfectly usable on the Lynx text-only browser.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trn3lub61alm4j6g9qn4.png)

## What about performance?

So. How does this score in [Lighthouse](https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk)?


![Lighthouse says 100% on performance, accessibility, and best practices, but 88% on SEO. Urk.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ta9lsu4t3wv9gxk2x5sr.png)

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

Well, partly it is because we have added the <code>&lt;meta content="noindex" name="robots"&gt;</code> element to the <code>&lt;head&gt;</code>. 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 <code>&lt;p&gt;</code> elements to get that space, but thatʼs a hack, so weʼll avoid it.)

There we have it. **Responiveness is not something we add to our web pages.** It is something we _destroy_&mdash;if weʼre not careful and thoughtful as we code. Keep it responsive.