HTMLCommon Mistakes to Avoid

Common HTML Mistakes to Avoid

Browsers rarely refuse to render broken HTML—they quietly patch over it, which means bad habits can survive in a codebase for years without anyone noticing. This page rounds up the anti-patterns that show up most often in real projects, why each one is a problem, and the fix.

1. Missing Alt Text

missing-alt.html

HTML
<!-- Bad: no alt attribute at all -->
<img src="team-photo.jpg" />

<!-- Good: describes the image's content -->
<img src="team-photo.jpg" alt="The engineering team at the 2026 offsite" />
Without alt, screen readers announce the filename or nothing at all, and the image contributes zero information if it fails to load. Purely decorative images should still include alt=""—omitting the attribute entirely is different from an intentionally empty one.
2. Missing lang Attribute

missing-lang.html

HTML
<!-- Bad -->
<html>

<!-- Good -->
<html lang="en">
Without lang, screen readers guess the language (often wrongly) and can mispronounce entire pages, and browsers can't offer accurate auto-translation.
3. Non-Unique IDs

duplicate-ids.html

HTML
<!-- Bad: two elements share the same id -->
<div id="card">First card</div>
<div id="card">Second card</div>

<!-- Good: unique ids, shared styling via class -->
<div id="card-1" class="card">First card</div>
<div id="card-2" class="card">Second card</div>
IDs must be unique per page
Duplicate IDs break document.getElementById, label for associations (the label binds to whichever matching ID comes first), and fragment links (#card jumps to the first match only). Use classes for shared styling, IDs only for genuinely unique references.
4. Deprecated Tags

A handful of tags from early HTML are obsolete—they either never made it into HTML5 or were explicitly removed. Modern browsers may still render some of them for backward compatibility, but they should never appear in new code.

Deprecated tag

Replacement

<font>

CSS font-family / font-size / color

<center>

CSS text-align: center / margin: auto

<marquee>

CSS animation or a JavaScript carousel

<blink>

Removed entirely — do not use

<big> / <small> as styling

CSS font-size (note: <small> is valid but means "side comment," not "smaller text")

<strike>

<s> or <del> depending on intent

deprecated-vs-modern.html

HTML
<!-- Bad: presentational tags from the 1990s -->
<center><font color="red" size="5">Sale ends soon!</font></center>

<!-- Good: semantic markup, styling via CSS -->
<p class="banner">Sale ends soon!</p>
5. Div-Soup Instead of Semantic Elements

div-soup.html

HTML
<!-- Bad: no semantic meaning anywhere -->
<div class="header">
  <div class="nav">...</div>
</div>
<div class="main">
  <div class="article">...</div>
</div>
<div class="footer">...</div>

<!-- Good: same layout, real meaning -->
<header>
  <nav>...</nav>
</header>
<main>
  <article>...</article>
</main>
<footer>...</footer>
6. Unclosed Tags

unclosed-tags.html

HTML
<!-- Bad: <p> never closed, browser guesses where it should end -->
<p>First paragraph
<p>Second paragraph

<!-- Good -->
<p>First paragraph</p>
<p>Second paragraph</p>

The browser's error-recovery algorithm auto-closes many unclosed tags, but the rules are subtle and can produce a DOM structure that doesn't match what you intended—especially with nested elements.

7. Invalid Nesting

invalid-nesting.html

HTML
<!-- Bad: block-level <div> inside inline-only <p> -->
<p>
  Some text
  <div>a block inside a paragraph</div>
</p>

<!-- Bad: <a> nested inside another <a> -->
<a href="/outer">
  Outer link
  <a href="/inner">Inner link</a>
</a>

<!-- Good -->
<div>
  <p>Some text</p>
  <div>a separate block</div>
</div>
Browsers silently repair invalid nesting
When the parser hits a <div> inside a <p>, it implicitly closes the paragraph early to keep the document valid—which can split content in ways you didn't expect and didn't write in your source.
8. Skipping Heading Levels

skipped-headings.html

HTML
<!-- Bad: jumps from h1 to h4 for visual size, not structure -->
<h1>Page Title</h1>
<h4>Section</h4>

<!-- Good: correct hierarchy, size controlled by CSS -->
<h1>Page Title</h1>
<h2 class="small-heading">Section</h2>
9. Using onclick Attributes for Interactivity

inline-handlers.html

HTML
<!-- Bad: div fakes a button, no keyboard access, inline JS handler -->
<div onclick="deleteItem(3)">Delete</div>

<!-- Good: real button, event listener attached in JS -->
<button type="button" data-id="3" class="delete-btn">Delete</button>
10. Missing width/height on Images

missing-dimensions.html

HTML
<!-- Bad: causes a layout shift once the image loads -->
<img src="banner.jpg" alt="Banner" />

<!-- Good: browser reserves the correct space up front -->
<img src="banner.jpg" alt="Banner" width="1200" height="400" />
Quick Reference

Mistake

Consequence

Fix

Missing alt

Inaccessible, meaningless on load failure

Always add alt (or alt="" for decorative)

Missing lang

Wrong pronunciation, bad auto-translation

Add lang on <html>

Duplicate IDs

Broken JS lookups, labels, fragment links

Make every id unique

Deprecated tags

No modern support, poor styling control

Use CSS + semantic tags

Div-soup

No accessibility/SEO signal

Use semantic elements

Unclosed tags

Unpredictable auto-correction

Always close non-void tags

Invalid nesting

Browser silently restructures your DOM

Follow content-model rules

Skipped headings

Broken navigation for screen readers

Sequential hierarchy, style with CSS

onclick on divs

No keyboard access, no semantics

Use real <button>/<a> elements

Missing dimensions

Layout shift (poor CLS)

Set width/height or aspect-ratio

Run it through a validator
Many of these mistakes—duplicate IDs, invalid nesting, unclosed tags—are caught automatically by the W3C Markup Validator. See the dedicated validation page for a walkthrough.
Muscle memory beats memorizing a list
You won't remember every rule on this page by heart. What sticks is the habit of reaching for a semantic element first and asking "is there a real tag for this?" before writing another div.