HTML Best Practices
Writing clean, maintainable HTML improves collaboration, performance, and security. These practices help you write professional-quality code.
Code Organization
Indentation
Use consistent indentation (2 or 4 spaces):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Page</title>
</head>
<body>
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
</header>
</body>
</html>
Line Length
Keep lines under 80-100 characters:
<!-- Bad: Long line -->
<img src="very-long-image-path/that-keeps-going/and-going.jpg" alt="A very long alt text that describes the image in great detail for accessibility" />
<!-- Good: Shorter lines with attributes on separate lines -->
<img
src="very-long-image-path/that-keeps-going/and-going.jpg"
alt="A very long alt text that describes the image in great detail for accessibility"
/>
Logical Structure
Organize elements logically:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Meta tags first -->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Title -->
<title>Page Title</title>
<!-- Styles -->
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<!-- Header -->
<header>
<nav><!-- Navigation --></nav>
</header>
<!-- Main content -->
<main>
<article><!-- Article content --></article>
</main>
<!-- Footer -->
<footer><!-- Footer content --></footer>
<!-- Scripts at end -->
<script src="app.js"></script>
</body>
</html>
Naming Conventions
Class Names
Use descriptive, kebab-case class names:
<!-- Bad: Generic or unclear names -->
<div class="box">
<div class="red">
<div class="container-1">
<!-- Good: Descriptive names -->
<div class="product-card">
<div class="error-message">
<div class="main-container">
Rules:
- Use lowercase
- Use hyphens (kebab-case):
nav-itemnotnavItem - Be descriptive:
user-profilenotprofile - Avoid abbreviations:
navigationnotnav(unless obvious)
ID Names
Use IDs sparingly, only for JavaScript or CSS hooks:
<!-- Good: IDs for JavaScript -->
<div id="user-dashboard">
<button id="submit-form">
<!-- Bad: IDs for styling -->
<div id="sidebar" class="sidebar"> <!-- Use class instead -->
HTML Structure
DOCTYPE
Always include DOCTYPE:
<!DOCTYPE html>
Language Attribute
Always set the language:
<html lang="en">
Character Encoding
Always include charset first:
<meta charset="UTF-8" />
Viewport
Always include for responsive design:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Semantic HTML
Use elements for their meaning:
<!-- Bad: Using divs for everything -->
<div class="header">
<div class="nav">
<div class="content">
<div class="footer">
<!-- Good: Using semantic elements -->
<header>
<nav>
<main>
<footer>
Performance
Optimize Images
Always specify dimensions:
<!-- Bad: Causes layout shift -->
<img src="photo.jpg" alt="Photo" />
<!-- Good: Prevents layout shift -->
<img src="photo.jpg" alt="Photo" width="800" height="600" />
Lazy Loading
Load images only when visible:
<img src="photo.jpg" alt="Photo" loading="lazy" />
Minimize HTTP Requests
Combine and minify:
<!-- Bad: Multiple files -->
<link rel="stylesheet" href="header.css" />
<link rel="stylesheet" href="content.css" />
<link rel="stylesheet" href="footer.css" />
<!-- Good: Single file -->
<link rel="stylesheet" href="styles.min.css" />
Security
Escape User Input
Always escape user-generated content:
<!-- User input -->
<script>alert('xss')</script>
<!-- Escaped (safe) -->
<script>alert('xss')</script>
Use HTTPS
Always use HTTPS:
<!-- Bad -->
<a href="http://example.com">Link</a>
<!-- Good -->
<a href="https://example.com">Link</a>
Set Content Security Policy
Prevent XSS attacks:
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
Validate Input
Never trust user input:
<!-- Always validate on server -->
<form action="/submit" method="POST">
<input type="email" name="email" required />
</form>
Accessibility
Label All Inputs
Every input needs a label:
<!-- Bad -->
<input type="text" name="email" />
<!-- Good -->
<label for="email">Email</label>
<input type="email" id="email" name="email" />
Use Semantic Elements
Semantic elements are more accessible:
<!-- Bad -->
<div onclick="handleClick()">Click me</div>
<!-- Good -->
<button onclick="handleClick()">Click me</button>
Add Alt Text
All images need alt text:
<!-- Bad -->
<img src="photo.jpg" />
<!-- Good -->
<img src="photo.jpg" alt="A sunset over mountains" />
Complete Example
Here’s a complete, well-structured HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Best Practices Example</title>
<meta name="description" content="Example of HTML best practices" />
<link rel="stylesheet" href="styles.min.css" />
</head>
<body>
<!-- Skip link for accessibility -->
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<!-- Header -->
<header class="site-header">
<nav class="main-navigation" aria-label="Main navigation">
<ul class="nav-list">
<li class="nav-item">
<a href="/" class="nav-link" aria-current="page">Home</a>
</li>
<li class="nav-item">
<a href="/about" class="nav-link">About</a>
</li>
</ul>
</nav>
</header>
<!-- Main Content -->
<main id="main-content" class="main-content">
<article class="blog-post">
<header class="post-header">
<h1 class="post-title">Article Title</h1>
<time class="post-date" datetime="2026-09-08">
September 8, 2026
</time>
</header>
<div class="post-content">
<p>Article content here...</p>
<figure class="post-image">
<img
src="photo.jpg"
alt="Descriptive alt text"
width="800"
height="600"
loading="lazy"
/>
<figcaption class="image-caption">
Figure 1: Image description
</figcaption>
</figure>
</div>
<footer class="post-footer">
<p class="post-tags">
Tags:
<a href="/tag/html" class="tag">HTML</a>,
<a href="/tag/best-practices" class="tag">Best Practices</a>
</p>
</footer>
</article>
</main>
<!-- Footer -->
<footer class="site-footer">
<nav class="footer-navigation" aria-label="Footer navigation">
<ul class="footer-links">
<li>
<a href="/privacy" class="footer-link">Privacy</a>
</li>
<li>
<a href="/terms" class="footer-link">Terms</a>
</li>
</ul>
</nav>
<p class="copyright">© 2026 My Site. All rights reserved.</p>
</footer>
<script src="app.min.js"></script>
</body>
</html>
Checklist
Structure:
- DOCTYPE included
- Language attribute set
- Character encoding set
- Viewport meta tag
Semantics:
- Semantic elements used
- Proper heading hierarchy
- Landmark roles where needed
Accessibility:
- All images have alt text
- All inputs have labels
- Keyboard navigation works
- Screen reader tested
Performance:
- Images optimized
- Lazy loading enabled
- CSS/JS minified
- No unnecessary requests
Security:
- HTTPS used
- User input escaped
- CSP header set
Common Mistakes
- Not using semantic HTML — Use divs only when necessary
- Missing alt text — All images need alt attributes
- No viewport meta — Site won’t work on mobile
- Inline styles — Use CSS files instead
- Ignoring accessibility — Test with screen readers
- Not validating code — Use W3C validator
- Hardcoding paths — Use relative URLs
- Over-nesting — Keep HTML flat when possible