|$ curl https://forge-ai.dev/api/markdown?path=docs/html/spec
$cat docs/html-spec-&-doctype.md
updated This week·25 min read·published

HTML Spec & DOCTYPE

HTMLSpecificationReferenceBeginner
Introduction

The HTML specification defines the rules, elements, attributes, and behaviors that make up the web's core language. Understanding the specification history, doctype evolution, and the differences between standards bodies is essential for writing valid, forward-compatible HTML.

The doctype declaration is the first thing in every HTML document. It tells the browser which version of HTML to expect and triggers the correct rendering mode. Despite its importance, many developers treat it as a magic incantation without understanding what it does.

info

The HTML Living Standard is now the single source of truth for HTML. It is maintained by the WHATWG and continuously updated. There are no version numbers — the standard is whatever the latest browsers implement. Always check html.spec.whatwg.org for the authoritative reference.
HTML Specification History

HTML has evolved through several major versions since its creation by Tim Berners-Lee in 1991. Each version introduced new elements, attributes, and capabilities while removing deprecated features.

VersionYearKey FeaturesStatus
HTML 2.01995First standardized version. Forms, tables (basic), images with alt textHistoric
HTML 3.21997Tables, applets, text flow around images, superscript/subscriptHistoric
HTML 4.011999Separation of structure and presentation (CSS), internationalization, accessibilityLegacy
XHTML 1.02000HTML reformulated as XML. Stricter parsing rules, lowercase tags, required closingLegacy
XHTML 1.12001Modular XHTML. Removed presentation elements entirelyLegacy
HTML52014Semantic elements (<header>, <nav>, <section>), multimedia (<video>, <audio>), canvas, form types, APIsCurrent
HTML Living StandardOngoingContinuously updated. No version numbers. WHATWG maintains. W3C adopted in 2019Active

The transition from HTML4 to HTML5 was a major shift. HTML4 was based on SGML (Standard Generalized Markup Language), which required complex doctype declarations. HTML5 simplified the doctype to its current minimal form and abandoned SGML compatibility.

📝

note

XHTML was an attempt to move the web toward XML strictness. It failed in practice because browsers had to support invalid HTML for backwards compatibility, making XHTML served as text/html behave identically to regular HTML. Only XHTML served with an XML content type (application/xhtml+xml) enforces strict parsing, but this causes older browsers to show a download dialog.
DOCTYPE Evolution

The doctype declaration has evolved from verbose SGML declarations to the simple <!DOCTYPE html> used today. Each variation tells the browser how to interpret the document and which rendering mode to use.

doctype-evolution.html
HTML
1<!-- HTML5 (modern, always use this) -->
2<!DOCTYPE html>
3
4<!-- HTML 4.01 Strict -->
5<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
6 "http://www.w3.org/TR/html4/strict.dtd">
7
8<!-- HTML 4.01 Transitional (includes presentational elements) -->
9<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
10 "http://www.w3.org/TR/html4/loose.dtd">
11
12<!-- HTML 4.01 Frameset (for frameset documents) -->
13<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
14 "http://www.w3.org/TR/html4/frameset.dtd">
15
16<!-- XHTML 1.0 Strict -->
17<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
18 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
19
20<!-- XHTML 1.0 Transitional -->
21<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
22 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
23
24<!-- XHTML 1.0 Frameset -->
25<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
26 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
27
28<!-- XHTML 1.1 -->
29<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
30 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
31
32<!-- Legacy doctypes (triggers almost-standards mode in some browsers) -->
33<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
34<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

best practice

Always use the HTML5 doctype <!DOCTYPE html>. It is the shortest, most forward-compatible declaration. It triggers standards mode in every modern browser, including Internet Explorer 6 and above. There is never a reason to use older doctypes in new projects.
Quirks Mode vs Standards Mode

Browsers use three rendering modes depending on the doctype (or lack thereof). Understanding these modes is critical because they dramatically affect how CSS is applied and how elements are rendered.

ModeTriggerBehavior
Standards ModeHTML5 doctype, HTML4 Strict, XHTML doctypesFull standards-compliance. CSS box model per spec, consistent layout behavior
Quirks ModeNo doctype, or old/unrecognized doctypeEmulates IE5 box model, non-standard sizing, buggy behavior. Avoid at all costs
Almost Standards ModeHTML4 Transitional with URI, HTML4 FramesetMostly standards-compliant but with minor quirks in table cell sizing

