HTML
12 / 12

SEO, Performance & Best Practices

HTML: SEO, Performance & Best Practices

Structured Data (JSON-LD)

JSON-LD is the preferred format for structured data. Google uses it to create rich results in search (review stars, FAQ dropdowns, recipe cards, etc.).

<!-- Article schema -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "How to Use HTML Semantic Elements",
  "datePublished": "2024-01-15",
  "dateModified": "2024-02-01",
  "author": {
    "@type": "Person",
    "name": "Alice Johnson",
    "url": "https://example.com/authors/alice"
  },
  "publisher": {
    "@type": "Organization",
    "name": "My Blog",
    "logo": {
      "@type": "ImageObject",
      "url": "https://example.com/logo.png"
    }
  },
  "image": "https://example.com/article-image.jpg",
  "description": "A comprehensive guide to semantic HTML elements"
}
</script>

<!-- Breadcrumb schema -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {"@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com"},
    {"@type": "ListItem", "position": 2, "name": "Blog", "item": "https://example.com/blog"},
    {"@type": "ListItem", "position": 3, "name": "This Article"}
  ]
}
</script>

Performance — Core Web Vitals

  • LCP (Largest Contentful Paint): how fast the largest visible element loads. Target < 2.5s. Fix: preload hero image, fast server response (TTFB), no render-blocking resources.

  • INP (Interaction to Next Paint): responsiveness to clicks/key presses. Target < 200ms. Fix: reduce main thread blocking, defer heavy JavaScript.

  • CLS (Cumulative Layout Shift): visual stability. Target < 0.1. Fix: always include width/height on images, don't inject content above existing content, use CSS aspect-ratio.

Preventing Layout Shift (CLS)

<!-- Always specify dimensions — browser reserves space before image loads -->
<img src="photo.jpg" alt="..." width="800" height="600" loading="lazy">

<!-- CSS aspect-ratio for responsive images -->
<style>
img {
  width: 100%;
  height: auto;
  aspect-ratio: 4/3;  /* maintains ratio even before image loads */
}
</style>

<!-- Font loading — prevent text flash/shift -->
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap;  /* show fallback immediately, swap when loaded */
  /* optional: avoid swap shift if font loads late */
  font-display: optional;
}
</style>

Resource Hints & Loading

<!-- Preload: high-priority fetch of critical resources -->
<link rel="preload" href="/hero.webp" as="image" fetchpriority="high">
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/inter.woff2" as="font" crossorigin>

<!-- Preconnect: early connection to third-party origins (saves 100-500ms) -->
<link rel="preconnect" href="https://api.example.com">
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- DNS-prefetch: cheaper than preconnect, just resolves DNS -->
<link rel="dns-prefetch" href="https://cdn.example.com">

<!-- Prefetch: low-priority fetch for next navigation -->
<link rel="prefetch" href="/next-page.html">

<!-- fetchpriority attribute (Chrome 101+) -->
<img src="hero.jpg" fetchpriority="high" alt="Hero">  <!-- bump priority -->
<img src="below-fold.jpg" fetchpriority="low" alt="Below fold">
<link rel="preload" href="non-critical.js" as="script" fetchpriority="low">

Script & Style Optimization

<!-- Scripts: always defer unless critical -->
<script src="app.js" defer></script>          <!-- recommended -->
<script src="analytics.js" async></script>    <!-- order-independent scripts -->

<!-- Critical CSS inline + load rest async -->
<style>/* inline above-the-fold CSS here */</style>
<link rel="stylesheet" href="full.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="full.css"></noscript>

<!-- Module preload -->
<link rel="modulepreload" href="/app.mjs">

<!-- Lazy load iframes -->
<iframe src="..." loading="lazy"></iframe>

SEO Best Practices Checklist

  • Unique <title> per page: primary keyword + brand name, 50-60 characters

  • Meta description: 120-155 characters, compelling, includes call to action

  • Canonical URL on every page — prevents duplicate content penalty

  • One h1 per page, matching the page topic

  • All images have descriptive alt text (empty alt for decorative images)

  • hreflang tags for multi-language sites

  • Sitemap.xml submitted to Google Search Console

  • robots.txt controlling what search engines can crawl

  • Structured data (JSON-LD) for articles, products, FAQs, breadcrumbs

  • HTTPS (Google uses HTTPS as a ranking signal)

  • Mobile-friendly (viewport meta tag, responsive design) — Google uses mobile-first indexing

  • Fast LCP: Core Web Vitals are ranking signals

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free