HTML syntax
- Lowercase tags and attributes
- Double quotes for attributes values
- No trailing slashes for self-closing tags
- Don’t omit optional closing tags (e.g.
</li>
or</body>
).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page title</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Hello, world!</h1>
<script src="hello.js"></script>
</body>
</html>
Indentation
Use soft tabs with four (4) spaces.
As a rule, nested elements should be indented once. (It’s okay to be flexible here. Perfectly indenting HTML code can result in excessive and unmanageable indentation.)
When working with templates:
- Readability of your source code matters much more than perfect indentation in the HTML output.
- In each template file, start from the leftmost side.
{# parent-template.html #}
<div class="x">
<div class="y">
<div class="z">
{% block content %}{% endblock %}
</div>
</div>
</div>
{# child-template.html #}
{% extends 'parent-template.html' %}
{% block content %}
<h1>{{ title }}</h1>
<div class="text">
{{ main_text }}
</div>
{% endblock %}
HTML5 doctype
Enforce standards mode and more consistent rendering in every browser possible with this simple doctype at the beginning of every HTML page.
<!DOCTYPE html>
<html>
<!-- … -->
</html>
Language attribute
From the HTML5 spec:
Authors are encouraged to specify a lang attribute on the root html element, giving the document’s language. This aids speech synthesis tools to determine what pronunciations to use, translation tools to determine what rules to use, and so forth.
Read more about the lang
attribute in the spec.
Use 2-letter ISO 639-1 language codes. Only use regional extensions (e.g. fr-FR
, en-GB
, en-US
) if there is a strong reason to do so.
<html lang="fr">
<!-- … -->
</html>
Character encoding
Always use UTF-8. Declare it first thing in the <head>
, using the HTML5 short syntax. Ideally, the server should also declare the charset in the Content-Type: text/html; charset=utf-8
HTTP header.
Use literal characters if you can. The only characters that require the use of character entities are <
and &
. Do not encode text such as “français” (bad: français
or français
).
<head>
<meta charset="UTF-8">
<!-- Everything else goes *after* the charset -->
</head>
IE compatibility mode
Internet Explorer 9 to 11 support the use of HTTP header, and the corresponding <meta>
tag, to specify what version of IE the page should be rendered as. Use the meta tag to tell IE to use its latest rendering engine (edge mode). Otherwise in some specific situations, IE 9-11 may fall back to Quirks or “Like IE7” or other compatibility modes.
Important:
- Keep this tag close to the start of the
<head>
. - There must be zero HTML comments in the HTML source before the meta, or it will be ignored.
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
</head>
Viewport meta
For responsive websites, use a viewport
meta in the page’s head
.
- Use
width=device-width
- Add
initial-scale=1
so that Safari does not zoom the content in portrait mode - Do not use
maximum-scale
, ever!
More info: detailed compatibility information.
This meta an be placed anywhere in the head, but we recommend putting it near the top with other “compatibility” stuff. So make sure your <head>
always has, in this order: charset, X-UA-Compatible, viewport; then everything else.
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>…</title>
<!-- Everything else -->
…
</head>
/* Windows Phone needs this in the CSS, or it understands "device-width" as "320px like the original iPhone" */
@-ms-viewport {
width: device-width;
}
Styles and scripts
Reference your stylesheets (ideally just one or two) in the <head>
, using a <link>
tag. If you must write some styles in the page itself, use a <style>
element.
Call your scripts (ideally just one or two) with <script src="…"></script>
tags at the bottom of the page (just before </body>
).
Don’t use type
attributes. The text/css
and text/javascript
values the default ones, so they’re optional.
Danger! Performance killers
- Calling a bazillion scripts and stylesheets! 😭
- Scripts in the
<head>
(except with the async attribute) - Calling a stylesheet with
<style>@import url</style>
<head>
…
<link rel="stylesheet" href="styles.min.css">
<!-- DON'T DO THIS! (Blocks page rendering.)
<script src="some-script.js"></script>
-->
<!-- That’s better, but ignored by IE9, and it
doesn’t guarantee execution order if you
have more than one async script.
<script async src="some-script.js"></script>
-->
</head>
<body>
…
<!-- DO THIS INSTEAD \o/ -->
<script src="libs-and-scripts.min.js"></script>
</body>
Attribute order
HTML attributes should come in this particular order for easier reading of code.
class
id
,name
data-*
src
,for
,type
,href
,value
title
,alt
aria-*
,role
Classes make for great reusable components, so they come first. Ids are more specific and should be used sparingly (e.g., for in-page bookmarks), so they come second.
<a class="ModalLink" data-modal-type="info" href="/help/item/276b6de1">
More information
</a>
<input class="form-control" id="some-thing" name="something" type="text">
<!--
Reminder: alt attribute is mandatory,
should be empty for purely decorative images
-->
<img src="icon-contact.svg" alt="Contact us">
Boolean attributes
A boolean attribute is one that needs no declared value. XHTML required you to declare a value, but HTML5 has no such requirement.
For further reading, consult the HTML5 section on boolean attributes:
The presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value.
If you must include the attribute’s value, and you don’t need to, follow this guideline:
If the attribute is present, its value must either be the empty string or … the attribute’s canonical name, with no leading or trailing whitespace.
In short, don’t add a value.
<input type="text" disabled>
<input type="checkbox" value="1" checked>
<select>
<option value="1" selected>1</option>
</select>
Reducing markup
Whenever possible, avoid superfluous parent elements when writing HTML. Add wrapper elements when you actually need them, not “just in case”. Many times this requires iteration and refactoring, but produces less HTML.
<!-- Not so great -->
<span class="avatar">
<img src="…" alt="">
</span>
<!-- Better -->
<img class="avatar" src="…" alt="">
Avoid inline style and scripts
Styling
- Don’t use the
style
attribute, or other presentation attributes. - Avoid setting the
style
attribute with JavaScript or jQuery’s$(element).css()
method. Add or remove classes instead. - Only use
<style>/* Some CSS */</style>
if you can’t put those styles in (one of the) external stylesheet(s).
Scripting
- Do not use
document.write()
, ever. - Avoid using inline event handlers, such as the
onclick
oronload
attribute. - Only use
<script>/* Some JS */</script>
for code that is short enough and must be executed as soon as possible. If it doesn’t hurt perceived performance, put this code in (one of the) external script(s).
<!-- ALL OF THIS IS AWFUL :(( -->
<body onload="start()">
<p id="hello" style="margin-top:50px">Hello World</p>
<script>
document.write('<p>Some HTML code</p>');
function start() {
var hello = document.querySelector('#hello');
hello.style.marginTop = '100px';
}
</script>
</body>
JavaScript generated markup
Writing markup in a JavaScript file makes the content harder to find, harder to edit, and less performant. Avoid it whenever possible.
IE conditional comments
Avoid using Internet Explorer conditional comments as much as possible. They’re often unnecessary in IE9+, and deprecated in IE11+.
If you need special tricks for IE8 support, see the following example. Note that the recommended option relies on JavaScript for adding an old-ie
class. This means dropping support for IE8-without-JavaScript (which is already the case if we’re using HTML5 elements such as <article>
, <header>
, etc.).
Use this with caution (for IE8):
<head>
…
<!--[if lte IE 8]>
<script>document.documentElement.className+=' old-ie';</script>
<script src="html5shiv.min.js"></script>
<link rel="stylesheet" href="styles-old-ie.css">
<![endif]-->
<!--[if gt IE 8]><!-->
<link rel="stylesheet" href="styles.css">
<!--<![endif]-->
</head>
And avoid this trick:
<!--[if IE 7]><html class="lt-ie9 lt-ie8"><![endif]-->
<!--[if IE 8]><html class="lt-ie9"><![endif]-->
<!--[if gt IE 8]><!--><html><!--<![endif]-->