Doctype and Character Encoding: Two Lines Every Page Needs
Two small declarations at the very top of a page decide how browsers interpret everything after them: the doctype, which selects the rendering mode, and the character encoding, which decides how bytes turn into letters. Both are easy to get right and surprisingly annoying to debug when wrong.
Why the doctype matters
<!doctype html> tells the browser to render in standards mode. Without it, or with an old
HTML 4 or XHTML doctype that lacks a URL, browsers fall back to quirks mode, which emulates
1990s browser bugs: box sizes are calculated differently, table cells inherit font sizes oddly, and
some CSS behaves unexpectedly. The page may look fine in one browser and broken in another.
Why the character encoding matters
If the browser guesses the encoding wrong, accented and non-Latin characters turn into garbage (“ç” instead of “ç”). Search engines may index that garbage too. UTF-8 covers every language and is what the web standard recommends, but it still has to be declared.
What we check
Doctype (seo.doctype): the first thing in the document, after optional whitespace and
comments.
| Result | When |
|---|---|
| Passed | <!doctype html> (any capitalization) |
| Needs attention | an older doctype, such as HTML 4.01 or XHTML 1.0 |
| Failed | no doctype |
Charset (seo.charset): the charset in the Content-Type header, else <meta charset>, else
<meta http-equiv="Content-Type">.
| Result | When |
|---|---|
| Passed | UTF-8 is declared |
| Needs attention | another encoding, such as ISO-8859-9 or Windows-1254 |
| Failed | no encoding is declared anywhere |
How to fix
Start every page like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- everything else -->
</head>
</html>
- Put nothing before the doctype except whitespace. A byte-order mark is fine; stray output from a server-side script is not.
- Put
<meta charset="utf-8">first in<head>: the browser only looks within the first 1,024 bytes. - Also send the encoding in the HTTP header:
Content-Type: text/html; charset=utf-8. Most frameworks do this already; in Nginx it’scharset utf-8;.
Moving an old site to UTF-8
If your pages are stored in a legacy encoding, declaring UTF-8 isn’t enough: the files or database
content must be converted too, otherwise every special character breaks. Convert the data first
(for MySQL, to utf8mb4), then change the declaration, and test pages with non-ASCII text.
Further reading: MDN: Quirks mode and W3C: Declaring character encodings in HTML.