Difficulty: Advanced
The DOCTYPE declaration is a required preamble in HTML documents that tells the browser which version and rules of HTML the document follows. In HTML5, the declaration is simply <!DOCTYPE html>. This seemingly simple line has a profound effect on how the browser renders your page because it determines the rendering mode. There are three rendering modes: quirks mode, almost standards mode (also called limited-quirks mode), and full standards mode. Understanding these modes and their differences is a classic interview question.
Quirks mode is triggered when the DOCTYPE is missing, malformed, or uses an old DOCTYPE that historically triggered quirks behavior. In quirks mode, the browser emulates the non-standard rendering behavior of Internet Explorer 5 and Netscape Navigator 4 from the late 1990s. The most significant difference is the box model: in quirks mode, width and height include padding and border (like CSS box-sizing: border-box), whereas in standards mode they do not (box-sizing: content-box by default). Other quirks include different table cell sizing, different treatment of inline element alignment, and the ability for body to inherit certain properties to the viewport.
Almost standards mode (limited-quirks mode) is triggered by certain transitional DOCTYPEs like <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">. This mode renders almost identically to full standards mode with one key exception: the handling of line-height and vertical sizing of table cells containing only images. In almost standards mode, table cells with only an image do not add extra space below the image, matching the behavior web developers expected during the HTML 4 era. In full standards mode, the image sits on the text baseline, leaving a small gap below it.
Full standards mode is triggered by the HTML5 DOCTYPE (<!DOCTYPE html>) and by strict HTML 4.01 and XHTML 1.0 DOCTYPEs with a system identifier. In this mode, the browser follows the CSS and HTML specifications precisely. The box model uses content-box sizing by default, inline elements are rendered according to the CSS inline formatting context, and all modern CSS features work as specified. This is the mode you should always use for new projects.
You can detect the current rendering mode with JavaScript using document.compatMode, which returns 'CSS1Compat' for standards mode (and almost standards mode) or 'BackCompat' for quirks mode. In practice, the main concern is avoiding quirks mode, which can cause significant rendering differences. If you inherit a legacy project in quirks mode, adding <!DOCTYPE html> as the first line will switch to standards mode, but this may break layouts that were built to depend on quirks mode box model behavior. The safest migration strategy is to add the DOCTYPE and simultaneously add box-sizing: border-box to the affected elements.
<!-- HTML5: triggers FULL STANDARDS mode -->
<!DOCTYPE html>
<!-- HTML 4.01 Strict with URL: triggers FULL STANDARDS mode -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- HTML 4.01 Transitional with URL: triggers ALMOST STANDARDS mode -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<!-- HTML 4.01 Transitional WITHOUT URL: triggers QUIRKS mode -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- No DOCTYPE at all: triggers QUIRKS mode -->
<html>
<head><title>Quirks!</title></head>
<body></body>
</html>
<!-- XHTML 1.0 Strict: triggers FULL STANDARDS mode -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- Best practice: Always use the HTML5 DOCTYPE -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Standards Mode</title>
</head>
<body></body>
</html>
The HTML5 DOCTYPE is the simplest and most reliable way to trigger standards mode. Old HTML 4 DOCTYPEs trigger different modes depending on whether a system identifier URL is present. Missing or malformed DOCTYPEs always trigger quirks mode.
<!-- In STANDARDS mode (with DOCTYPE html): -->
<style>
.box-standards {
width: 200px;
padding: 20px;
border: 5px solid black;
/* Total width = 200 + 20*2 + 5*2 = 250px */
/* width only covers content area */
}
</style>
<div class="box-standards">Standards: 250px total</div>
<!-- In QUIRKS mode (without DOCTYPE): -->
<!--
.box-quirks {
width: 200px;
padding: 20px;
border: 5px solid black;
Total width = 200px (padding and border included!)
Content area = 200 - 20*2 - 5*2 = 150px
}
-->
<!-- Modern CSS equivalent of quirks box model: -->
<style>
/* This mimics quirks mode box model in standards mode */
.border-box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 5px solid black;
/* Total width = 200px (same as quirks!) */
/* Content area = 150px */
}
/* Common reset to use border-box globally */
*,
*::before,
*::after {
box-sizing: border-box;
}
</style>
The biggest quirks mode difference is the box model. In standards mode, width is content-only by default. In quirks mode, width includes padding and border. Modern CSS solves this with box-sizing: border-box, which gives the intuitive behavior of quirks mode within a standards-mode document.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rendering Mode Detection</title>
</head>
<body>
<h1>Rendering Mode Detector</h1>
<div id="result"></div>
<script>
// document.compatMode returns:
// 'CSS1Compat' = standards mode (or almost standards)
// 'BackCompat' = quirks mode
const mode = document.compatMode;
const resultEl = document.getElementById('result');
if (mode === 'CSS1Compat') {
resultEl.textContent = 'Standards Mode (CSS1Compat)';
resultEl.style.color = 'green';
} else {
resultEl.textContent = 'Quirks Mode (BackCompat) - Fix your DOCTYPE!';
resultEl.style.color = 'red';
}
console.log('document.compatMode:', mode);
// Additional detection info
console.log('DOCTYPE name:', document.doctype?.name); // 'html'
console.log('DOCTYPE publicId:', document.doctype?.publicId); // ''
console.log('DOCTYPE systemId:', document.doctype?.systemId); // ''
// Full standards vs almost standards cannot be distinguished
// via JavaScript -- both report CSS1Compat
</script>
</body>
</html>
document.compatMode is the standard way to detect rendering mode. Both full standards and almost standards mode return 'CSS1Compat'. Only quirks mode returns 'BackCompat'. The document.doctype property provides details about the DOCTYPE declaration itself.
<!-- BEFORE: Legacy page in quirks mode -->
<html>
<head>
<style>
.sidebar { width: 250px; padding: 15px; border: 1px solid #ccc; }
.content { width: 750px; padding: 20px; }
/* In quirks mode: sidebar total = 250px, content total = 750px */
/* In standards mode: sidebar total = 282px, content total = 790px -- BROKEN! */
</style>
</head>
<body>
<div class="sidebar">Sidebar</div>
<div class="content">Content</div>
</body>
</html>
<!-- AFTER: Migrated to standards mode -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
/* Reset box model to match quirks behavior */
*, *::before, *::after {
box-sizing: border-box;
}
.sidebar { width: 250px; padding: 15px; border: 1px solid #ccc; }
.content { width: 750px; padding: 20px; }
/* Now: sidebar total = 250px, content total = 750px -- same as before! */
</style>
</head>
<body>
<div class="sidebar">Sidebar</div>
<div class="content">Content</div>
</body>
</html>
When migrating from quirks to standards mode, the box model change is the primary concern. Adding box-sizing: border-box globally makes width/height include padding and border, matching quirks mode behavior. This is the safest migration strategy and is also considered a modern best practice.
DOCTYPE, Quirks Mode, Standards Mode, Almost Standards Mode, document.compatMode, Browser Rendering