LearnThatStack Ace your next interview

HTML5

HTML Living Standard in current browsers Checked Oct 2026 142 code snippets

The model

  • Pick each element for what the content is. CSS sets the look, and its display property decides block or inline.
  • The browser parses HTML top to bottom into the DOM. A plain <script> stops the parser, and CSS holds back the first paint.
  • Screen readers read the accessibility tree the browser builds from the DOM. A <button> comes with a role, a name and keyboard support. A <div> has none.
  • ARIA changes only what assistive technology announces, never behavior. Use a native element first.
  • HTML is now the WHATWG's Living Standard, with no version number. <!DOCTYPE html> only keeps the browser out of quirks mode.
Networkserver and cacheDOMbuilt by the parserScreenCSSOM, layout, paintAccessibility treerole, name, stateLOADHTML parsed in orderfetch CSS, JS, images<script> stops parserCSS blocks paintBUILDrender DOM + CSSOMroles from elements
A plain script stops the parser until it has run, and CSS holds back the first paint. Screen readers read the accessibility tree, not the screen.

Document & elements

the page skeleton and how tags behave

Fit the page to a phone

Lay the page out at the screen's width<meta name="viewport" content="width=device-width, initial-scale=1">

TrapWithout it, a phone lays the page out in a wide viewport, often 980px, and shrinks it. Never set user-scalable=no.

id, class, data and editable text

Name one unique element, or label manyid="header"class="card featured"
Store data on an element and read itdata-user-id="123"el.dataset.userId
Let users edit an element in placecontenteditable="true"contenteditable="plaintext-only"

TipStyle with classes. An ID selector beats any number of class selectors, so rules on ids are hard to override.

Semantic elements

pick elements by what the content is

Images & media

pictures, video and drawing

Alt text, subtitles and captions

Say what an image showsalt="Dog catching a ball"In a link or button, say what it does
Hide a decorative imagealt=""
Add a WebVTT subtitle track<track kind="subtitles" src="en.vtt" srclang="en">
Cover sound effects and music tookind="captions"For viewers who can't hear the audio

TrapDon't write "Image of" or the file name. The old longdesc attribute is obsolete.

Accessibility

make pages work with a keyboard and a screen reader

Native elements first, then ARIA

Make a clickable control<button>Focusable, works with the keyboard, announced as a button
Name an icon-only buttonaria-label="Close"
Hide an icon from screen readersaria-hidden="true"
Announce a change without moving focusaria-live="polite"
Set the language screen readers speak<html lang="en">Set it again on any part in another language

TrapARIA adds no behavior. A div with role="button" still needs tabindex and key handlers.

Focus, dialogs and popovers

Open a dialog the user must answer firstdialog.showModal()Focus moves in, and the rest of the page goes inert
Close a modalSend focus back to the button that opened it
Move focus after a route changetabindex="-1"heading.focus()
Show a menu or tooltippopovertarget="menu"<div id="menu" popover>Esc or a click outside closes it

TrapA z-index can't escape its stacking context. Dialogs and popovers sit in the top layer instead.

Performance

get the first screen up fast

Load scripts and styles

plainparsefetchrunparseasyncparsefetchrunparsedeferparsefetchrun

A plain script stops parsing while it downloads and runs. async runs the moment it arrives. defer waits for parsing to end.

Run scripts after parsing, in page order<script src="app.js" defer>Modules defer by default
Run a script the moment it arrives<script async src="ga.js">
Put scripts just before </body>The old fix. defer in the head starts the download sooner.
Link CSS in the head<link rel="stylesheet">

Trapasync runs scripts in finish order, not page order.

Resource hints

Look up or connect to an origin earlyrel="dns-prefetch"rel="preconnect"
Fetch what this page needs soon<link rel="preload" href="font.woff2" as="font" crossorigin>
Fetch the next page for laterrel="prefetch"

TrapA font preload needs crossorigin, even on the same origin. Without it, the preload doesn't match the real request.

Core Web Vitals

Get LCP to 2.5 seconds or lessfetchpriority="high"On the hero <img>. Keep it in the HTML, not in CSS.
Get INP to 200 ms or lessDefer JavaScript you don't need yet, so the main thread can respond
Get CLS to 0.1 or lesswidth="800" height="600"

TipINP replaced First Input Delay in March 2024.

Smaller files and caching