The most visible difference between quirks mode and standards mode is the box model. In quirks mode, the CSS width property includes padding and borders (the IE5 box model). In standards mode, width applies only to the content area.

quirks-vs-standards.html
HTML
1<!-- Triggers standards mode in all browsers -->
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="UTF-8">
6 <title>Standards Mode</title>
7 <style>
8 .box {
9 width: 200px;
10 padding: 20px;
11 border: 5px solid black;
12 /* In standards mode: total width = 200 + 40 + 10 = 250px */
13 /* In quirks mode: content width = 200 - 40 - 10 = 150px */
14 }
15 </style>
16</head>
17<body>
18 <div class="box">Standards Mode</div>
19</body>
20</html>
21
22<!-- No doctype → triggers quirks mode -->
23<html>
24<head>
25 <title>Quirks Mode</title>
26 <!-- Same CSS behaves differently -->
27</head>
28<body>
29 <div class="box">Quirks Mode</div>
30</body>
31</html>

warning

Never omit the doctype. Pages without a doctype render in quirks mode, which causes inconsistent box models, broken layouts, and unexpected behavior across browsers. Always put <!DOCTYPE html> as the very first line of your HTML document — before any whitespace or comments.

You can check which mode a browser is using from the JavaScript console:

check-mode.js
JavaScript
1// Check rendering mode
2console.log(document.compatMode);
3// "CSS1Compat" → Standards mode
4// "BackCompat" → Quirks mode
Validators

The W3C Markup Validation Service is the official tool for checking HTML documents against the specification. Validating your HTML catches structural errors, deprecated elements, and accessibility issues before they reach users.

W3C Validatorhttps://validator.w3.org — validates by URL, file upload, or direct input
Nu HTML Checker — The engine behind the W3C validator. Available as a command-line tool
Lighthouse — Includes best-practice audits for HTML validity and accessibility
HTML-validate — Offline HTML validator available as an npm package for CI integration
validators.html
Bash
1# Validate from command line with vnu.jar
2java -jar vnu.jar index.html
3
4# Validate with HTML-validate (npm)
5npx html-validate src/**/*.html
6
7# Validate with W3C validator API
8curl -H "Content-Type: text/html; charset=utf-8" \
9 --data-binary @index.html \
10 https://validator.w3.org/nu/?out=json
11
12# Integrate into CI pipeline
13# .github/workflows/validate.yml
14name: HTML Validate
15on: [push]
16jobs:
17 validate:
18 runs-on: ubuntu-latest
19 steps:
20 - uses: actions/checkout@v4
21 - run: npx html-validate "src/**/*.html"
🔥

pro tip

Run the W3C validator as part of your CI pipeline. It catches issues that linters miss, such as improperly nested elements, missing required attributes, and deprecated features. A valid HTML document is the foundation of consistent cross-browser behavior and proper accessibility support.
WHATWG vs W3C

The Web Hypertext Application Technology Working Group (WHATWG) was formed in 2004 by Apple, Mozilla, and Opera in response to the W3C's decision to abandon HTML in favor of XHTML. The WHATWG developed what would become HTML5, and since 2019, the W3C has officially adopted the WHATWG Living Standard as the sole source of truth for HTML.

CharacteristicWHATWGW3C
ModelLiving Standard (continuously updated)Versioned snapshots (historically)
URLhtml.spec.whatwg.orgw3.org/TR/html
StatusActive, authoritative standardAdopted WHATWG Living Standard in 2019
VersioningNo version numbersVersioned (HTML 4.01, HTML5, HTML 5.1, 5.2, 5.3)
ProcessConsensus-driven, browser vendorsMember organization, formal recommendations

In practice, the two organizations now agree: the HTML Living Standard is the specification that browser vendors implement. The W3C's role is to publish review drafts and coordinate with other web standards (CSS, SVG, ARIA). For developers, html.spec.whatwg.org is the definitive reference.

📝

note

The W3C published HTML 5.1 in 2016 and HTML 5.2 in 2017, but these versioned snapshots became obsolete when the W3C adopted the Living Standard. Previous W3C HTML versions (5.1, 5.2, 5.3) are now historical documents. Always reference the WHATWG Living Standard for the current specification.
Browser Implementation Notes

