High performance HTML

Sam Dutton
Sam Dutton
Published in
10 min readJul 21, 2015

--

How can you improve the performance of web pages?

Most developers look to JavaScript and image optimisation, server configuration, file minification and concatenation — even CSS tweaks.

Poor old HTML gets neglected, despite being the core language of the web.

HTML payloads are big and getting bigger. Pages on most top-100 sites require around 40k of HTML per page. Sites such as Amazon and Yahoo use thousands of lines of HTML per page. The youtube.com home page currently clocks in at a whopping 3.5K HTML elements.

Reducing HTML complexity and the number of elements in a page won’t improve parse time much — but well crafted HTML is a crucial foundation for building fast-loading pages and layouts that respond successfully to different viewport sizes.

In this article you’ll find out how to write clean, concise HTML that enables you to create content that loads fast and works well across a variety of devices. In the process, you’ll learn how to build sites and apps that are easier to debug and maintain.

There is always more than one way to write code — especially HTML. Rather than begin every sentence in this article with ‘In general …’ we’ve gone ahead and prescribed what in our experience usually works best. That doesn’t mean that every suggestion is right every time.

tl;dr

HTML, CSS and JavaScript

HTML is a markup language for adding structure and meaning to content.

HTML should not be used to style content. Don’t put text in heading tags to ‘make it bigger’ or use blockquotes just for indentation. Instead, use CSS to change the appearance and layout of elements.

The default appearance of HTML elements is defined by a browser’s default stylesheet: Chrome, Firefox, Internet Explorer and Opera each have their own. For example, in Chrome the h1 element by default is rendered as 32px bold Times.

Three general principles:

  • Use HTML for structure, CSS for presentation and JavaScript for behaviour. CSS Zen Garden (12 years old this year!) shows this separation of concerns in action.
  • Use HTML, then turn to CSS if and when required — and, if really necessary, move on to JavaScript. For example: in many cases it’s possible to use HTML for form validation and CSS or SVG for animation — without resorting to JavaScript.
  • Put CSS and JavaScript in files separate from your HTML. This enables caching and makes code easier to debug. In production, CSS and JavaScript can then be minified, concatenated and inlined as part of your build process.

Document structure

Use the HTML5 document type. Here’s a barebones document:

<!DOCTYPE html>
<html>

<head> <title>Recipes: pesto</title>
</head>

<body> <h1>Pesto</h1> <p>Pesto is good!</p>
</body>

</html>

  • Link to CSS files at the top of the page, in the head element like this:

<head> <title>My pesto recipe</title> <link rel=”/css/global.css”> <link rel=”css/local.css”>
</head>

That way, browsers have CSS information ready before parsing HTML.

  • Put JavaScript at the bottom of the page, before the closing body tag. This speeds up page load — since the browser can render the page before parsing JavaScript — and has the helpful side effect of enabling JavaScript to refer to page elements:

<body>
… <script src=”/js/global.js”></script> <script src=”js/local.js”></script>
</body>

  • Alternatively, use the defer and async attributes — but be aware of their behaviour: script elements with an async attribute aren’t guaranteed to be executed in order. Also consider support: async is only implemented in Internet Explorer 10 and above; defer is only partially supported prior to Internet Explorer 10.
  • Add handlers in JavaScript code. DON’T add them inline in HTML. For example, this is error prone and hard to maintain:

<head>
… <script src=”js/local.js”></script>
</head>
<body onload=”init()”>
… <button onclick=”handleFoo()”>Foo</button>

</body>

This is much better:

index.html

<head>

</head>
<body>
… <button id=”foo”>Foo</button>
… <script src=”js/local.js”></script>
</body>

js/local.js:

