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.

© 2026 Xygeni. All rights reserved