Make HTML, CSS and JS files smallerMinify in the build step, often 30 to 40 percent smaller. Turn on gzip or Brotli too.
Revalidate the HTML on every visitCache-Control: no-cache
Cache hashed files for a yearmax-age=31536000, immutableLike app.3f9a2c.js. A new version gets a new name.
Set caching with a meta taghttp-equiv="Cache-Control"Not a standard value. Send real HTTP headers.

Trapno-cache still stores the response, but checks with the server before reuse. no-store never stores it.

SEO & sharing

what search engines and social sites read

Meta tags for search

Write the result title and snippet<title><meta name="description">About 50 to 60 characters, then 150 to 160
Keep a page out of search results<meta name="robots" content="noindex">
Pick the main URL among duplicatesrel="canonical"
Add a keywords tag<meta name="keywords">Google ignores it

TrapIf robots.txt blocks a URL, crawlers never see its noindex.

Previews, rich results and A/B tests

Set a shared link's title and imageproperty="og:title"property="og:image"og:type and og:url are required too
Describe the page for rich results<script type="application/ld+json">
Tag the variant a visitor sees<body data-variant="b">Choose it on the server, so the page doesn't flicker
Send users to a variant URL302, not 301, plus a canonical link to the original

TrapShowing Googlebot a different page is cloaking.

Browser APIs

storage, location, workers and offline

Storage, location and drag and drop

Keep data across browser restartslocalStorage.setItem(k, v)Strings only. Use JSON.stringify for objects.
Keep data for this tab onlysessionStorage.setItem(k, v)Cleared when the tab closes
Get the user's locationnavigator.geolocation.getCurrentPosition(onPos)Needs HTTPS and the user's permission
Drag an element and drop it on anotherdraggable="true"e.preventDefault()In the target's dragover, or drop never fires

TrapAny script can read both stores. Never keep session tokens there.

Workers, observers and PWAs

Run heavy work off the main threadnew Worker("w.js")w.postMessage(data)The worker has no DOM access
Know when an element scrolls into viewnew IntersectionObserver(cb)observer.observe(el)
Register a service workernavigator.serviceWorker.register("/sw.js")Needs HTTPS. Serve it from the root to cover every page.
Make the site installable<link rel="manifest" href="/manifest.json">Lists name, icons, start_url, display

Web Components

reusable custom elements without a framework

Custom elements

Register a new tagcustomElements.define("x-card", XCard)The name must contain a hyphen
Set up and clean upconnectedCallback()disconnectedCallback()
React when an attribute changesattributeChangedCallback()Only for names in observedAttributes
Add behavior to a real button<button is="fancy-button">Safari doesn't support it
Load a component file into the page<link rel="import" href="card.html">Chrome only, dropped in version 80. Ship an ES module now.

Shadow DOM, templates and slots

Give an element its own scoped DOMthis.attachShadow({ mode: "open" })Its styles and ids don't leak
Hold markup until script clones it<template>
Show a child in a named slot<slot name="header"><h1 slot="header">
Create a shadow root in plain HTML<template shadowrootmode="open">For server-side rendering
Put several teams' apps on one pageServer-side includes, mount points, script tags, custom elements or iframes

TrapDeclarative Shadow DOM works only at parse time. Setting innerHTML won't create the shadow root.

Security

limit what injected and third-party code can do

Content Security Policy

Allow scripts from your origin and a CDNscript-src 'self' https://cdn.example.com
Trust one inline script<script nonce="r4nd0m">A new random nonce on every response

TrapA <meta> policy can't set frame-ancestors or report-only mode. Send the header.

CDN scripts and iframes

Refuse a CDN file that was changedintegrity="sha384-<hash>" crossorigin="anonymous"
Fetch a script or image with CORScrossorigin="anonymous"crossorigin="use-credentials"
Embed a page with no scripts or forms<iframe src="widget.html" sandbox>

TrapNever give a same-origin frame allow-scripts with allow-same-origin. Its script can remove the sandbox.

Found this useful? Pass it on.
Pro · $10/mo

This sheet stays free. With Pro, you can:

  • Every answer on this sheet. Read the full answer to all 87 questions it links, not just the 14 free ones.
  • My sheet. The cards you star and the ones you miss in Quiz me, from every sheet, on one page to quiz and print.
  • PDFs. Download this sheet and My sheet, laid out for A4, with every question a link to its answer.
  • The rest of Pro. Every answer in the question library, and 1,000 AI credits a month.