init();
var fooButton = document.querySelector(‘button#foo’);
fooButton.onclick = handleFoo();

Validation

A major reason for the success of the web is that browsers handle invalid HTML. There are even standardised rules for how browsers should render invalid code.

However, this is NOT a reason to be laissez-faire. Valid HTML is easier to debug and often smaller in file size, faster and less resource-hungry to parse and render. Invalid HTML can make successful responsive design difficult to implement.

Writing valid HTML is particular important when working with templates: what seems to work OK in an isolated chunk of code may go horribly wrong in combination with other content.

  • Incorporate validation in your workflow: use validation plugins such as HTMLHint and SublimeLinter with your editor and incorporate validation in your build process using tools such as HTMLHint with Grunt. You can check code online with tools such as the W3C HTML validator, and share configuration files with project contributors.
  • Use the HTML5 document type.
  • Make sure to maintain HTML hierarchy: nest elements correctly, and make sure no elements are left unclosed. It can be helpful for debugging to add a comment to the closing tag of an element that holds a large amount of complex content — especially when using templating:

<div id=”foobar”>

</div> <! -- foobar ends

  • Make sure to add closing tags to all elements that aren’t self-closing.

For example, this will work:

<p>Pesto is good to eat…
<p>…and pesto is easy to make.

But this is less likely to go wrong, since the end of each paragraph is made explicit:

<p>Pesto is good to eat…</p>
<p>…and pesto is easy to make.</p>

  • Closing tags are not required for list items and some very clever developers believe you should leave them out. Whatever you do, make sure to close every list element:

<ul> <li>Basil <li>Pine nuts <li>Garlic
</ul>

  • One place you absolutely must include closing tags is with the video and audio elements. These are not ‘self closing’:

<! — wrong: liable to cause layout grief →
<video src=”foo.webm” />

<! — better →
<video src=”foo.webm”> <p>Video element not supported.</p>
</video>

Conversely, cut clutter by removing unnecessary code:

  • There is no need to add a slash to ‘self closing’ (void) elements such as <img> and <link>. (You can enjoy a comprehensive list of self-closing elements here.)
  • Boolean attributes do not have a value: if the attribute is there, it’s true. In the following example, the video element will not autoplay and will not have controls (since this is the default):
<video src="foo.webm">
  • The following example doesn’t work as expected, because the presence of an attribute forces a true value:
<video src="foo.webm" autoplay="false" controls="false">
  • This works:
<video src="foo.webm" autoplay="true" controls="true">
  • This is more readable:
<video src="foo.webm" autoplay controls>
  • Stylesheets and scripts don’t need a type attribute: CSS and JavaScript are the defaults.
  • Omit the protocol when linking to external content: this prevents problems with mixed content. For example:
<a href="//en.wikipedia.org/wiki/Tag_soup">Tag soup</a>

Code formatting

Consistent formatting makes HTML code easier to understand, optimise and debug.

  • Maintain an HTML style guide for project contributors (or use an existing one like Google’s).
  • Use your editor to automate code beautification. For example, in Sublime Text add a shortcut for Reindent. You can check layout with code linters such as SublimeLinter or online tools such as CSS Beautify and JS Beautifier.
  • Don’t go mad with hierarchical HTML indentation! This can easily get out of hand, so set rational defaults for when to begin an element at the left margin. Conversely, deep hierarchies may mean you need to refactor.
  • Standardise on indentation and use either spaces or tabs, not both.
  • Improve readability with sensible nesting. For example, it’s clear that this is a heading:
<h2><a href="/contact">Contact</a><h2>

…whereas at first glance this just looks like a link:

<a href="/contact"><h2>Contact</h1></a>
  • Order elements in ways that won’t be a surprise to other developers — or you in six months. For example, a footer element should go at the bottom of your .html page, even though (in theory) it could be put anywhere.
  • Standardise on single or double quotes.
  • Use lowercase code for tag and attribute names. UPPERCASE IS TIRESOME:
<A HREF="/">Home</A>
  • Mixed case is EVEN worse:
<H2>Pesto</h2>

Semantic markup

Semantic means ‘relating to meaning’.

HTML markup adds meaning to content: element and attribute names describe the role of content.

HTML5 introduced a number of new ‘semantic elements’ such as <header>, <footer> and <nav>.

Using the right element for the right content is good for accessibility and helps ensure your code is understandable:

  • Use <h1> (<h2>, <h3>…) for headings, <ul> or <ol> for lists.
  • Note that <article> headings should begin with an <h1> (reasoning here).
  • Where appropriate, use the HTML5 semantic elements such as <header>, <footer>, <nav> and <aside>.
  • Use <p> for body text, HTML5 semantic elements (or <div> as a fallback) to structure content — not vice versa.
  • Use <em> and <strong> rather than <i> and <b>: <em> and <strong> add meaning, not styling hints.
  • With forms use the <label> element, input types, placeholder text, and the required attribute to enforce validation. (Pete LePage’s articles on Web Fundamental show how.)
  • Mixing text and elements, as children of another element, tends to lead to layout bugs. For example, this:
<div>Name: <input type="text" id="name"></div>

is better expressed as this:

<div>
<label for="name">Name:</label>
<input type="text" id="name">
</div>

This has a bonus side effect: the for attribute means that clicking on the label automatically throws focus onto the input element. This is particularly useful for checkboxes and radio buttons.

Layout

To reiterate: HTML should be used to add meaning and structure to content, not for styling.

  • Use <p> elements for text, not for layout. By default, <p> has margins and other styles applied by the built-in browser stylesheet.
  • Avoid using <br> for line breaks: use block elements or the CSS display property instead. The <br> should only ever be seen within text — and even then, only very rarely (for example, as a form of punctuation within poetry).
  • Avoid using the humble <hr> to add horizontal lines: CSS border-bottom is a better option. It may make sense to use <hr> to denote a thematic break.
  • Don’t use divs unnecessarily: the W3C HTML spec describes the div as ‘an element of last resort, for when no other element is suitable’ (sixrevisions.com). Style inline elements such as links and img elements with display: block, rather than putting them in divs or (worse) using <br>.
  • Learn which elements are block level, to avoid unnecessarily putting block level elements inside divs. For example, there is no need to put a list inside a div element.
  • Do not use tables for layout. Do use tables for tabular data.
  • Flex box is now widely implemented: use it.
  • Use CSS padding for padding and margin for margins: understand the box model.
  • Standardise on margins: it’s often best to add margins to the bottom and the right of elements, rather than the top or left. Whatever you do, avoid mixing top and bottom or left and right. Use the last-of-type selector to avoid redundant margins.

HTML emails

Coding for email is nothing like coding for the modern web.

We won’t go into the gruesome details here — suffice to say that best practice for HTML email coding resembles web development from the late 1990s: tables, shim GIFs, inconsistent and minimal CSS, patchy image and media support, little or no support for JavaScript, and lots of minor hacks. (For an unpleasant taster, take a look at MailChimp’s most basic template.)

More information here, here and here.

CSS

This article is about HTML, but here are some basic CSS tips:

  • Avoid inline CSS. For performance optimisation, CSS files can be inlined as part of your build process.
  • Use an ID once and once only: there should only be a single element with id=”foo”, id=”bar”, or any other ID.
  • Use classes when you want to refer to multiple elements — and take a look at BEM syntax. Where possible, use class attributes on a parent rather than children. For example:

<! — verbose :( →

<ul> <li class=”ingredient”>Basil</li> <li class=”ingredient”>Pine nuts</li> <li class=”ingredient”>Garlic</li>
</ul>

<! — better :) →
<ul class=”ingredients”> <li>Basil</li> <li>Pine nuts</li> <li>Garlic</li>
</ul>

Accessibility

Consider the range of devices, contexts and input methods that will be used to interact with your HTML:

  • Use semantic elements.
  • Provide fallbacks: add captions and subtitles with the track element, include fallback text and/or images in video and audio elements; use poster images for video; add alt attributes to every image (give the alt attribute an empty value if the image is only for decoration).
  • Add title attributes to links — but only if the title adds meaning and doesn’t just repeat the link text.
  • Use type and placeholder elements in input elements.
  • Use ARIA attributes.

Random bonus extra suggestions

  • Make sure to encode characters with special meaning in HTML, such as < and &. For example: <title>HTML &amp; JavaScript</title>.
  • Conversely, do not unnecessarily encode characters such as en dashes (for example, 4–5 weeks) or currency symbols such as ¢ and €.
  • Add comments if and only if it’s not obvious what’s happening in code. (And bear in mind that code commenting often shows a need for refactoring — good HTML, even when it’s complex, is generally self-explanatory.)
  • Where it makes sense — with all-capitalised headings, for example — apply text case via the CSS text-transform and font-variant properties, not by entering uppercase text. You may change your mind later! Also, if users copy text, they probably want upper and lower case. The following <h4> is displayed in small caps, but when copied will be upper and lower case.HTML:
<h4>W3C Web Accessibility Initiative ARIA guidance</h4>

CSS:

h4 {
font-variant: small-caps;
}

And finally…

Whatever you do, test!

Build HTML testing into your workflow, toolchain and deployment processes.

Test page load on a variety of devices, on large and small screens, in a variety of connectivity contexts. Try interacting with your page with a text-only browser such as Lynx, or with a screenreader such as ChromeVox. Use emulators such as Chrome Dev Tools device mode to monitor changes. Page Speed, Web Page Test and other tools can be integrated with your workflow to automate testing before or after deployment.

For more information about how to write high performance HTML, follow the links in HTML, CSS and JavaScript resources and check out the guidance on Web Fundamentals.

Originally published at samdutton.wordpress.com on April 2, 2015.

--

--

Sam Dutton
Sam Dutton

I am a Developer Advocate for Google Chrome. I grew up South Australia, went to university in Sydney, and have lived since 1986 in London.