Browsers are forgiving to a fault. When they meet a tag in the wrong place, a missing attribute or a duplicated id, they repair the page and carry on — which is why broken HTML can look perfect and still behave strangely. A validator shows you what the browser is quietly fixing, before it becomes a layout bug or an accessibility problem.
What does a validator actually catch?
It checks the document against the specification, and it reports two kinds of problem. Errors are things that are definitely wrong: an unclosed element, a div inside a p, an attribute that does not exist. Warnings are things that are legal but suspicious, such as a heading that skips a level.
Error: Element p not allowed as child of element ul in this context.
Error: Attribute "onclick" not allowed on element "div" at this point.
Error: Duplicate attribute "class".
Warning: Heading level 3 should not skip level 2.
The first kind is worth fixing immediately. The second is a judgement call, and experienced developers disagree about some of them.
How do I use a validator?
There are three ways, and they suit different situations. The online validator takes a URL or a file and reports every problem with a line number. A command line tool runs over a whole directory, which is what you want for a site. And a build step runs on every commit, which is what stops the errors coming back.
# validate a single file
npx html-validate index.html
# validate every html file in a project
npx html-validate "**/*.html"
# with the W3C validator's own ruleset
npx html-validate --rule "preset:standard" "**/*.html"
For a project that is built from templates, validating the output is better than validating the source, because the output is what a browser will actually receive. Either way, wire it into the build so that a broken page fails the check instead of shipping.
Which errors come up most often?
Four mistakes account for most of them. The first is a block element inside a paragraph: a paragraph cannot contain a heading, a list or a div, and the browser closes the paragraph early, moving your content outside where you put it.
<!-- wrong: the div is not allowed inside a p -->
<p>
Some text
<div>A block inside a paragraph</div>
</p>
<!-- right -->
<p>Some text</p>
<div>A block of its own</div>
The second is a missing closing tag, which the browser repairs by moving the rest of the page inside the element you forgot to close. The third is a duplicate id: identifiers must be unique, and a duplicate breaks every label and every fragment link that points at it. The fourth is a stray </div> with no opening tag, which is usually the sign that a wrapper was closed in the wrong place.
Why do structure errors matter if the page looks fine?
Because the repair is not always cosmetic. A paragraph broken open by a block element can swallow the rest of the content into a heading, which changes the document outline that screen readers navigate by. A duplicate id breaks a label association, so a form field loses its name. A missing closing tag can move a navigation menu inside a footer, which changes what a keyboard user reaches first.
<!-- ids must be unique: the second label points at the first input -->
<label for="email">Email</label>
<input type="email" id="email">
<label for="email">Confirm email</label>
<input type="email" id="email">
None of these show up visually. All of them show up in behaviour. That is the argument for validating: the browser is not telling you about the problem, so you need a tool that will.
What does the browser repair, exactly?
The HTML parser has a defined list of errors it fixes, and knowing it explains a lot of strange behaviour. A missing closing tag does not leave the element open: the parser closes it when it reaches an element that cannot be inside it. A paragraph cannot contain a block, so a block inside a paragraph closes the paragraph first. A <p> is closed by any other block-level start tag, including another paragraph.
<!-- what you wrote -->
<p>First
<p>Second
<!-- what the browser builds -->
<p>First</p>
<p>Second</p>
That last example is the famous one, and the surprising part is that the output is usually what you wanted. The repair rules are good, which is exactly why the bugs are hard to find: the page looks right, and something subtler is wrong.
Which errors should you fix first?
Prioritise by what breaks behaviour rather than by what appears first in the list. An id that appears twice breaks a label. A missing closing tag that swallows a navigation menu changes what a keyboard user reaches first. A duplicate attribute or an invalid attribute value often means the styling or the script was relying on something that never applied. An unclosed tag deep in a long page is usually the cause of something that looked wrong three screens earlier.
fix first duplicate ids, unbalanced wrappers, wrong nesting
fix next invalid attributes, missing alt on meaningful images
judgement heading levels, stylistic warnings
One more check that no validator does: look at the rendered page in the accessibility tree, where the nesting the browser actually built is visible as a tree. An element that appears in an unexpected place is the fingerprint of a structural error that the validator also reported but you had not connected to it.
Quick reference
- Browsers repair broken HTML silently, so the problem shows up in behaviour rather than in layout.
- Validate the built output, not only the source templates.
- Run the validator in the build so broken markup fails the check.
- Common errors: a block inside a paragraph, a missing closing tag, a duplicate id, an unbalanced wrapper.
- Fix every error; treat warnings as a judgement call.
Try it yourself: take a page you have written and run it through a validator. Fix the first error, then the second, and keep going until the list is empty. Notice how many of them you would never have found by looking at the page.