A missing or outdated DOCTYPE changes how a page is laid out and how its CSS is parsed. We ran 34 variants through Chrome, Firefox and WebKit and measured the three modes side by side.
Check your browser
The first line reads this page. The menu loads a hidden test page with the DOCTYPE you pick. compatMode can’t tell limited quirks from no quirks, so the demo also measures a line holding one image. Only the two quirks modes shrink that line to the height of the image.
This page, in your browser: checking
<!doctype html>
Measuring
What each DOCTYPE triggers
Browsers pick one of three modes when the parser reaches the DOCTYPE, using fixed lists in the HTML standard. We served 34 variants over HTTP and recorded the mode in each browser. “URL” means the second quoted string, which the standard calls the system identifier.
| DOCTYPE | Chrome | Firefox | WebKit |
|---|---|---|---|
| HTML5 | No quirks | No quirks | No quirks |
| No DOCTYPE | Quirks | Quirks | Quirks |
| HTML 4.01 Strict, with URL | No quirks | No quirks | No quirks |
| HTML 4.01 Strict, no URL | No quirks | No quirks | No quirks |
| HTML 4.01 Transitional, with URL | Limited quirks | Limited quirks | Limited quirks |
| HTML 4.01 Transitional, no URL | Quirks | Quirks | Quirks |
| HTML 4.01 Transitional, empty URL | Quirks | Limited quirks | Quirks |
| HTML 4.01 Frameset, with URL | Limited quirks | Limited quirks | Limited quirks |
| HTML 4.01 Frameset, no URL | Quirks | Quirks | Quirks |
| HTML 4.0 Transitional, with URL | Quirks | Quirks | Quirks |
| HTML 3.2 | Quirks | Quirks | Quirks |
| XHTML 1.0 Strict | No quirks | No quirks | No quirks |
| XHTML 1.0 Transitional | Limited quirks | Limited quirks | Limited quirks |
| XHTML 1.1 | No quirks | No quirks | No quirks |
| Made-up public identifier | No quirks | No quirks | No quirks |
| Name other than html | Quirks | Quirks | Quirks |
| XHTML 1.0 Transitional, served as XHTML | No quirks | No quirks | No quirks |
| No DOCTYPE, served as XHTML | No quirks | No quirks | No quirks |
Dropping the URL from HTML 4.01 Transitional moves a page from limited quirks to full quirks. The match ignores case: the same DOCTYPE in lower case with no URL also gave quirks. A public identifier the lists don’t contain gets no quirks, so an invented one behaves like HTML5.
Firefox 159 made the only departure from the standard in the run. With an empty URL (""), the standard says quirks, and Chrome and WebKit agreed. Firefox gave limited quirks. Pages sent as application/xhtml+xml use the XML parser and got no quirks whatever the DOCTYPE said, including when there was none.
What can come before it
A comment, blank lines or a byte order mark before the DOCTYPE did no harm in any browser.
| Before the DOCTYPE | Chrome, Firefox, WebKit |
|---|---|
| Comment before it | No quirks |
| Blank lines before it | No quirks |
| Byte order mark before it | No quirks |
| XML declaration before it | No quirks |
| Stray text before it | Quirks |
| <html> tag before it | Quirks |
A PHP warning or a debug line printed at the top of a template puts the whole page in quirks mode, even with a correct DOCTYPE below it.
What each mode changes
We loaded each test page once per mode, in a 1000 by 800 window. Values are in pixels. Chrome’s number is shown, and another browser is named only if it differed.
| Measurement | Quirks | Limited quirks | No quirks |
|---|---|---|---|
| 20px image alone in a div | 20 | 20 | 24 (Firefox 23.5) |
| 20px image alone in a td | 20 | 20 | 24 (Firefox 23.5) |
| Same image, line-height 50px | 20 | 20 | 50 |
| height: 50% on a child of body | 392 | 18 | 18 |
| 50% through an auto parent, 200px box | 100 | 18 | 18 |
| td: height 100, padding 20, border 5 | 100 | 150 | 150 |
| td holding one p, height | 18 | 50 | 50 |
| div: width 200, padding 20, border 5 | 250 | 250 | 250 |
| table, same CSS | 200 | 200 | 200 |
| input, same CSS | 200 | 250 | 250 |
| textarea, same CSS | 200 | 250 | 250 |
| Table text, body font-size 30px | 16 | 30 | 30 |
| Two 50px images, table width 1px | 100 | 50 | 50 |
Quirks mode no longer brings back the old Internet Explorer box model. The div measured 250 pixels wide in every mode, with box-sizing still content-box. Tables are border-box in all three. Of the controls we measured, only input and textarea switch.
Limited quirks differed from no quirks on one thing: lines holding only an image. The Quirks Mode standard writes that rule for any inline box, and the plain div collapsed the same way as the table cell. Every other measurement in the run matched.
Table text in quirks mode ignores what it would inherit. Font size went back to 16, weight and style to normal, and color came from body, skipping the div around the table in our test.
Firefox differs from the other two on the size of the page. In quirks mode Chrome and WebKit made html 800 pixels tall and body 784. Firefox reported 34 and 18, as it did in the other modes, though its percentage heights still resolved against the window. An empty table with a 10 pixel border was 0 pixels tall in Firefox and 20 in Chrome and WebKit. The standard asks for 0.
CSS parsing and scripts
Scroll values were read after moving a 5000 pixel page down 300 pixels in an 800 pixel window. All three browsers returned the same values.
| Test | Quirks | Limited quirks | No quirks |
|---|---|---|---|
| color: ff0000 | Red | Ignored | Ignored |
| width: 100 | 100px | Ignored | Ignored |
| .Foo matches class=foo | Yes | No | No |
| #Bar matches id=bar | Yes | No | No |
| document.scrollingElement | body | html | html |
| documentElement.scrollTop | 0 | 300 | 300 |
| body.scrollTop | 300 | 0 | 0 |
| documentElement.clientHeight | 5016 | 800 | 800 |
| body.clientHeight | 800 | 5000 | 5000 |
window.scrollY returned 300 in every mode, so use it to read the position, and document.scrollingElement when you need the element. getElementById stayed case sensitive in quirks mode, while selectors and getElementsByClassName did not.
Firefox 159 has one odd behaviour here. When two same-origin pages in a row had an identical inline style sheet, one in quirks mode and one not, the second page used the first page’s parse. color: ff0000 stayed red on a no-quirks page that followed a quirks one, and stayed ignored on a quirks page that followed a no-quirks one. Chrome and WebKit parsed each page separately.
Photo by Rachel ClaireFrames have their own mode
A frame doesn’t inherit its parent’s mode. Every row ran inside an HTML5 page.
| Document | Chrome | Firefox | WebKit |
|---|---|---|---|
| srcdoc, no DOCTYPE | CSS1Compat | CSS1Compat | CSS1Compat |
| srcdoc, HTML 3.2 DOCTYPE | CSS1Compat | CSS1Compat | CSS1Compat |
| iframe src, page with no DOCTYPE | BackCompat | BackCompat | BackCompat |
| Empty iframe (about:blank) | BackCompat | BackCompat | BackCompat |
| document.write, no DOCTYPE | BackCompat | BackCompat | BackCompat |
| document.write, with DOCTYPE | CSS1Compat | CSS1Compat | CSS1Compat |
| DOMParser, no DOCTYPE | BackCompat | BackCompat | CSS1Compat |
| createHTMLDocument() | CSS1Compat | CSS1Compat | CSS1Compat |
A srcdoc frame is never in quirks mode, even with an HTML 3.2 DOCTYPE. A frame filled with document.write and no DOCTYPE is in quirks mode inside a standards page, so a widget built that way needs the DOCTYPE in the string it writes.
How to fix a quirks page
- Run
document.compatModein the console on the live page. MDN notes that Firefox also logs a console warning for both quirks modes. - Put
<!doctype html>first, and check nothing in the template prints before it. - If the layout moved, add the CSS below and correct any colours with no
#, lengths with no unit, and class names in the wrong case. - Replace
documentElement.scrollTopandbody.scrollToplogic withwindow.scrollY.
html, body { height: 100%; margin: 0; }
img { vertical-align: bottom; }
input, textarea, td, th { box-sizing: border-box; }
table {
font-size: medium; font-weight: normal; font-style: normal;
line-height: normal; text-align: start; white-space: normal;
}On an HTML5 page with these rules, the input, the image cell and the td measured 200, 20 and 100 pixels, the same as quirks mode without them. height: 50% on a child of body gave 400. display: block on the image closes the gap as well. If something still shifts, cut the page down to a reduced test case.
How this was tested
A script served every page from a temporary local server with real Content-Type headers, on 8 November 2026, on Windows 11.
- Chrome 156.0.8078.80, headless.
- Firefox 159.0.1, headless.
- WebKit 26.0 from Playwright 1.56.1. This is not Safari, and nothing here ran on an iPhone.
We left some quirks untested: text decoration into tables, :hover on non-links and nowrap cells with a width. The full output is available as raw JSON. The test script and this article were prepared with help from AI.
How this used to work
The Quirks Mode standard calls the split “basically a historical accident”. CSS as specified clashed with what existing pages relied on, so browsers kept the old behaviour and added a new mode. Some browsers kept the old sizing of images in table cells in their new mode, sites came to depend on it, and the browsers that followed the specification added a third mode. Using the DOCTYPE as the switch was browsers’ own idea: Henri Sivonen’s reference points out that neither HTML 4.01 nor SGML defines it. The same reference says an XML declaration before the DOCTYPE put IE 6 in quirks mode. None of the three browsers here did that.
Common questions
How can a script tell limited quirks from no quirks?
compatMode returns CSS1Compat for both. Read document.doctype.publicId, or measure a line holding only an image as the demo above does.
Is an old XHTML Transitional DOCTYPE a problem?
Limited quirks changed only lines holding an image in our run, so it is a small problem. Replace it the next time you edit the template.
Can I switch mode with CSS or a meta tag?
The HTML standard sets the mode from the DOCTYPE during parsing, and XML pages skip it. The X-UA-Compatible header and meta tag were for Internet Explorer.
Sources
- HTML Standard: the initial insertion mode
- HTML Standard: rendering
- Quirks Mode Standard
- DOM Standard: compatMode
- Quirks mode and standards mode, MDN
- Activating Browser Modes with Doctype, Henri Sivonen
All sources were read on 8 November 2026.
