Skip to main content
Following HTML best practices ensures your code is accessible, maintainable, performant, and future-proof. This guide covers essential practices every web developer should follow.

Document Structure

Always Include DOCTYPE

<!DOCTYPE html>

Why It Matters

Tells browsers to use standards mode instead of quirks mode, ensuring consistent rendering across browsers.

HTML5 Simplicity

HTML5’s DOCTYPE is simple and backwards compatible. Always use it.

Set Language and Charset

<html lang="es">
<head>
  <meta charset="UTF-8" />
  <!-- Rest of head -->
</head>
Benefits:
  • lang attribute helps screen readers pronounce content correctly
  • Improves SEO by indicating content language
  • charset="UTF-8" supports all characters worldwide
  • Must be declared early in the <head> section

Include Viewport Meta Tag

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Essential for responsive design. Without this, mobile devices display the desktop version zoomed out.

Semantic HTML

Use Semantic Elements

<div class="header">
  <div class="nav">
    <div class="link">Home</div>
    <div class="link">About</div>
  </div>
</div>

<div class="content">
  <div class="article">
    <div class="title">Article Title</div>
    <div class="text">Content...</div>
  </div>
</div>

<div class="footer">
  <div class="copyright">© 2024</div>
</div>
Uses generic <div> elements for everything.
Semantic elements to use:
  • <header>, <nav>, <main>, <article>, <section>, <aside>, <footer>
  • <figure>, <figcaption>, <time>, <mark>, <address>

Proper Heading Hierarchy

<h1>Main Title</h1>
<h3>Subtitle</h3> <!-- Skipped h2 -->
<h2>Section</h2> <!-- Out of order -->
<h1>Another Title</h1> <!-- Multiple h1s -->
  • Skips heading levels
  • Multiple <h1> elements
  • Out of logical order
SEO and Accessibility: Search engines and screen readers use heading hierarchy to understand page structure. Don’t skip levels or use multiple <h1> tags.

Accessibility

Always Include Alt Text

<!-- No alt attribute -->
<img src="product.jpg" />

<!-- Generic alt text -->
<img src="laptop.jpg" alt="image" />

<!-- Filename as alt -->
<img src="IMG_1234.jpg" alt="IMG_1234" />
Alt text guidelines:
  • Describe the image’s content and function
  • Keep it concise (under 125 characters)
  • Don’t start with “image of” or “picture of”
  • Use empty alt (alt="") for decorative images
  • For complex images, consider <figcaption> or longer description

Use ARIA Labels for Icons

<!-- Icon-only button needs aria-label -->
<button type="submit" class="search-btn" aria-label="Search">
  <svg><!-- Search icon --></svg>
</button>

<!-- Button with visible text doesn't need aria-label -->
<button type="submit" class="search-btn">
  <svg><!-- Search icon --></svg>
  Search
</button>

Associate Labels with Inputs

<!-- No label -->
<input type="email" placeholder="Email" />

<!-- Unassociated label -->
<label>Email</label>
<input type="email" />

Semantic Navigation

<!-- Use nav element and lists -->
<nav aria-label="Main navigation">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

<!-- For multiple navs, use aria-label to distinguish -->
<nav aria-label="Breadcrumb">
  <ol>
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a></li>
    <li aria-current="page">Laptops</li>
  </ol>
</nav>

Performance

Optimize Images

<!-- Use loading='lazy' for images below the fold -->
<img 
  src="product.jpg" 
  alt="Gaming Laptop" 
  loading="lazy"
  width="800"
  height="600"
/>

<!-- Provide width and height to prevent layout shift -->
<img 
  src="hero.jpg" 
  alt="Hero image" 
  width="1920" 
  height="1080"
/>
Benefits:
  • loading="lazy": Defers loading until image is near viewport
  • width and height: Prevents Cumulative Layout Shift (CLS)
  • Improves Core Web Vitals

Preconnect to External Domains

<head>
  <!-- Preconnect to external API -->
  <link rel="preconnect" href="https://api.example.com" />
  
  <!-- Preconnect to Google Fonts -->
  <link rel="preconnect" href="https://fonts.googleapis.com" />
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
</head>
Benefits: Establishes early connections, reducing latency when fetching resources.

Script Loading Strategy

<head>
  <!-- Blocks HTML parsing -->
  <script src="large-script.js"></script>
</head>
Script downloads and executes immediately, blocking page render.
When to use each:
  • No attribute: Critical scripts that must run before page render
  • defer: Most scripts (executes in order, after DOM ready)
  • async: Independent scripts (analytics, ads)
  • type=“module”: Modern ES6 modules

Code Quality

Use Lowercase for Tags and Attributes

<DIV CLASS="Container">
  <IMG SRC="image.jpg" ALT="Image" />
</DIV>

