HTML Performance Attributes

โ–ถ Try It Yourself

HTML Performance Attributes

1. Introduction

Modern HTML provides a set of attributes that directly control how the browser loads, parses, and executes resources โ€” without any JavaScript required. Attributes like defer, async, loading, fetchpriority, decoding, and importance let you express your loading intent directly in HTML, allowing browsers to optimise the critical rendering path. This lesson covers each attribute, when to use it, and the common combinations that significantly improve Core Web Vitals.

2. Concept

Script Loading Attributes Compared

Attribute HTML Parsing Blocked? Execution Order Best For
(none) Yes โ€” immediately In order Avoid for external scripts
defer No โ€” downloads in parallel In order, after HTML parsed Non-critical scripts that need DOM
async No โ€” downloads in parallel As soon as downloaded (may be out of order) Independent scripts: analytics, ads
type="module" No โ€” behaves like defer In order, deferred ES module scripts
Note: defer guarantees scripts execute in the order they appear in HTML, after the document is fully parsed but before DOMContentLoaded. async makes no order guarantees โ€” the first to download executes first. Use defer for scripts with dependencies; use async for truly independent scripts.
Tip: Place <script defer> in the <head>, not at the bottom of <body>. When placed in the head, the browser can begin downloading the script while parsing the HTML. Placing scripts at the bottom of body delays the download start.
Warning: async scripts may execute before or after DOMContentLoaded, and they execute as soon as they are downloaded โ€” not when the DOM is ready. Never use async for scripts that need to interact with the DOM or depend on other scripts.

3. Basic Example

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Performance Attributes Demo</title>

    <!-- async: independent analytics script, order doesn't matter -->
    <script async src="/js/analytics.js"></script>

    <!-- defer: main app script, needs DOM, executed in order -->
    <script defer src="/js/app.js"></script>
    <script defer src="/js/components.js"></script>

    <!-- ES module: deferred by default -->
    <script type="module" src="/js/main.mjs"></script>
  </head>
  <body>
    <h1>Performance Attributes</h1>

    <!-- loading="eager": above-fold image โ€” default, no lazy loading -->
    <img
      src="/images/hero.jpg"
      alt="Hero image"
      width="1200" height="600"
      fetchpriority="high"
      decoding="sync"
    >

    <!-- loading="lazy": below-fold image โ€” deferred until near viewport -->
    <img
      src="/images/product.jpg"
      alt="Product image"
      width="400" height="300"
      loading="lazy"
      decoding="async"
    >

    <!-- iframe lazy loading -->
    <iframe
      src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ"
      title="Product demo video"
      width="560" height="315"
      loading="lazy"
      allow="accelerometer; autoplay; clipboard-write; encrypted-media"
      allowfullscreen
    ></iframe>

  </body>
</html>

4. How It Works

Step 1 โ€” defer vs async

defer downloads the script in parallel with HTML parsing and executes it in source order once the HTML is fully parsed. This is safe for all scripts that read or modify the DOM. async also downloads in parallel but executes immediately when downloaded โ€” potentially mid-parse and out of order. Use async only for truly independent scripts like analytics.

Step 2 โ€” fetchpriority

fetchpriority="high" on an image signals to the browser’s preload scanner that this resource should be fetched at high priority. Use it on the LCP (Largest Contentful Paint) image โ€” typically the hero banner. fetchpriority="low" is useful for below-fold images where you want lazy loading to defer even further.

Step 3 โ€” decoding

decoding="async" allows the browser to decode the image off the main thread without blocking other rendering. decoding="sync" ensures the image is decoded before the next paint โ€” use this only for above-fold images where you want to avoid a flash of unstyled content. The default is auto (browser decides).

Step 4 โ€” loading=”lazy” on iframes

The loading="lazy" attribute works on both <img> and <iframe>. Lazy-loading a YouTube embed until it nears the viewport can save several hundred kilobytes of JavaScript and eliminate the render-blocking impact of third-party iframes entirely.

