Validation starts at the first line of the file. If the doctype is missing or wrong, the browser switches to a compatibility mode designed for websites built in the nineties, and the validator has no idea which set of rules to apply. Both consequences are avoidable with fourteen characters.
<!DOCTYPE html>
That is the whole thing. It is not a tag, not an element, and it contains no version number, which surprises people who remember the two line declarations of the past. Those old strings existed because HTML 4 and XHTML were defined by document type definitions, and the parser needed to be told which one to load. The current specification has no DTD, so the declaration has been reduced to a marker whose only job is to say: use standards mode.
It is case insensitive, so <!doctype html> is equally valid. Nothing may come before it, not a blank line, not a comment, and certainly not a stray character produced by a template. A single space before the doctype is harmless in practice but a byte order mark or a PHP warning is not.
A document with no doctype triggers quirks mode. The most visible consequence is the box model: in quirks mode a declared width includes padding and border, in standards mode it does not. A layout designed under one rule and rendered under the other will be wrong by exactly the sum of its paddings, which is the source of a surprising number of mysterious alignment bugs.
| Declaration | Rendering mode | Verdict |
|---|---|---|
| Nothing at all | quirks | fix it now |
<!DOCTYPE html> | standards | correct |
| HTML 4.01 Transitional | standards, old rule set | obsolete, replace |
| XHTML 1.0 Strict | standards, old rule set | obsolete, replace |
| XHTML 1.0 Frameset | quirks in some cases | replace |
Replacing an old doctype with the short one is safe in the overwhelming majority of cases, since both already select standards mode. The exception worth a test is a site that still relies on XHTML syntax habits mixed with HTML parsing, where a few self closing tags may behave differently.
A document needs four things to pass validation: a doctype, a language, a character encoding declaration and a title. Everything else is optional as far as the rules go.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Page title</title>
</head>
<body>
<p>Hello.</p>
</body>
</html>
The <html>, <head> and <body> tags may technically be omitted, because the parser inserts them for you. Do not do it. The elements exist in the resulting tree either way, and writing them explicitly is the difference between a file another developer can read and one they have to reason about.
Put it first, within the first 1024 bytes, and use UTF-8. Any other encoding in a new document is a decision you will regret the first time someone types a curly quote. Make sure the file itself is actually saved as UTF-8, without a byte order mark: declaring one encoding while serving another produces the mangled characters that no amount of markup will fix.
Required, exactly once, and it must contain text. An empty title passes the letter of the rule while being useless to every search engine and every bookmark list.
Not required by the specification, required by reality. Without it a phone renders your page at desktop width and scales it down, so your responsive stylesheet never gets a chance.
<meta name="viewport" content="width=device-width, initial-scale=1">
Resist the temptation to add user-scalable=no or a maximum scale. It does not help your design and it takes zoom away from people who need it.
Also optional, also worth writing. It has no direct effect on ranking, but it is often the text shown under your link in a result page, and a good one earns clicks a generated snippet would not.
Stylesheets belong in the head, because a page rendered before its styles arrive flashes unstyled content. Scripts belong at the end of the body, or in the head with the defer attribute, which downloads them in parallel and runs them once the document is parsed. A plain <script src> in the head blocks parsing until the file has arrived, which is the single easiest performance mistake to make.
<link rel="stylesheet" href="/style.css">
<script src="/app.js" defer></script>
Self closing slashes on void elements, as in <br /> or <img ... />, are accepted and ignored by the parser. They are not errors, so a validator will not complain, but they carry no meaning either. On a non void element the slash is silently dropped, so <div /> opens a div that is never closed, which is a genuine trap.
Attribute values do not strictly need quotes when they contain no spaces or special characters, and uppercase tag names are allowed. Both freedoms are best declined: quote every value, write every tag in lowercase, and your diffs stay readable.
<p lang="fr"> around the French passage. Screen readers switch pronunciation accordingly, and translation tools stop trying to translate what is already translated.
Once the skeleton is right, the rest of the document usually follows. Run the site wide validator to see whether the same head level problem is repeated across every template, which is the common case: one fix in one include file and the error count drops to zero. The error messages you are most likely to meet next are explained on the common HTML errors page.
The authoritative text on all of this is the HTML living standard, published by the WHATWG, with reference documentation maintained on MDN Web Docs.