Doctype After The First Tag
ID |
html.doctype_first |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Html |
Tags |
best-practice, reliability |
Description
Reports a <!DOCTYPE> declaration that is present but written after the markup has already
started — most often just below the <html> tag.
Comments are allowed before the declaration, so a licence header above it is fine. Only an open tag
ends the region in which a doctype still counts — and two things that look like an open tag are not
one. A tag written inside a template-engine comment (Smarty’s {* *}, Jinja’s {# #}) is stripped
by the engine and never reaches a browser, so an e-mail address in a licence header,
<brady@example.com>, does not start the markup. Neither does a < followed by something that
does not spell a tag name: a name starts with a letter and carries letters, digits and - _ : ..
Rationale
A doctype selects standards mode only when it is the first thing in the document. Once a tag has opened, the browser has committed to quirks mode, and the declaration that follows is inert: it is parsed, it is valid, and it changes nothing.
That makes a misplaced doctype harder to diagnose than a missing one. The page emulates legacy
box-model and layout bugs — percentage heights, width including padding, inline-block baselines —
while the source carries what looks like a correct declaration, so the usual first check ("does it
have a doctype?") passes and the real cause is somewhere nobody looks.
<html lang="en">
<!DOCTYPE html>
<head><title>Order summary</title></head>
<body><p>Order</p></body>
</html>
Remediation
Move the declaration above every tag. Nothing but comments may precede it.
<!DOCTYPE html>
<html lang="en">
<head><title>Order summary</title></head>
<body><p>Order</p></body>
</html>
When the page is assembled from templates or server-side includes, the declaration belongs in the
outermost layout, above the include that opens <html> — not in a partial that is stitched in
afterwards.
Scope
This rule covers only the case where a declaration exists in the wrong place. A document that
declares no doctype anywhere is reported separately, by html.doctype_declaration. This rule checks
first that a declaration exists somewhere, so it never reports a document that has none.
A misplaced declaration cannot be seen in the parsed document tree — the transformer keeps a doctype
node only for a declaration at the top of the file, so one written inside <html> is dropped
entirely. Detection therefore works on the token stream, comparing each declaration’s position
against the first tag that opens.