Quote Attribute Values

<input type=text class=form-input />
<a href=/products>Products</a>

Close Void Elements Consistently

<!-- HTML5 allows both, pick one style and stick to it -->

<!-- Self-closing (XHTML style) -->
<img src="image.jpg" alt="Image" />
<br />
<meta charset="UTF-8" />

<!-- No self-closing (HTML5 style) -->
<img src="image.jpg" alt="Image">
<br>
<meta charset="UTF-8">
Both styles are valid in HTML5. Choose one and use it consistently throughout your project.

Indent and Format Consistently

<!-- Good indentation and structure -->
<header class="header">
  <div class="header__container">
    <nav class="header__nav">
      <ul class="header__nav-list">
        <li class="header__nav-item">
          <a href="/" class="header__nav-link">Home</a>
        </li>
        <li class="header__nav-item">
          <a href="/products" class="header__nav-link">Products</a>
        </li>
      </ul>
    </nav>
  </div>
</header>
Best practices:
  • Use consistent indentation (2 spaces or 4 spaces)
  • One element per line for block elements
  • Group related attributes
  • Use formatting tools (Prettier, etc.)

SEO

Unique, Descriptive Titles

<title>Home</title>
<title>Page</title>
<title>Welcome to our website where we sell products</title>
Too generic, too vague, or too long.
Title best practices:
  • 50-60 characters max
  • Include primary keyword
  • Add brand name
  • Make each page title unique

Meta Descriptions

<meta 
  name="description" 
  content="Shop the best gaming laptops at ML Store. Free shipping on orders over $299. Expert reviews and top brands."
/>
Best practices:
  • 150-160 characters
  • Include primary keyword naturally
  • Write compelling copy (it appears in search results)
  • Unique for each page

Structured Data

<!-- JSON-LD structured data for products -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Gaming Laptop Pro",
  "image": "https://example.com/laptop.jpg",
  "description": "High-performance gaming laptop",
  "brand": "TechBrand",
  "offers": {
    "@type": "Offer",
    "price": "1299.99",
    "priceCurrency": "USD"
  }
}
</script>
Helps search engines understand your content better, potentially showing rich results.

Common Anti-Patterns to Avoid

Don't Use Tables for Layout

Tables are for tabular data only. Use CSS Grid or Flexbox for layouts.
<!-- Bad -->
<table>
  <tr>
    <td>Header</td>
  </tr>
  <tr>
    <td>Content</td>
  </tr>
</table>

Don't Use Inline Styles

Use external CSS files or CSS classes. Inline styles are hard to maintain.
<!-- Bad -->
<div style="color: red; margin: 10px;">
  Content
</div>

Don't Use Deprecated Tags

Avoid <center>, <font>, <marquee>, <blink>, <frame>, etc.
<!-- Bad -->
<center>
  <font color="red">Text</font>
</center>

Don't Omit Required Attributes

Always include required attributes like alt, src, href, type.
<!-- Bad -->
<img src="image.jpg" />
<a>Click here</a>

Validation

Validate Your HTML

Use the W3C Markup Validation Service to check for:
  • Syntax errors
  • Missing required attributes
  • Deprecated elements
  • Improper nesting
<!-- Example of validation catching errors -->

<!-- Invalid: Missing alt attribute -->
<img src="logo.png" />

<!-- Invalid: Improper nesting -->
<p>Paragraph <div>Block inside inline</div></p>

<!-- Invalid: Duplicate IDs -->
<div id="content"></div>
<div id="content"></div>

Quick Reference Checklist

1

Document Setup

  • DOCTYPE declaration
  • lang attribute on <html>
  • charset meta tag
  • Viewport meta tag
  • Unique, descriptive title
2

Semantic HTML

  • Use semantic elements (<header>, <nav>, <main>, etc.)
  • Proper heading hierarchy (one <h1>, logical order)
  • <article> for independent content
  • <section> for thematic grouping
3

Accessibility

  • Alt text on all images
  • Labels associated with form inputs
  • ARIA labels on icon buttons
  • Semantic navigation with <nav> and lists
  • Sufficient color contrast
4

Performance

  • Lazy loading on below-fold images
  • Width/height on images
  • Preconnect to external domains
  • Scripts loaded with defer or async
5

Code Quality

  • Consistent indentation
  • Lowercase tags and attributes
  • Quoted attribute values
  • Valid HTML (no syntax errors)

Summary

Following these best practices will help you create:
  • Accessible websites that work for everyone
  • Performant pages that load quickly
  • Maintainable code that’s easy to update
  • SEO-friendly content that ranks well
  • Standards-compliant HTML that works across browsers

Keep Learning

HTML is constantly evolving. Stay updated with MDN Web Docs and W3C specifications for the latest standards and best practices.

Build docs developers (and LLMs) love