5. Real-World Example

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TechStore Homepage</title>

    <!-- Preconnect to CDN -->
    <link rel="preconnect" href="https://cdn.techstore.com" crossorigin>

    <!-- Critical CSS inline (omitted here for brevity) -->
    <style>/* critical CSS inlined */</style>

    <!-- Non-critical CSS loaded asynchronously -->
    <link rel="preload" href="/css/full.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
    <noscript><link rel="stylesheet" href="/css/full.css"></noscript>

    <!-- analytics: async โ€” independent, does not need DOM -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX"></script>

    <!-- app scripts: defer โ€” need DOM and must execute in order -->
    <script defer src="/js/polyfills.js"></script>
    <script defer src="/js/app.js"></script>
    <script defer src="/js/cart.js"></script>

    <!-- Preload LCP image -->
    <link rel="preload" as="image" href="/banners/hero.webp" imagesrcset="/banners/hero-480.webp 480w, /banners/hero.webp 1200w" imagesizes="(max-width:480px) 100vw, 1200px">
  </head>
  <body>

    <!-- LCP image: fetchpriority high, no lazy loading -->
    <picture>
      <source type="image/webp" srcset="/banners/hero-480.webp 480w, /banners/hero.webp 1200w" sizes="(max-width:480px) 100vw, 1200px">
      <img
        src="/banners/hero.jpg"
        alt="TechStore summer sale โ€” up to 40% off laptops and monitors"
        width="1200" height="400"
        fetchpriority="high"
        decoding="sync"
      >
    </picture>

    <h1>Summer Sale โ€” Up to 40% Off</h1>

    <!-- Below-fold products: lazy load -->
    <section>
      <h2>Featured Products</h2>
      <img src="/products/probook15-thumb.jpg" alt="ProBook 15 laptop thumbnail" width="300" height="200" loading="lazy" decoding="async">
      <img src="/products/monitor4k-thumb.jpg" alt="4K monitor thumbnail"        width="300" height="200" loading="lazy" decoding="async">
      <img src="/products/keyboard-thumb.jpg"  alt="Mechanical keyboard thumbnail" width="300" height="200" loading="lazy" decoding="async">
    </section>

    <!-- Third-party embed: lazy load to avoid blocking render -->
    <iframe
      src="https://www.youtube-nocookie.com/embed/PRODUCT_VIDEO_ID"
      title="ProBook 15 overview video"
      width="560" height="315"
      loading="lazy"
      allow="accelerometer; autoplay; encrypted-media"
      allowfullscreen
      style="border:none"
    ></iframe>

  </body>
</html>

6. Common Mistakes

Loading scripts without defer or async โ€” blocks HTML parsing

<head>
  <script src="/js/app.js"></script>  <!-- blocks rendering -->
</head>

Use defer in the head for DOM-dependent scripts

<head>
  <script defer src="/js/app.js"></script>
</head>

async on a script that depends on another script

<script async src="/js/jquery.js"></script>
<script async src="/js/jquery-plugin.js"></script>  <!-- may run before jQuery -->

Use defer for scripts with dependencies; async only for independent scripts

<script defer src="/js/jquery.js"></script>
<script defer src="/js/jquery-plugin.js"></script>  <!-- guaranteed order -->

7. Try It Yourself

▶ Test with PageSpeed Insights

8. Quick Reference

Attribute Element Effect Use When
defer script Download in parallel; execute in order after parse DOM-dependent scripts
async script Download in parallel; execute immediately when ready Independent scripts (analytics)
loading=”lazy” img, iframe Defers load until near viewport Below-fold images and iframes
fetchpriority=”high” img, link, script Elevates download priority LCP image, critical CSS
decoding=”async” img Decode off main thread Below-fold images
decoding=”sync” img Decode before next paint Above-fold hero image
type=”module” script ES module โ€” deferred, strict mode Modern JS modules

9. Quiz

🧠 Test Yourself

Which script attribute downloads the file in parallel with HTML parsing AND guarantees execution order?





โ–ถ Try It Yourself