Dotted pixel art of rows of red and orange tulips below a dark green treeline and a grey-blue sky.

Quirks mode and the DOCTYPE

Author
gunlaug team
Updated
8 Nov 2026
Reading time
7 min

Photo by Siegfried Poepperl

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.

Rendering mode by DOCTYPE and browser
DOCTYPEChromeFirefoxWebKit
HTML5No quirksNo quirksNo quirks
No DOCTYPEQuirksQuirksQuirks
HTML 4.01 Strict, with URLNo quirksNo quirksNo quirks
HTML 4.01 Strict, no URLNo quirksNo quirksNo quirks
HTML 4.01 Transitional, with URLLimited quirksLimited quirksLimited quirks
HTML 4.01 Transitional, no URLQuirksQuirksQuirks
HTML 4.01 Transitional, empty URLQuirksLimited quirksQuirks
HTML 4.01 Frameset, with URLLimited quirksLimited quirksLimited quirks
HTML 4.01 Frameset, no URLQuirksQuirksQuirks
HTML 4.0 Transitional, with URLQuirksQuirksQuirks
HTML 3.2QuirksQuirksQuirks
XHTML 1.0 StrictNo quirksNo quirksNo quirks
XHTML 1.0 TransitionalLimited quirksLimited quirksLimited quirks
XHTML 1.1No quirksNo quirksNo quirks
Made-up public identifierNo quirksNo quirksNo quirks
Name other than htmlQuirksQuirksQuirks
XHTML 1.0 Transitional, served as XHTMLNo quirksNo quirksNo quirks
No DOCTYPE, served as XHTMLNo quirksNo quirksNo 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.

Rendering mode by what precedes the DOCTYPE
Before the DOCTYPEChrome, Firefox, WebKit
Comment before itNo quirks
Blank lines before itNo quirks
Byte order mark before itNo quirks
XML declaration before itNo quirks
Stray text before itQuirks
<html> tag before itQuirks

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.

Layout measurements in quirks, limited quirks and no quirks mode
MeasurementQuirksLimited quirksNo quirks
20px image alone in a div202024 (Firefox 23.5)
20px image alone in a td202024 (Firefox 23.5)
Same image, line-height 50px202050
height: 50% on a child of body3921818
50% through an auto parent, 200px box1001818
td: height 100, padding 20, border 5100150150
td holding one p, height185050
div: width 200, padding 20, border 5250250250
table, same CSS200200200
input, same CSS200250250
textarea, same CSS200250250
Table text, body font-size 30px163030
Two 50px images, table width 1px1005050

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.

CSS parsing, selector matching and scroll properties by mode
TestQuirksLimited quirksNo quirks
color: ff0000RedIgnoredIgnored
width: 100100pxIgnoredIgnored
.Foo matches class=fooYesNoNo
#Bar matches id=barYesNoNo
document.scrollingElementbodyhtmlhtml
documentElement.scrollTop0300300
body.scrollTop30000
documentElement.clientHeight5016800800
body.clientHeight80050005000

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.

Dotted pixel art of an orange sun setting behind dark hills, with its reflection in still water.Photo by Rachel Claire

Frames have their own mode

A frame doesn’t inherit its parent’s mode. Every row ran inside an HTML5 page.

document.compatMode for frames and script-created documents
DocumentChromeFirefoxWebKit
srcdoc, no DOCTYPECSS1CompatCSS1CompatCSS1Compat
srcdoc, HTML 3.2 DOCTYPECSS1CompatCSS1CompatCSS1Compat
iframe src, page with no DOCTYPEBackCompatBackCompatBackCompat
Empty iframe (about:blank)BackCompatBackCompatBackCompat
document.write, no DOCTYPEBackCompatBackCompatBackCompat
document.write, with DOCTYPECSS1CompatCSS1CompatCSS1Compat
DOMParser, no DOCTYPEBackCompatBackCompatCSS1Compat
createHTMLDocument()CSS1CompatCSS1CompatCSS1Compat

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

  1. Run document.compatMode in the console on the live page. MDN notes that Firefox also logs a console warning for both quirks modes.
  2. Put <!doctype html> first, and check nothing in the template prints before it.
  3. 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.
  4. Replace documentElement.scrollTop and body.scrollTop logic with window.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

All sources were read on 8 November 2026.