HTML Parsing & Quirks Mode
Understand how browsers parse HTML, why quirks mode exists, the error-recovery algorithm, and how malformed HTML is handled.
Overview
Key Points
- •`<!DOCTYPE html>` triggers standards mode; missing or incorrect DOCTYPE triggers quirks mode
- •Browsers use a defined error-recovery algorithm invalid HTML renders predictably, not randomly
- •The HTML parsing algorithm has ~70 insertion modes (before html, in head, in body, etc.)
- •Self-closing syntax `<br/>` is ignored for HTML elements browsers only use it for void elements anyway
- •Unclosed tags: `<p>`, `<li>`, `<td>` etc. are implicitly closed by the parser when a sibling or parent is opened
- •Script blocking: parser halts when a `<script>` tag is encountered until the script executes
- •`document.readyState` transitions: "loading" → "interactive" → "complete" track parse progress
Examples
Standards mode vs. quirks mode
<!-- ✅ STANDARDS MODE correct DOCTYPE triggers modern rendering -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Standards Mode Page</title>
</head>
<body>
<p>Rendered in standards mode.</p>
</body>
</html>
<!-- ❌ QUIRKS MODE no DOCTYPE triggers legacy IE5 rendering emulation -->
<html>
<head><title>Quirks Mode Page</title></head>
<body>
<p>May render differently across browsers due to quirks mode.</p>
</body>
</html>
<!--
In quirks mode, browsers emulate old IE5 box model behavior:
- box-sizing defaults to border-box (not content-box)
- Some CSS percentages are calculated differently
- Table cells ignore explicit heights in some ways
- CSS colors may be parsed differently
Always use <!DOCTYPE html> to ensure consistent behavior.
-->Always use <!DOCTYPE html>. The parser ignores case <!doctype html> also works.
HTML error recovery in action
<!-- Parser error recovery: these all render identically -->
<!-- Unclosed <p> tag parser auto-closes it -->
<p>First paragraph
<p>Second paragraph
<!-- becomes: -->
<p>First paragraph</p>
<p>Second paragraph</p>
<!-- Misplaced table content parser moves it above the table -->
<table>
<p>This text doesn't belong in a table</p>
<tr><td>Cell</td></tr>
</table>
<!-- becomes: -->
<p>This text doesn't belong in a table</p>
<table>
<tr><td>Cell</td></tr>
</table>
<!-- Nested inline in block parser forces closure -->
<p><b>Bold <p>New paragraph</p></b>
<!-- becomes: -->
<p><b>Bold</b></p>
<p><b>New paragraph</b></p>The HTML5 spec defines every error recovery case results are consistent across Chrome, Firefox, and Safari.
Script blocking and DOMContentLoaded
<!DOCTYPE html>
<html>
<head>
<!-- Parser blocks here until external CSS loads (render-blocking) -->
<link rel="stylesheet" href="/styles.css">
<!-- Parser blocks here until script.js downloads AND executes -->
<script src="/script.js"></script>
<!-- async: downloads in parallel, executes when ready (non-blocking parse) -->
<script src="/analytics.js" async></script>
<!-- defer: downloads in parallel, executes AFTER HTML is fully parsed -->
<script src="/app.js" defer></script>
</head>
<body>
<!-- ... HTML content ... -->
</body>
</html>
<script>
// DOMContentLoaded fires when HTML is fully parsed (defer scripts run first)
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM ready document.readyState:', document.readyState);
// 'interactive'
});
// window.load fires after ALL resources (images, stylesheets) load
window.addEventListener('load', () => {
console.log('Fully loaded document.readyState:', document.readyState);
// 'complete'
});
</script>Prefer defer over async for scripts that need the DOM defer scripts run in document order after parsing.
Common Mistakes
- Omitting `<!DOCTYPE html>` and accidentally triggering quirks mode always start every HTML document with it
- Relying on browser error recovery for intentional behavior malformed HTML may render consistently now but different browsers may handle edge cases differently
- Using `document.write()` after the page has loaded calling it post-parse triggers a full document re-parse (destroying the current DOM)
Note
Validate your HTML with the W3C Markup Validation Service (validator.w3.org). Valid HTML parses faster (no error recovery needed), is more accessible, and is future-proof as browsers change their error handling.
Exercises
Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4