HTML Standards and Best Practices

Article · 6:00

What to do when the course is over: validate, check support, write markup the next person can read, and build in the order that survives one piece failing to arrive.

This lesson has 3 runnable examples. Press Try yourself! under any of them to open it in the editor.

HTML Standards and Best Practices

Thirty topics of specifics. This one is the habits that keep them true on a real project.

Validate

HTML Example 1 12 lines
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>A page that validates</title>
  </head>
  <body>
    <h1>Nothing here is ambiguous</h1>
    <p>Every element is closed, every attribute quoted, every id unique.</p>
  </body>
</html>

Open this example in the editor and change it. Nothing you type is saved.

A validator reads your markup the way the specification says to, and reports what it finds. It catches the things a browser silently repairs: unclosed elements, duplicate ids, invalid nesting, attributes on elements that do not take them, missing required attributes.

Those are exactly the bugs that are hardest to find by looking, because the page renders.

What validation does not prove: that the page is accessible, that the elements are the right ones, that it is secure or usable. A page of div elements with correct syntax validates perfectly. Validation is a floor.

Check support, then degrade

Features arrive at different times in different browsers. The question is never "is this in the specification" but "what happens in the browsers my readers use".

HTML Example 2 13 lines
<details>
  <summary>Works everywhere</summary>
  <p>Supported for years.</p>
</details>

<div popover id="newer">
  <p>Newer. In an older browser this is simply visible.</p>
</div>

<picture>
  <source srcset="diagram.avif" type="image/avif">
  <img src="diagram.png" alt="How the parser builds a tree" width="800" height="400">
</picture>

Open this example in the editor and change it. Nothing you type is saved.

Notice that two of those degrade by themselves. picture falls back to the img. An unknown attribute is ignored. Markup tends to fail softly, which is its great advantage over script - the popover case is the exception worth testing, because an unsupported popover is not hidden, it is just shown.

The pattern to follow is progressive enhancement: build the version that works with plain HTML, then add the version that feels better. In that order, because the first one is what runs when the second fails to arrive - and scripts fail to arrive more often than anyone expects.

Markup the next person can read

HTML Example 3 9 lines
<article class="course-card">
  <h3 class="course-card__title">
    <a href="/courses/html">HTML: From Basics to Expert</a>
  </h3>
  <p class="course-card__summary">Thirty topics, every example runnable.</p>
  <footer class="course-card__meta">
    <time datetime="2026-03-14">Updated 14 March 2026</time>
  </footer>
</article>

Open this example in the editor and change it. Nothing you type is saved.

A short list, all of it boring and all of it worth doing:

  • Lowercase tag and attribute names. Consistency makes search and replace work.
  • Quote every attribute value.
  • Close every non-void element.
  • Indent to show nesting, and keep lines short enough to read.
  • One idea per element. An element doing three jobs is three elements.
  • Name classes after what the thing is.
  • Comment the surprising, not the obvious. <!-- the empty cell is deliberate, see the headers below --> earns its place; <!-- the header --> above a header does not.

The test for all of it: open the file in six months and see how long it takes to find the thing you want to change.

Do not divide what is already joined

Three habits that follow from the whole course, stated once:

Choose the element before the class. A button is focusable, keyboard-operable and announced; a styled div is none of those and takes four attributes to catch up.

Let the markup carry state. aria-expanded, aria-current, open, required, disabled, aria-invalid. Each is already true and already announced; a parallel class is a second copy that will drift.

Keep the reading order right. CSS can move anything; the keyboard and the screen reader follow the document. Write the order the content matters, then place it.

Reading a validator message

Validator output reads like a compiler's until you have seen each kind once.

"End tag li implied" - something was left open and the parser closed it for you. Usually a missing </li>, and the real mistake is often several lines earlier.

"Element div not allowed as child of element ul" - a content-model violation. Only li may be a child of ul; the parser will move the div out.

"Duplicate ID" - almost always copied markup. The symptom is a label pointing at the wrong field, or a fragment link scrolling to the wrong place.

"Attribute X not allowed on element Y" - either a typo or an attribute borrowed from a different element.

"Element h1 is missing required instance of child element" - some elements have required content, and an empty one is a mistake rather than a placeholder.

The one piece of advice that saves the most time: fix the first error and re-run. A single unclosed tag produces a cascade of errors underneath it, and most of them vanish when the first one is fixed.

A review checklist

Before shipping any page:

  1. Doctype, lang, charset, viewport, unique title.
  2. One h1, no skipped heading levels.
  3. Every image has alt - informative, functional or empty.
  4. Every form control has a real label; groups have a fieldset and legend.
  5. Every link's text makes sense read on its own.
  6. Tables have a caption and scope on every header cell.
  7. Landmarks present: header, nav, main, footer, and a skip link.
  8. width and height on images; loading="lazy" below the fold.
  9. Scripts deferred; nothing blocking in the head that need not be.
  10. Keyboard: everything reachable, focus visible, nothing trapped.
  11. Validator clean.
  12. It still makes sense with CSS off and with JavaScript off.

The living standard

HTML is not versioned any more. There is no HTML6 coming; the specification is amended continuously, which has two practical consequences.

"Is it HTML5?" is the wrong question. The right one is whether the browsers your readers use support it, which is a support table rather than a specification.

Nothing is removed abruptly. Elements are marked obsolete, browsers keep rendering them, and the cost of using one is not that it breaks but that it puts presentation back in the markup. font, center, frameset, marquee all still work and are all still mistakes.

The corollary is that markup you write correctly today keeps working. HTML's compatibility record is the best of any web technology, and that is worth something when choosing between a platform feature and a library.

Where to look things up

The specification - the WHATWG HTML Standard - is the authority, and it is written for implementers. MDN is the reference most working developers actually use and is a better first stop. For "can I use this yet", a browser-support table beats both, because the specification describes what should exist and the table describes what does.

One habit worth more than any of them: when something behaves strangely, look at the Elements panel. The difference between what you wrote and what the browser built explains a surprising share of all HTML bugs, and nothing else shows it to you.

Practice task

Run a page you have built through the W3C validator and fix everything it reports. Then go through the twelve-point checklist above. Keep the list; it is the same list for every page you will ever write, and the fourth time through it takes about ten minutes.