Doctype Errors: Fixing a Missing or Wrong Doctype
The doctype is the short line at the very top of an HTML file. It carries no content, yet browsers use it to decide which set of layout rules to follow.
When it is missing, misspelt, an old HTML 4 or XHTML version, or pushed down the file by stray output, the browser can fall back to quirks mode and your CSS starts behaving strangely. The HTML Checker reports these as doctype errors. This guide explains what each message means, how to prove which rendering mode a page is in, and how to fix the template that produces it.
What the doctype actually does
In the early days of CSS, browsers disagreed about basic sums such as how wide a box is once padding and borders are added. When browsers were later corrected to follow the standards, millions of existing pages relied on the old, wrong behaviour. The compromise was doctype sniffing: pages that declared a modern doctype got the standards behaviour, and pages without one kept the old behaviour so they would not suddenly break.
That compromise survives in every current browser. The HTML specification defines three modes:
| Mode | What triggers it | What changes |
|---|---|---|
| No-quirks (standards) | <!DOCTYPE html>, and some strict
older doctypes | Layout follows the current CSS specifications. |
| Limited-quirks (almost standards) | HTML 4.01 Transitional or Frameset with a system identifier, and XHTML 1.0 Transitional or Frameset | One notable difference: images inside table cells are laid out the old way, which leaves small gaps under them. |
| Quirks | No doctype, a doctype after other content, a malformed doctype, or an old public identifier without a system identifier | A long list of legacy behaviours, including the old box model on some elements, tables not inheriting font sizes, and percentage heights resolving differently. |
Only the first is what you want. The doctype does not tell the browser which version of HTML you wrote, and it does not switch features on or off. It is purely a switch between rendering modes, which is why the modern version is so short.
<!DOCTYPE html>, <!doctype html>
and <!DocType HTML> are all valid and all give standards mode. Pick one form and use
it in every template.The messages you will see and what they mean
The HTML Checker follows the same wording as the W3C Nu validator, so the messages below are the ones to search your report for.
Start tag seen without seeing a doctype first
The parser reached an element, usually <html> or <head>, before
any doctype. Either the doctype is missing from the template altogether, or the page is assembled from
pieces and the piece that holds the doctype is not being included. The page is in quirks mode.
Non-space characters found without seeing a doctype first
Some visible text arrived before the doctype. This is the classic sign of a server-side script printing
something too early: a PHP notice, a debugging echo, a stray character left in an include
file, or a plugin writing output when it loads. The page is in quirks mode, and the stray text often
appears as a line at the top of the screen.
Obsolete doctype. Expected <!DOCTYPE html>
The page uses an older declaration such as HTML 4.01 Strict or XHTML 1.0 Strict. These still give standards mode, so the layout is probably fine, but the validator flags them because they are no longer conforming. Replacing them is a one-line change.
Almost standards mode doctype. Expected <!DOCTYPE html>
A transitional or frameset doctype is putting the page into limited-quirks mode. The visible symptom is usually a few pixels of space under images in tables or in elements styled as table cells.
Quirky doctype. Expected <!DOCTYPE html>
The doctype exists but is one of the forms that browsers deliberately treat as quirks mode, for example HTML 4.01 Transitional written without its URL. Some very old site builders and email tools output these.
Stray doctype
A doctype appeared after the document had already started. This almost always means a complete HTML
document has been pasted or included inside another one. The second doctype is ignored by the browser,
but the <html>, <head> and <body> tags that
come with it produce a cascade of further errors.
What is allowed before the doctype
There is a lot of folklore about the first line of an HTML file. The actual rules are narrower than many tutorials suggest. According to the HTML specification, a document may begin with the following before the doctype without any effect on the rendering mode:
- A byte order mark. The invisible BOM that some editors add to UTF-8 files is permitted at the very start of the document and is used by browsers to detect the encoding. It is not an error, although it can cause other trouble in PHP includes, which the character encoding guide covers.
- Whitespace. Blank lines and spaces before the doctype are allowed and do not trigger quirks mode in current browsers.
- Comments. An HTML comment such as a build stamp can sit above the doctype. Some very old versions of Internet Explorer mishandled this, which is where the advice to avoid it comes from, but it is conforming HTML.
What is not allowed is any other character: text, a tag, a PHP warning, an XML declaration
in a page served as text/html that is then followed by other stray output, or a second copy
of the page. So when you hunt for the cause, you are looking for visible characters, not whitespace.
<?php tags, can stop
later code from sending headers or cookies. Keep the doctype as the first output for that reason, even
though the validator would accept the whitespace.Proving what the browser received
The fastest check is the browser console. Open the page, open developer tools and run this in the console:
document.compatMode
// "CSS1Compat" means standards or limited-quirks mode
// "BackCompat" means quirks mode
document.doctype
// shows the doctype node the parser found, or null if there was none
document.compatMode cannot tell standards mode from limited-quirks mode, so if it says
CSS1Compat but you suspect a transitional doctype, read document.doctype.publicId
and document.doctype.systemId. Firefox also prints a console message when a page loads in
quirks mode.
Next, look at what the server actually sends rather than what your template file contains. View Source is good, but it can hide invisible characters. From a terminal:
curl -s https://www.example.co.uk/ | head -c 200 | od -c | head -8
This prints the first 200 bytes one character at a time. You should see the doctype immediately, optionally
preceded by the three BOM bytes (shown as 357 273 277) or whitespace. Anything else in front
of it is the cause of your problem.
Test more than the home page
Doctype problems are often confined to one template. A shop may have a correct home page while product pages load a different header file, or an error page, search results page or print view may be built by separate code. Run the HTML Checker on one page of each type, and include pages behind query strings, such as filtered listings, which sometimes go through a different code path.
Where the doctype lives on common platforms
| Platform | File that outputs the doctype | Usual cause of errors |
|---|---|---|
| WordPress (classic themes) | header.php in the active theme or child theme | An old theme with an XHTML doctype, or a plugin printing a notice before the header loads. |
| WordPress (block themes) | Generated by WordPress core | Rarely the doctype itself;
look for plugins or functions.php code producing early output. |
| Shopify | layout/theme.liquid and any alternate layouts | A second layout file, for example for a landing page app, written without a doctype. |
| Laravel, Django, Rails | The base layout that other views extend | A view that does not extend the base layout, or a partial that contains a full document. |
| React, Next.js, Vue | The server document or root layout; Next.js adds it automatically | A
custom server template or a static index.html edited by hand. |
| Static site generators | The base layout in the layouts or includes folder | A page using a different layout, or a layout that includes another full layout. |
| Hand-built HTML | Every file | Pages copied from an old template years ago. |
The line should read exactly this, with the html element and the character encoding following immediately:
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Garden rooms and summerhouses | Larchfield Timber</title>
The fix, step by step
Step 1
Confirm the rendering mode in the browser
Open a page the HTML Checker flagged, open the developer tools console and run document.compatMode.
A result of BackCompat means quirks mode and should be fixed first, because it changes layout.
A result of CSS1Compat with an obsolete or almost standards warning is less urgent. Check
document.doctype too; a result of null means the parser found no doctype at all, not merely
an old one.
Step 2
Read the raw bytes the server sends
Fetch
the page with curl and look at the first few hundred bytes, or use View Source and check
the very first line. You are looking for anything other than whitespace, a comment or a byte order mark
in front of the doctype: a warning message, a stray letter, a closing PHP tag followed by text, or a
second HTML document. Write down exactly what appears, because it tells you which file to open.
Step 3
Replace any old doctype with the HTML5 one
Open the base layout or header template and replace the whole HTML 4 or XHTML declaration,
including its long public identifier and URL, with <!DOCTYPE html>. On XHTML templates,
also remove the xmlns attribute only if you are sure the page is served as text/html,
and replace any old http-equiv content type tag with <meta charset="utf-8">.
Do this in a child theme or your own layout file, never in files an update will overwrite.
Step 4
Remove output printed before the doctype
If text appears before the doctype, find where it comes from. A PHP notice or deprecation
warning means you should fix that code and set display_errors to off in production so errors
are logged instead of printed. A stray character usually lives after a closing ?> tag
in an include or functions.php; removing the closing tag from files that contain only PHP
prevents it. Deactivate plugins one at a time if the source is unclear.
Step 5
Delete doctypes repeated inside the page
A stray doctype message means a whole document has been placed inside another. Search
the template and the content for a second <!DOCTYPE, typically in an HTML block pasted
from an email builder, an embedded widget saved as a full page, or a partial that was once a standalone
file. Keep only the fragment that belongs in the body, and delete its doctype, html, head
and body tags along with their closing tags.
Step 6
Retest the layout after switching modes
Moving a page from quirks mode to standards mode can change its appearance, because the
CSS was written against the old rules. Clear caches, rerun the HTML Checker, confirm document.compatMode
now reads CSS1Compat, and then check the page at mobile and desktop widths. Look closely
at boxes with padding, tables, full-height sections and images in table cells, and fix any shifts in
the stylesheet rather than reverting the doctype.
Layout changes to expect after the switch
Fixing a doctype on a page that has been in quirks mode for years sometimes looks like it broke the page. It did not; it exposed CSS that only worked because of legacy behaviour. These are the differences you are most likely to notice:
- Box sizes. Under standards rules,
widthmeans the content width and padding and borders are added on top. Many designs now setbox-sizing: border-boxon all elements to get the intuitive behaviour without relying on quirks mode. - Percentage heights. In quirks mode,
height: 100%on the body often fills the window. In standards mode it needs thehtmlelement to have a height too, or you can use viewport units such asmin-height: 100vhinstead. - Gaps under images. Images are inline by default and sit on the text baseline, leaving
a small gap below them. Setting
display: blockorvertical-align: middleon the images removes it. - Table text size. In quirks mode, tables do not inherit the font size from the page. After the switch, text in tables may suddenly match the rest of the page and appear larger or smaller than before.
- Unitless lengths. Quirks mode accepts values such as
width: 300without a unit in some cases. Standards mode ignores them, so addpxwhere it is missing.
Edge cases
- Pages served as XHTML. A document sent with the
application/xhtml+xmlcontent type is parsed as XML and never enters quirks mode, whatever its doctype. This is rare on public websites; most XHTML-looking pages are actually served astext/htmland follow the normal rules. - The legacy-compat doctype.
<!DOCTYPE html SYSTEM "about:legacy-compat">is a permitted alternative for tools that cannot output the short form. It is valid, gives standards mode, and does not need changing. - Iframes. Each iframe has its own document and its own mode. A widget in an iframe can be in quirks mode while your page is not; fixing it is the widget provider's job.
- HTML emails. Email templates often keep an XHTML Transitional doctype on purpose because of how some email clients behave. Emails are outside the scope of the website checker.
- Fragments loaded by JavaScript. HTML snippets fetched and inserted into a page should not have a doctype at all. If you validate such a snippet on its own, ignore the missing doctype message.
- Error pages from the server or CDN. Default 404 and 500 pages generated by the web server, a load balancer or a CDN may have no doctype. Replace them with custom error pages built from your normal template.
Keeping it fixed
- One base layout. Make every page type extend a single base layout that owns the
doctype, the
htmlelement and the charset. Pages built outside it are where the problem returns. - Errors to logs, not screens. Production servers should log PHP and application errors rather than print them. That removes the most common source of text before the doctype.
- An automated check. A simple test that fetches key URLs and fails if the response body does not start with the doctype, after an optional BOM and whitespace, catches regressions in a deployment pipeline.
- Regular validation. Rerun the HTML Checker after theme updates, plugin installs and migrations, which are the moments doctypes most often change.
1. Does a missing doctype hurt SEO?
Not directly. Search engines do not rank pages on whether they declare a doctype, and Google renders pages in a modern browser engine that copes with quirks mode. The indirect effects are what matter: quirks mode can break a responsive layout, push content out of view on phones or make text overlap, which harms how visitors use the page. Text printed before the doctype, such as a PHP error, can also end up in search snippets. Fix it for visitors first.
2. Is <!doctype html> in lower case valid?
Yes. The doctype keyword and the word html are both case-insensitive, so lower case, upper case and mixed case all produce standards mode and all pass validation. Many developers prefer the lower-case form because it compresses slightly better and matches the rest of their markup. What matters is that the text is complete, spelt correctly and is the first real content in the file. Choose one style and use it in every template so searches across the codebase find them all.
3. Can there be a blank line or a comment before the doctype?
Yes, according to the HTML specification. A byte order mark, whitespace and HTML comments may all appear before the doctype without triggering quirks mode in current browsers. Visible text, tags or error messages may not. The advice to keep the doctype on the first line is still sensible, partly because very old browsers were stricter and partly because in PHP any output before your code sends headers, including a blank line, can cause header and cookie errors.
4. Why did my layout change after I fixed the doctype?
Because the page had been rendering in quirks mode, and the CSS was relying on the old behaviour without anyone realising. In standards mode, padding adds to an element's width, percentage heights need a parent with a set height, images leave a small gap underneath, and tables inherit font sizes. Adjust the CSS to work under standards rules, for example by using border-box sizing and viewport height units, rather than putting the old doctype back.
5. Should I replace an XHTML 1.0 Strict doctype if the page looks fine?
It is worth doing, but it is low priority. XHTML 1.0 Strict and HTML 4.01 Strict already put browsers into standards mode, so the page will look the same after the change. The validator flags them as obsolete because they are no longer conforming, and the long declaration is easy to copy wrongly into new templates. Swap in the short HTML5 doctype next time you edit the base layout, and check that the page is served as text/html.
6. How do I tell if a page is in quirks mode?
Open the page, open your browser developer tools and type document.compatMode into the console. BackCompat means quirks mode; CSS1Compat means standards or almost standards mode. To tell those last two apart, look at document.doctype and check its public identifier. Firefox also logs a message to the console when a page loads in quirks mode. The HTML Checker reports the same problem from the other side by flagging the missing, quirky or transitional doctype that caused it.
7. Why does the checker report a stray doctype in the middle of my page?
A stray doctype means the parser met a second doctype after the document had already begun. It nearly always comes from a whole HTML document being placed inside another: an embed pasted with its full page wrapper, a partial template that still contains the full skeleton, or content copied from an email builder. Browsers ignore the extra doctype but the repeated html, head and body tags cause further errors. Keep only the fragment that belongs in the body.
The HTML Checker validates your markup against W3C standards and reports errors and warnings from the doctype and character encoding through to nesting, ARIA, forms and the language attribute, so you can fix each template at its source.
Open HTML Checker Fixes โ