A legacy page renders with subtly wrong element widths, and document.compatMode reports "BackCompat". What has the browser done, what in the HTML caused it, and can you switch it at runtime?
answer
- one line in the console tells you
- the first bytes of the response decide
- two values, three modes
- padding eats the width instead of adding
- parser locks it; script cannot unlock it
basics
~20 s"BackCompat" means the browser parsed the page in quirks mode and is applying legacy layout rules, including the old box model where width includes padding and border. A missing or unrecognised DOCTYPE causes it, and the mode is fixed at parse time.
solid answer
~50 s`document.compatMode` has two values: `"CSS1Compat"` for standards mode and `"BackCompat"` for quirks mode. Quirks mode is the browser deliberately emulating pre-standards behaviour, most visibly the legacy box model in which a declared `width` swallows padding and border rather than adding to them — which is exactly the "subtly wrong widths" symptom. The trigger is the very first thing in the document: no `<!DOCTYPE html>`, a malformed one, or anything emitted before it, such as a stray comment, a BOM-less encoding banner or a server-injected header line. A handful of legacy doctypes land the page in a third, limited-quirks mode, which still reports `"CSS1Compat"`. The mode is decided by the parser and locked for the document's lifetime — you cannot flip it with script, so the fix is to emit a correct `<!DOCTYPE html>` as the first bytes of the response.
code
javascript · 10 lines// run in the misrendering document, not necessarily the top page
console.log(document.compatMode); // "BackCompat" = quirks mode
console.log(document.doctype); // null when no doctype was parsed
console.log(document.doctype && document.doctype.name); // "html" on a modern page
// for an embedded document, ask that document
const frame = document.querySelector('iframe');
if (frame && frame.contentDocument) {
console.log(frame.contentDocument.compatMode);
}go deeper
Know that <!DOCTYPE html> must be the first line of every HTML page and that leaving it out makes the browser lay the page out with old rules. Be able to check document.compatMode in the console.
Explain the mapping from doctype to mode, that "BackCompat" means quirks, and name the concrete effects — the legacy box model in particular — that produce the wrong-width symptom.
Show the diagnostic path: read compatMode in the failing document before touching CSS, trace the missing doctype back to whatever the server or template emitted first, and know that iframes and document.write output each carry their own mode.
Treat it as a delivery-pipeline invariant rather than a page bug — decide where the doctype is guaranteed to be emitted, add a check that catches a quirks-mode response before release, and rule on whether legacy quirks pages get fixed or fenced off.
## What the doctype is actually for `<!DOCTYPE html>` is not a validation instruction and it does not tell the browser which HTML version to use. Its single remaining job is to select a **rendering mode**. It is parsed into a real `DocumentType` node (`nodeType` 10) that you can read as `document.doctype`, whose `name` is `"html"` for a modern page and `null` if there was no doctype at all. ## The three modes | mode | `document.compatMode` | trigger | |---|---|---| | no-quirks (standards) | `"CSS1Compat"` | `<!DOCTYPE html>`, or any document parsed as XML | | limited-quirks ("almost standards") | `"CSS1Compat"` | certain legacy transitional doctypes | | quirks | `"BackCompat"` | missing, malformed, or unrecognised doctype | Note the trap in the second row: `compatMode` cannot distinguish limited-quirks from full standards mode. It is a two-valued property over three modes, so a `"CSS1Compat"` reading is not proof that nothing legacy is in play. ## What quirks mode changes The changes are a compatibility bundle inherited from the 1990s, and the layout-visible ones are what you notice: - **The legacy box model.** A declared `width` is treated as the total border-box width, so padding and border eat into the content rather than adding to the element's size. Every element on a page is a little narrower than the author intended — the classic "subtly wrong widths" report. - **Percentage heights** resolve differently, so a layout relying on a chain of `height: 100%` behaves unlike the standards-mode version. - **Images in table cells** sit on the text baseline, so a row of images gains a few pixels of unexplained gap underneath. This one also applies in limited-quirks mode, which is essentially "standards mode plus the table-cell baseline quirk". - **Assorted parsing and inheritance quirks** around tables, fonts and unitless values. Because it is a bundle, the symptom rarely arrives as one broken thing — it arrives as "the whole page is a bit off, and it looks fine in the staging copy". ## Why a page loses its doctype in practice The doctype must be the first thing in the document. Real-world causes of losing it: - A templating layer or server framework emitting a comment, a blank line with a byte-order mark, or a debug banner before the layout template runs. - A page assembled by `document.write` or an injected `srcdoc` where the fragment was never given its own doctype — **each document gets its own mode**, so an iframe with no doctype is in quirks mode even if the parent page is not. - Content ported from an old CMS whose "HTML 4.01" doctype string was truncated or mangled. - An HTML email or export template hand-edited into a web page. ## Diagnosing and fixing Diagnosis is one line in the console: ```js console.log(document.compatMode); // "BackCompat" ⇒ quirks console.log(document.doctype); // null ⇒ no doctype at all ``` Do this **inside the frame that is misrendering**, not the top page — `iframeEl.contentDocument.compatMode` for an embedded document. The fix is always the same: emit `<!DOCTYPE html>` as the literal first bytes of the response, before any whitespace or comment, and give every iframe document its own. What you cannot do is fix it from script. The mode is chosen by the parser as the document is constructed and is immutable afterwards. Inserting a `DocumentType` node later, or setting `document.doctype`, does not re-run layout under different rules. Neither does a `<meta>` tag, a CSS reset, or a framework. A page that boots in quirks mode stays there until it is reloaded from markup that has the doctype. A partial mitigation, if you truly cannot change the first bytes, is to set `box-sizing: border-box` on everything so the box model at least matches quirks behaviour intentionally — but the other quirks remain, so treat it as a stopgap, not a fix. ## Why this is still asked Not because anyone writes quirks-mode pages on purpose, but because it is a good test of whether a candidate can reason about a whole-page symptom instead of chasing individual CSS rules. The senior answer is: check `compatMode` first, understand that the cause is upstream in the response bytes rather than in the stylesheet, and know that no amount of client-side code can undo it.
- Can you switch a page out of quirks mode after it has loaded?No. The mode is decided by the HTML parser while the document is being constructed and is fixed for that document's lifetime. Inserting a `DocumentType` node afterwards, adding a meta tag, or loading a CSS reset changes nothing. The only fix is to serve markup whose first bytes are `<!DOCTYPE html>` and reload.
- Does document.compatMode returning "CSS1Compat" guarantee full standards mode?No. There are three modes but only two values: limited-quirks mode — triggered by certain legacy transitional doctypes — also reports `"CSS1Compat"`. It differs from full standards mode mainly in the table-cell baseline quirk that leaves a gap under images. To be sure, inspect `document.doctype` itself rather than trusting `compatMode` alone.
- If the main page has a correct doctype, can an iframe inside it still be in quirks mode?Yes. Rendering mode is per document, not per browsing context tree. An iframe whose source, `srcdoc`, or `document.write`-generated content lacks a doctype is parsed in quirks mode independently of the parent. Check the frame's own `contentDocument.compatMode` when an embedded widget lays out wrongly.
saying these in an interview costs you the question
- Thinks the doctype selects an HTML version to validate against
- Says quirks mode can be turned off with JavaScript at runtime
- Assumes CSS1Compat rules out every legacy mode
- Believes the parent page's doctype applies to its iframes
- Blames the stylesheet rather than checking compatMode first