While the HTML specification defines how documents should be parsed and rendered, browser implementations have historically differed. Modern browsers converge on the standard, but edge cases still exist. Understanding parser behavior helps you write HTML that works consistently.

Error handling — HTML parsers are designed to handle invalid markup gracefully. Browsers infer closing tags, repair misnested elements, and ignore unrecognized tags. This forgiving behavior is a feature, not a bug — but don't rely on it.
Parser recovery — Different browsers may recover from parse errors differently. Edge cases like <table> inside <p> or unclosed <form> tags can produce unexpected DOM trees.
Scripting — The <script> element blocks DOM parsing by default, but async and defer alter this behavior. The parser handles document.write() during parsing but not after.
Self-closing tags — Void elements like <br>, <hr>, <img>, and <input> must not have a closing tag. The trailing slash (<br />) is allowed in HTML5 but ignored.
Raw text elements<script> and <style> are raw text elements. Their content is not parsed as HTML until the closing tag is found. This means </script> inside a string literal will prematurely close the element.
parser-behavior.html
HTML
1<!-- Parser behavior examples -->
2
3<!-- Implicit tag closure (browser infers </p>) -->
4<p>Paragraph 1
5<p>Paragraph 2
6<!-- Parsed as: <p>Paragraph 1</p><p>Paragraph 2</p> -->
7
8<!-- Misnested tags (browser reconciles) -->
9<b><i>Bold and italic</b></i>
10<!-- Parsed as: <b><i>Bold and italic</i></b><i></i> -->
11
12<!-- Table inside paragraph (paragraph auto-closes) -->
13<p>Text before <table><tr><td>Cell</td></tr></table></p>
14<!-- Parsed as: <p>Text before</p><table>...</table><p></p> -->
15
16<!-- Script with </script> in content (breaks) -->
17<script>
18 var x = "</script>"; // Syntax error! Closes the script tag
19</script>
20<!-- Fix: escape the slash -->
21<script>
22 var x = "</script>";
23</script>
24
25<!-- Void elements don't need closing -->
26<br>
27<br />
28<img src="photo.jpg" alt="Photo">
29<img src="photo.jpg" alt="Photo" />
30
31<!-- Foreign content (SVG, MathML) maintains namespace -->
32<svg viewBox="0 0 100 100">
33 <circle cx="50" cy="50" r="40" />
34</svg>
35
36<!-- Custom elements must have a hyphen -->
37<my-component></my-component>
38<my-element></my-element>

best practice

Do not rely on the browser's error recovery for production code. Write valid HTML that passes the W3C validator. The forgiving parser is meant for backward compatibility with legacy content, not as a feature to exploit. Valid HTML renders consistently across all browsers.
Deprecated Elements

Several HTML elements have been deprecated or obsolete across different versions of the specification. These elements should not be used in new code and should be replaced with modern CSS equivalents.

ElementStatusReplacement
<center>ObsoleteCSS text-align: center or margin: 0 auto
<font>ObsoleteCSS font-family, font-size, color
<marquee>ObsoleteCSS animations (prefers-reduced-motion)
<frame>Obsolete<iframe> or CSS layout (Flexbox, Grid)
<frameset>ObsoleteCSS Grid or Flexbox
<noframes>ObsoleteFallback content in <iframe>
<big>ObsoleteCSS font-size: larger
<strike>Obsolete<s>, <del>, or CSS text-decoration: line-through
<tt>Obsolete<code>, <kbd>, <samp>, <pre>, or CSS font-family: monospace
<acronym>Obsolete<abbr>
<applet>Obsolete<object>, <embed>, or modern JavaScript
<bgsound>Obsolete<audio> with autoplay
deprecated.html
HTML
1<!-- Deprecated — don't use these -->
2<center>Centered text</center>
3<font color="red" size="4">Red text</font>
4<marquee behavior="scroll">Scrolling text</marquee>
5<big>Big text</big>
6<strike>Strikethrough text</strike>
7<tt>Monospace text</tt>
8<acronym title="HyperText Markup Language">HTML</acronym>
9
10<!-- Modern equivalents -->
11<p style="text-align: center;">Centered text</p>
12<span style="color: red; font-size: 1.25rem;">Red text</span>
13<p style="font-size: larger;">Big text</p>
14<s>Strikethrough text</s>
15<code>Monospace text</code>
16<abbr title="HyperText Markup Language">HTML</abbr>
17
18<!-- Frames (obsolete — replaced by iframes and CSS) -->
19<!-- Instead of <frameset>, use: -->
20<iframe src="navigation.html" title="Navigation"></iframe>
21<iframe src="content.html" title="Content"></iframe>
22
23<!-- Marquee replacement with CSS -->
24<style>
25 .scroll-text {
26 animation: scroll 10s linear infinite;
27 }
28 @media (prefers-reduced-motion: reduce) {
29 .scroll-text {
30 animation: none;
31 }
32 }
33 @keyframes scroll {
34 from { transform: translateX(100%); }
35 to { transform: translateX(-100%); }
36 }
37</style>
38<div class="scroll-text">Scrolling text (accessible)</div>

