HTML Performance Best Practices
Performance isn't only a JavaScript or CSS concern—a lot of it comes down to decisions made directly in your HTML markup: how deep your DOM is, which resources you hint the browser to prioritize, which images load lazily, and whether elements have the dimensions they need to avoid shifting the page around. This page is a practical checklist.
Minimize DOM Depth and Size
<div> adds a node the browser must parse, style, lay out, and keep in memory. A large or deeply nested DOM slows down style recalculation, layout, and any JavaScript that queries or walks it.dom-depth.html
<!-- Bloated: five wrapper divs for one line of text -->
<div class="wrapper">
<div class="container">
<div class="row">
<div class="col">
<div class="inner">
<p>Hello</p>
</div>
</div>
</div>
</div>
</div>
<!-- Flatter: same visual result, far fewer nodes -->
<section class="card">
<p>Hello</p>
</section>Aim for well under 1,500 total DOM nodes on any one page where possible.
Avoid nesting deeper than ~10–15 levels; deep trees slow style and layout recalculation.
Use CSS Grid/Flexbox to achieve layouts instead of stacking wrapper divs.
Lazy-Load Below-the-Fold Images
loading="lazy" to every <img> and <iframe> that isn't visible without scrolling. It defers the network request until the user actually scrolls near it, for zero JavaScript cost. See the dedicated lazy-loading page for details on when to skip it.lazy-below-fold.html
<img src="footer-illustration.svg" alt="" loading="lazy" width="600" height="300" />
Defer Non-Critical Scripts
defer to application scripts and async to independent third-party scripts (analytics, ads) so neither blocks HTML parsing. See the dedicated async/defer page for the full comparison.defer-scripts.html
<script src="/js/app.js" defer></script> <script src="https://analytics.example.com/tag.js" async></script>
Preload Critical Resources
<link rel="preload"> tells the browser to start fetching a resource immediately, at high priority, without waiting for the parser or CSSOM to discover it naturally. Use it for resources the browser wouldn't otherwise find early—a hero image referenced only in CSS, or a custom font.preload.html
<head> <link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin /> <link rel="preload" href="/images/hero.avif" as="image" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> </head>
Use Modern Image Formats
<picture> fallback chain so older browsers still get a working image.modern-formats.html
<picture> <source srcset="/images/product.avif" type="image/avif" /> <source srcset="/images/product.webp" type="image/webp" /> <img src="/images/product.jpg" alt="Wireless headphones" width="640" height="480" /> </picture>
Avoid Layout-Shift-Causing Patterns
Cumulative Layout Shift (CLS) measures how much visible content jumps around after it first renders. The most common HTML-level cause is an image, iframe, or ad slot that has no reserved space, so the surrounding content jumps down once it loads.
missing-dimensions.html
<!-- Bad: no dimensions, causes a layout jump when the image loads --> <img src="banner.jpg" alt="Sale banner" /> <!-- Good: browser reserves the exact space up front --> <img src="banner.jpg" alt="Sale banner" width="1200" height="400" />
width and height attributes doesn't lock an image to that pixel size—combined with img { width: 100%; height: auto; } in your CSS, the attributes only establish the correct aspect ratio for layout reservation, while the image still scales responsively.Always set width and height (or aspect-ratio in CSS) on images, videos, and iframes.
Reserve space for ad slots and embeds before they load, even if the exact size varies.
Avoid inserting content above existing content unless in response to a user interaction.
Use font-display: swap (or optional) and preload key fonts to reduce font-swap layout shift.
Full Checklist
Practice | Why it matters |
|---|---|
Minimize DOM depth/size | Faster style calculation, layout, and JS traversal |
loading="lazy" on below-fold media | Reduces initial network and CPU load |
defer/async on scripts | Stops JS from blocking HTML parsing |
rel="preload" on critical assets | Starts fetching key resources sooner |
Modern image formats (WebP/AVIF) | Smaller file sizes at equal quality |
width/height on media | Prevents layout shift (CLS) |
Minified HTML/CSS/JS | Fewer bytes to transfer and parse |