For writing maintainable and scalable HTML documents
- General
- Start with DOCTYPE
- Don’t use legacy or obsolete DOCTYPE
- Don’t use XML Declaration
- Don’t use character references as much as possible
- Escape
&
,<
,>
,"
, and'
with named character references - Use numeric character references for control or invisible characters
- Put white spaces around comment contents
- Don’t omit closing tag
- Don’t mix empty element format
- Don’t put white spaces around tags and attribute values
- Don’t mix character cases
- Don’t mix quotation marks
- Don’t separate attributes with two or more white spaces
- Omit boolean attribute value
- Omit namespaces
- Don’t use XML attributes
- Don’t mix
data-*
, Microdata, and RDFa Lite attributes with common attributes - Prefer strong native semantics
- The root element
- Document metadata
- Add
title
element - Don’t use
base
element - Specify MIME type of minor linked resources
- Don’t link to
favicon.ico
- Add
title
attribute to alternate stylesheets - Specify document character encoding
- Don’t use legacy character encoding format
- Specify character encoding at first
- Use UTF-8
- Omit
type
attribute for CSS - Don’t comment out contents of
style
element - Don’t mix tag for CSS and JavaScript
- Add
- Sections
- Grouping content
- Don’t start with newline in
pre
element - Use appropriate element in
blockquote
element - Don’t include attribution directly in
blockquote
element - Write one list item per line
- Use
type
attribute forol
element - Don’t use
dl
for dialogue - Place
figcaption
element as first or last child offigure
element - Use
main
element - Avoid
div
element as much as possible
- Don’t start with newline in
- Text-level semantics
- Don’t split same link that can be grouped
- Use
download
attribute for downloading a resource - Use
rel
,hreflang
, andtype
attribute if needed - Clear link text
- Don’t use
em
element for warning or caution - Avoid
s
,i
,b
, andu
element as much as possible - Don’t put quotes to
q
element - Add
title
attribute toabbr
element - Markup
ruby
element verbosely - Add
datetime
attribute to non-machine-readabletime
element - Specify code language with
class
attribute prefixed withlanguage-
- Keep
kbd
element as simple as possible - Avoid
span
element as much as possible - Break after
br
element - Don’t use
br
element only for presentational purpose
- Edits
- Embedded content
- Tabular data
- Forms
- Wrap form control with
label
element - Omit
for
attribute if possible - Use appropriate
type
attribute forinput
element - Add
value
attribute toinput type="submit"
- Add
title
attribute toinput
element when there ispattern
attribute - Don’t use
placeholder
attribute for labeling - Write one
option
element per line - Add
max
attribute toprogress
element - Add
min
andmax
attribute tometer
element - Place
legend
element as the first child offieldset
element
- Wrap form control with
- Scripting
- Other
- Contributors
- License
DOCTYPE is required for activating standard mode.
Bad:
<html>
...
</html>
Good:
<!DOCTYPE html>
<html>
...
</html>
DOCTYPE is not for DTD anymore, be simple.
Bad:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
Good:
<!DOCTYPE html>
Are you sure you want to write XHTML?
Bad:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE html>
Good:
<!DOCTYPE html>
If you write an HTML document with UTF-8, almost all charaters (including Emoji) can be write directly.
Bad:
<p><small>Copyright © 2014 W3C<sup>®</sup></small></p>
Good:
<p><small>Copyright © 2014 W3C<sup>®</sup></small></p>
These characters should escape always for a bug-free HTML document.
Bad:
<h1>The "&" character</h1>
Good:
<h1>The "&" character</h1>
These characters are easily mistaken for another character. And also spec does not guarantee to define a human readable name for these characters.
Bad:
<p>This book can read in 1 hour.</p>
Good:
<p>This book can read in 1 hour.</p>
Some character cannot be used immediately after comment open tag or before comment close tag.
Bad:
<!--This section is non-normative-->
Good:
<!-- This section is non-normative -->
I think you don’t understand a rule for omitting closing tag.
Bad:
<html>
<body>
...
Good:
<html>
<body>
...
</body>
</html>
Consistency is a key for readability.
Bad:
<img alt="HTML Best Practices" src="/img/logo.png">
<hr />
Good:
<img alt="HTML Best Practices" src="/img/logo.png">
<hr>
There is no reason for doing this.
Bad:
<h1 class=" title " >HTML Best Practices</h1>
Good:
<h1 class="title">HTML Best Practices</h1>
It gives a consistency also.
Bad:
<a HREF="#general">General</A>
Good:
<a href="#general">General</a>
Same as above.
Bad:
<img alt="HTML Best Practices" src='/img/logo.jpg'>
Good:
<img alt="HTML Best Practices" src="/img/logo.jpg">
Your weird formatting rule confuses someone.
Bad:
<input name="q" type="search">
Good:
<input name="q" type="search">
It’s easy to write, isn’t it?
Bad:
<audio autoplay="autoplay" src="/audio/theme.mp3">
Good:
<audio autoplay src="/audio/theme.mp3">
SVG and MathML can be used directly in an HTML5 document.
Bad:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
...
</svg>
Good:
<svg version="1.1">
...
</svg>
We write an HTML document.
Bad:
<span lang="ja" xml:lang="ja">...</span>
Good:
<span lang="ja">...</span>
A tag string can be very complicated. This simple rule helps reading such tag string.
Bad:
<img alt="HTML Best Practices" data-height="31" data-width="88" itemprop="image" src="/img/logo.png">
Good:
<img alt="HTML Best Practices" src="/img/logo.png" data-width="88" data-height="31" itemprop="image">
Some element has a implicit ARIA role in an HTML document, don’t specify (or change).
Bad:
<nav role="navigation">
...
</nav>
<hr role="separator">
Good:
<nav>
...
</nav>
<hr>
lang
attribute will help translating an HTML document.
Bad:
<html>
Good:
<html lang="en-US">
Japanese is only used in Japan. So country code is not necessary.
Bad
<html lang="ja-JP">
Good:
<html lang="ja">
A value for title
element is used by various application not only a browser.
Bad:
<head>
<meta charset="UTF-8">
</head>
Good:
<head>
<meta charset="UTF-8">
<title>HTML Best Practices</title>
</head>
An absolute path or URL is safer for both developers and users.
Bad:
<head>
...
<base href="/blog/">
<link href="hello-world" rel="canonical">
...
</head>
Good:
<head>
...
<link href="/blog/hello-world" rel="canonical">
...
</head>
This is a hint how application handles this resource.
Bad:
<link href="/pdf" rel="alternate">
<link href="/feed" rel="alternate">
<link href="/css/screen.css" rel="stylesheet">
Good:
<link href="/pdf" rel="alternate" type="application/pdf">
<link href="/feed" rel="alternate" type="application/rss+xml">
<link href="/css/screen.css" rel="stylesheet">
Almost all browsers fetch /favicon.ico
automatically and asynchronously.
Bad:
<link href="/favicon.ico" rel="icon" type="image/vnd.microsoft.icon">
Good:
<!-- Place `favicon.ico` in the root directory. -->
A human readable label helps people selecting proper stylesheet.
Bad:
<link href="/css/screen.css" rel="stylesheet">
<link href="/css/high-contrast.css" rel="alternate stylesheet">
Good:
<link href="/css/screen.css" rel="stylesheet">
<link href="/css/high-contrast.css" rel="alternate stylesheet" title="High contrast">
UTF-8 is not default in all browsers yet.
Bad:
<head>
<title>HTML Best Practices</title>
</head>
Good:
<head>
<meta charset="UTF-8">
<title>HTML Best Practices</title>
</head>
HTTP headers should be specified by a server, be simple.
Bad:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
Good:
<meta charset="UTF-8">
Spec requires the character encoding is specified within the first 1024 bytes of the document.
Bad:
<head>
<meta content="width=device-width" name="viewport">
<meta charset="UTF-8">
...
</head>
Good:
<head>
<meta charset="UTF-8">
<meta content="width=device-width" name="viewport">
...
</head>
With UTF-8, you can free to use Emoji.
Bad:
<meta charset="Shift_JIS">
Good:
<meta charset="UTF-8">
In HTML5, default type
attribute’s value of style
element is text/css
.
Bad:
<style type="text/css">
...
</style>
Good:
<style>
...
</style>
This ritual is for the old browser.
Bad:
<style>
<!--
...
-->
</style>
Good:
<style>
...
</style>
Sometimes script
element blocks DOM construction.
Bad:
<script src="/js/jquery.min.js"></script>
<link href="/css/screen.css" rel="stylesheet">
<script src="/js/main.js"></script>
Good:
<link href="/css/screen.css" rel="stylesheet">
<script src="/js/jquery.min.js"></script>
<script src="/js/main.js"></script>
Also good:
<script src="/js/jquery.min.js"></script>
<script src="/js/main.js"></script>
<link href="/css/screen.css" rel="stylesheet">
Sometimes body
element is complemented in unexpected position by a browser.
Bad:
<html>
<head>
...
</head>
...
</html>
Good:
<html>
<head>
...
</head>
<body>
...
</body>
</html>
W3C spec removes this element.
Bad:
<hgroup>
<h1>HTML Best Practices</h1>
<h2>For writing maintainable and scalable HTML documents.</h2>
</hgroup>
Good:
<h1>HTML Best Practices</h1>
<p>For writing maintainable and scalable HTML documents.</p>
address
element is for email address, social network account, street address,
telephone number, or something you can get in touch with.
Bad:
<address>No rights reserved.</address>
Good:
<address>Contact: <a href="https://twitter.com/hail2u_">Kyo Nagashima</a></address>
A first newline will ignored in the browsers, but second and later are rendered.
Bad:
<pre>
<!DOCTYPE html>
</pre>
Good:
<pre><!DOCTYPE html>
</pre>
blockquote
element’s content is a quote, not a chunks of characters.
Bad:
<blockquote>For writing maintainable and scalable HTML documents.</blockquote>
Good:
<blockquote>
<p>For writing maintainable and scalable HTML documents.</p>
</blockquote>
blockquote
element’s content is a quote.
Bad:
<blockquote>
<p>For writing maintainable and scalable HTML documents.</p>
<p>— HTML Best Practices</p>
</blockquote>
Good:
<blockquote>
<p>For writing maintainable and scalable HTML documents.</p>
</blockquote>
<p>— HTML Best Practices</p>
Also good (recommended by WHATWG):
<figure>
<blockquote>
<p>For writing maintainable and scalable HTML documents.</p>
</blockquote>
<figcaption>— HTML Best Practices</figcaption>
</figure>
Also good too (recommended by W3C):
<blockquote>
<p>For writing maintainable and scalable HTML documents.</p>
<footer>— HTML Best Practices</footer>
</blockquote>
Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line is hard toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo read.
Bad:
<ul>
<li>General</li><li>The root Element</li><li>Sections</li>...
</ul>
Good:
<ul>
<li>General</li>
<li>The root Element</li>
<li>Sections</li>
...
</ul>
Sometimes marker referenced by the contents in the near. If you change marker
with type
attribute, you will be safe to reference.
Bad:
<head>
<style>
.toc {
list-style-type: upper-roman;
}
</style>
</head>
<body>
<ol class="toc">
<li>General</li>
<li>The root Element</li>
<li>Sections</li>
...
</ol>
</body>
Good:
<body>
<ol type="I">
<li>General</li>
<li>The root Element</li>
<li>Sections</li>
...
</ol>
</body>
dl
element is restricted to an association list in HTML5.
Bad:
<dl>
<dt>Costello</dt>
<dd>Look, you gotta first baseman?</dd>
<dt>Abbott</dt>
<dd>Certainly.</dd>
<dt>Costello</dt>
<dd>Who’s playing first?</dd>
<dt>Abbott</dt>
<dd>That’s right.</dd>
<dt>Costello becomes exasperated.</dd>
<dt>Costello</dt>
<dd>When you pay off the first baseman every month, who gets the money?</dd>
<dt>Abbott</dt>
<dd>Every dollar of it.</dd>
</dl>
Good:
<p>Costello: Look, you gotta first baseman?</p>
<p>Abbott: Certainly.</p>
<p>Costello: Who’s playing first?</p>
<p>Abbott: That’s right.</p>
<p>Costello becomes exasperated.</p>
<p>Costello: When you pay off the first baseman every month, who gets the money?</p>
<p>Abbott: Every dollar of it.</p>
Spec disallows figcaption
element in the middle of figure
element.
Bad:
<figure>
<img alt="Front cover of the “HTML Best Practices” book" src="/img/front-cover.png">
<figcaption>“HTML Best Practices” Cover Art</figcaption>
<img alt="Back cover of the “HTML Best Practices” book" src="/img/back-cover.png">
</figure>
Good:
<figure>
<img alt="Front cover of the “HTML Best Practices” book" src="/img/front-cover.png">
<img alt="Back cover of the “HTML Best Practices” book" src="/img/back-cover.png">
<figcaption>“HTML Best Practices” Cover Art</figcaption>
</figure>
main
element can be used wrapping contents.
Bad:
<div id="content">
...
</div>
Good:
<main>
...
</main>
div
element is an element of last resort.
Bad:
<div class="chapter">
...
</div>
Good:
<section>
...
</section>
a
element can wrap almost all elements (except interactive elements like form
controls and a
element itself).
Bad:
<h1><a href="https://whatwg.org/">WHATWG</a></h1>
<p><a href="https://whatwg.org/">A community maintaining and evolving HTML since 2004.</a></p>
Good:
<a href="https://whatwg.org/">
<h1>WHATWG</h1>
<p>A community maintaining and evolving HTML since 2004.</p>
</a>
It will force browsers to download linked resource to the storage.
Bad:
<a href="/downloads/offline.zip">offline version</a>
Good:
<a download href="/downloads/offline.zip">offline version</a>
These hints helps applications how handle linked resource.
Bad:
<a href="/ja/pdf">Japanese PDF version</a>
Good:
<a href="/ja/pdf" hreflang="ja" rel="alternate" type="application/pdf">Japanese PDF version</a>
Link text should be the label of its linked resource.
Bad:
<p><a href="/pdf" rel="alternate" type="application/pdf">Click here</a> to view PDF version.</p>
Good:
<p><a href="/pdf" rel="alternate" type="application/pdf">PDF version</a> is also available.</p>
These are seriousness. So, strong
element is more appropriate.
Bad:
<em>Caution!</em>
Good:
<strong>Caution!</strong>
These elements’ semantics is too difficult to humans.
Bad:
<i class="icon-search"></i>
Good:
<span class="icon-search" aria-hidden="true"></span>
Quotes are provided by the browser.
Bad:
<q>“For writing maintainable and scalable HTML documents”</q>
Good:
<q>For writing maintainable and scalable HTML documents</q>
Also good:
“For writing maintainable and scalable HTML documents”
There is no other way to represent its expansion.
Bad:
<abbr>HBP</abbr>
Good:
<abbr title="HTML Best Practices">HBP</abbr>
ruby
element support is not completed across the modern browsers.
Bad:
<ruby>HTML<rt>えいちてぃーえむえる</ruby>
Good:
<ruby>HTML<rp> (</rp><rt>えいちてぃーえむえる</rt><rp>) </rp></ruby>
When datetime
attribute does not present, the format of time
element’s
content is restricted.
Bad:
<time>Dec 19, 2014</time>
Good:
<time datetime="2014-12-19">Dec 19, 2014</time>
This is not a formal way, but spec mentions this.
Bad:
<code><DOCTYPE html></code>
Good:
<code class="language-html"><DOCTYPE html></code>
Nesting kbd
element is too difficult to humans.
Bad:
<kbd><kbd>Ctrl</kbd>+<kbd>F5</kbd></kbd>
Good:
<kbd>Ctrl+F5</kbd>
span
element is an element of last resort.
Bad:
HTML <span class="best">Best</span> Practices
Good:
HTML <em>Best</em> Practices
Line break should be needed where br
element is used.
Bad:
<p>HTML<br>Best<br>Practices</p>
Good:
<p>HTML<br>
Best<br>
Practices</p>
br
element is not for line breaking, it is for line breaks in the contents.
Bad:
<p><label>Rule name: <input name="rule-name" type="text"></label><br>
<label>Rule description:<br>
<textarea name="rule-description"></textarea></label></p>
Good:
<p><label>Rule name: <input name="rule-name" type="text"></label></p>
<p><label>Rule description:<br>
<textarea name="rule-description"></textarea></label></p>
Elements cannot be overflow other elements.
Bad:
<p>For writing maintainable and scalable HTML documents.<del> And for mental stability.</p>
<p>Don’t trust!</p></del>
Good:
<p>For writing maintainable and scalable HTML documents.<del> And for mental stability.</del></p>
<del><p>Don’t trust!</p></del>
The support of picture
element is not good yet.
Bad:
<picture>
<source srcset="/img/logo.webp" type="image/webp">
<source srcset="/img/logo.hdp" type="image/vnd.ms-photo">
<source srcset="/img/logo.jp2" type="image/jp2">
<source srcset="/img/logo.jpg" type="image/jpg">
</picture>
Good:
<picture>
<source srcset="/img/logo.webp" type="image/webp">
<source srcset="/img/logo.hdp" type="image/vnd.ms-photo">
<source srcset="/img/logo.jp2" type="image/jp2">
<img src="/img/logo.jpg">
</picture>
alt
attribute helps those who cannot process images or have image loading
disabled.
Bad:
<img src="/img/logo.png">
Good:
<img alt="HTML Best Practices" src="/img/logo.png">
If the image is supplemental, there is equivalent content somewhere in the near.
Bad:
<img alt="Question mark icon" src="/img/icon/help.png"> Help
Good:
<img alt="" src="/img/icon/help.png"> Help
Sometimes you don’t know what text is suitable for alt
attribute.
Bad:
<img alt="CAPTCHA" src="captcha.cgi?id=82174">
Good:
<img src="captcha.cgi?id=82174" title="CAPTCHA">
(If you cannot see the image, you can use an <a href="?audio">audio</a> test instead.)
There is some restriction in its content. Being empty is always safe.
Bad:
<iframe src="/ads/default.html">
<p>If your browser support inline frame, ads are displayed here.</p>
</iframe>
Good:
<iframe src="/ads/default.html"></iframe>
This content presents to a screen reader.
Bad:
<map name="toc">
<a href="#general">General</a>
<area alt="General" coords="0, 0, 40, 40" href="#General"> |
<a href="#the_root_element">The root element</a>
<area alt="The root element" coords="50, 0, 90, 40" href="#the_root_element"> |
<a href="#sections">Sections</a>
<area alt="Sections" coords="100, 0, 140, 40" href="#sections">
</map>
Good:
<map name="toc">
<p>
<a href="#general">General</a>
<area alt="General" coords="0, 0, 40, 40" href="#General"> |
<a href="#the_root_element">The root element</a>
<area alt="The root element" coords="50, 0, 90, 40" href="#the_root_element"> |
<a href="#sections">Sections</a>
<area alt="Sections" coords="100, 0, 140, 40" href="#sections">
</p>
</map>
Fallback content is needed for newly introduced elements in HTML5.
Bad:
<video>
<source src="/mov/theme.mp4" type="video/mp4">
<source src="/mov/theme.ogv" type="video/ogg">
...
</video>
Good:
<video>
<source src="/mov/theme.mp4" type="video/mp4">
<source src="/mov/theme.ogv" type="video/ogg">
...
<iframe src="//www.youtube.com/embed/..." allowfullscreen></iframe>
</video>
Long lines are hard to scan.
Bad:
<tr>
<td>General</td><td>The root Element</td><td>Sections</td>
</tr>
Good:
<tr>
<td>General</td>
<td>The root Element</td>
<td>Sections</td>
</tr>
There is no reason to avoid this.
Bad:
<table>
<thead>
<tr>
<td><strong>Element</strong></td>
<td><strong>Empty</strong></td>
<td><strong>Tag omission</strong></td>
</tr>
</thead>
<tbody>
<tr>
<td><strong><code>pre</code></strong></td>
<td>No</td>
<td>Neither tag is omissible</td>
</tr>
<tr>
<td><strong><code>img</code></strong></td>
<td>Yes</td>
<td>No end tag</td>
</tr>
</tbody>
</table>
Good:
<table>
<thead>
<tr>
<th>Element</th>
<th>Empty</th>
<th>Tag omission</th>
</tr>
</thead>
<tbody>
<tr>
<th><code>pre</code></th>
<td>No</td>
<td>Neither tag is omissible</td>
</tr>
<tr>
<th><code>img</code></th>
<td>Yes</td>
<td>No end tag</td>
</tr>
</tbody>
</table>
label
element helps focusing form element.
Bad:
<p>Query: <input name="q" type="text"></p>
Good:
<p><label>Query: <input name="q" type="text"></label></p>
label
element can contain some form elements.
Bad:
<label for="q">Query: </label><input id="q" name="q" type="text">
Good:
<label>Query: <input name="q" type="text"></label>
With appropriate type
, browsers gives a tiny features to the input
element.
Bad:
<label>Search keyword: <input name="q" type="text"></label>
Good:
<label>Search keyword: <input name="q" type="search"></label>
The default label for submit button is not standarized across the browser and languages.
Bad:
<input type="submit">
Good:
<input type="submit" value="Search">
If input text does not match to pattern
attribute, the value of title
attribute will be display as a hint.
Bad:
<input name="security-code" pattern="[0-9]{3}" type="text">
Good:
<input name="security-code" pattern="[0-9]{3}" title="A security code is a number in three figures." type="text">
label
element is for a label, placeholder
attribute is for a short hint.
Bad:
<input name="email" placeholder="Email" type="text">
Good:
<label>Email: <input name="email" placeholder="[email protected]" type="text"></label>
Long lines are hard to scan.
Bad:
<datalist id="toc">
<option label="General"><option label="The root element"><option label="Sections">
</datalist>
Good:
<datalist id="toc">
<option label="General">
<option label="The root element">
<option label="Sections">
</datalist>
With max
attribute, the value
attribute can be write in an easy format.
Bad:
<progress value="0.5"> 50%</progress>
Good:
<progress max="100" value="50"> 50%</progress>
With min
and max
attribute, the value
attribute can be write in an easy
format.
Bad:
<meter value="0.5"> 512GB used (1024GB total)</meter>
Good:
<meter min="0" max="1024" value="512"> 512GB used (1024GB total)</meter>
Spec requires this.
Bad:
<fieldset>
<p><label>Is this section is useful?: <input name="usefulness-general" type="checkbox"></label></p>
...
<legend>About "General"</legend>
</fieldset>
Good:
<fieldset>
<legend>About "General"</legend>
<p><label>Is this section is useful?: <input name="usefulness-general" type="checkbox"></label></p>
...
</fieldset>
In HTML5, the default type
attribute’s value of script
element is
text/javascript
.
Bad:
<script type="text/javascript">
...
</script>
Good:
<script>
...
</script>
async
attribute is better, but some browser doesn’t support this attribute.
defer
attribute is not bad.
Bad:
<script async src="/js/main.js"></script>
Good:
<script async defer src="/js/main.js"></script>
This ritual is for the old browser.
Bad:
<script>
/*<![CDATA[*/
...
/*]]>*/
</script>
Also bad:
<script>
<!--
...
// -->
</script>
Good:
<script>
...
</script>
async
attribute is the best for both simplicity and performance.
Bad:
<script>
var script = document.createElement("script");
script.async = true;
script.src = "//example.com/widget.js";
document.getElementsByTagName("head")[0].appendChild(script);
</script>
Good:
<script async defer src="//example.com/widget.js"></script>
Indentation is important for readability.
Bad:
<html>
<head>
...
</head>
<body>
...
</body>
</html>
Good:
<html>
<head>
...
</head>
<body>
...
</body>
</html>
An absolute path works better on your localhost without internet connection.
Bad:
<link rel="apple-touch-icon" href="http://you.example.com/apple-touch-icon-precomposed.png">
...
<p>You can find more at <a href="//you.example.com/contact.html">contact page</a>.</p>
Good:
<link rel="apple-touch-icon" href="/apple-touch-icon-precomposed.png">
...
<p>You can find more at <a href="/contact.html">contact page</a>.</p>