warning

Browsers still render deprecated elements for backward compatibility, but they may stop working in future versions. The W3C validator flags all deprecated elements as errors. Never use <center>, <font>, or <frame> in new projects — they are completely replaced by CSS.
HTML Living Standard

The HTML Living Standard is the modern approach to web standards. Instead of releasing versioned specifications every few years, the WHATWG maintains a continuously updated standard that reflects the latest browser implementations and web developer needs.

No version numbers — There is no HTML6 or HTML5.2. The standard is simply "HTML" and it evolves continuously.
Feature maturity — Features move through stages: proposal, implementation in browsers, stabilization, and finally inclusion in the standard. The standard documents what browsers actually do.
Browser-driven — New features are typically implemented in browsers first, then standardized. The standard catches up to implementation, rather than the other way around.
Backward compatibility — The Living Standard maintains full backward compatibility. No existing HTML document breaks when the standard is updated. Old features are marked as obsolete but continue to work.
Cross-references — The HTML standard integrates with related specifications (DOM, Fetch, URL, Web IDL) to provide a complete picture of the web platform.
living-standard.html
HTML
1<!-- Recent additions to the HTML Living Standard -->
2
3<!-- Lazy loading (added 2019) -->
4<img src="photo.jpg" loading="lazy" alt="Photo">
5
6<!-- Decoding hint (added 2019) -->
7<img src="photo.jpg" decoding="async" alt="Photo">
8
9<!-- Fetch priority (added 2022) -->
10<img src="hero.jpg" fetchpriority="high" alt="Hero">
11
12<!-- Invoker commands (proposed) -->
13<button command="show-modal" commandfor="myDialog">Open</button>
14<dialog id="myDialog">
15 <p>Modal content</p>
16 <button command="close" commandfor="myDialog">Close</button>
17</dialog>
18
19<!-- Popover API (added 2024) -->
20<button popovertarget="my-popover">Toggle Popover</button>
21<div id="my-popover" popover>
22 <p>Popover content</p>
23</div>
24
25<!-- Declarative Shadow DOM (added 2023) -->
26<template shadowrootmode="open">
27 <style>
28 :host { display: block; color: #00FF41; }
29 </style>
30 <p>Shadow DOM content</p>
31</template>
32
33<!-- Search element (added 2023) -->
34<search>
35 <form action="/search">
36 <input type="search" name="q">
37 <button type="submit">Search</button>
38 </form>
39</search>
🔥

pro tip

Follow the @whatwg GitHub repository and the html.spec.whatwg.org/multipage/ page for the latest additions. The Living Standard is updated whenever a feature stabilizes across browsers. Features like popover, <search>, and Declarative Shadow DOM are recent additions.
Best Practices
Always start with <!DOCTYPE html> to trigger standards mode in all browsers
Use valid HTML that passes the W3C validator — this ensures consistent cross-browser behavior
Reference html.spec.whatwg.org as the authoritative HTML specification
Avoid deprecated elements (center, font, marquee, frame, frameset) — use CSS equivalents
Use lowercase for tag names and attribute names for consistency and readability
Always quote attribute values with double quotes for consistency
Include the lang attribute on the <html> element for accessibility and translation
Write HTML that handles parser behavior gracefully — close all tags properly
Validate HTML in CI with tools like html-validate or vnu.jar to catch errors early
Stay informed about new Living Standard additions (popover, search, declarative shadow DOM)
Use semantic elements (header, nav, main, article, section, footer) for document structure
Test your HTML in multiple browsers — the standard describes ideal behavior, but implementations vary
$Blueprint — Engineering Documentation·Section ID: HTML-39·Revision: 1.0