The class and id Attributes
Two ways to name an element, with different rules and different jobs. Choosing correctly makes a stylesheet maintainable and stops the specificity war before it starts.
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
Concept
class and id both attach a name to an element, and beginners often treat them as interchangeable. They are not.
class | id | |
|---|---|---|
| Reusable | Yes, on any number of elements | No, unique per document |
| Multiple per element | Yes, space separated | No, one only |
| CSS selector | .name | #name |
| Specificity | Low (0,1,0) | High (1,0,0) |
| Fragment link target | No | Yes |
| Label association | No | Yes |
| Main use | Styling | Addressing one element |
Syntax
<article class="card card-featured is-new" id="post-1043">
<h2 class="card-title">Reading a bus timetable</h2>
</article>Three class names, separated by spaces, all applying at once. One id, unique in the document.
What each is actually for
class - styling and grouping
.card { border: 1px solid #cbd5e1; border-radius: 8px; }
.card-featured { border-color: #1e3a8a; }
.is-new::after { content: "New"; }Because classes are reusable and low specificity, they compose well and stay easy to override. This is why nearly all styling should go through them.
id - addressing one specific element
<!-- a fragment link target -->
<h2 id="fees">Fees</h2>
<a href="#fees">Jump to fees</a>
<!-- label association -->
<label for="email">Email</label>
<input id="email" name="email">
<!-- ARIA relationships -->
<input aria-describedby="email-hint">
<small id="email-hint">We will not share it.</small>
<!-- a script hook -->
<div id="chart"></div>These are the real uses, and every one of them is about identifying one element, not about styling it.
Why styling with ids goes wrong
Specificity. An id selector is worth more than any number of class selectors, so once a style is set through an id, overriding it needs another id or !important.
#sidebar { background: white; }
/* loses, despite being far more specific in plain English */
.theme-dark .sidebar.is-collapsed { background: black; }The escalation that follows - more ids, then !important, then !important on the override - is how a stylesheet becomes unmaintainable. Keeping styling to classes keeps specificity flat and predictable.
Naming
Rules first:
- Both are case sensitive.
.Cardand.cardare different. - An id must be unique and must not contain spaces.
- An id starting with a digit needs escaping in CSS, so start with a letter.
- A class name starting with a digit is invalid in a selector.
- Avoid dots, colons and slashes; they need escaping.
Then conventions:
<!-- weak: names the appearance -->
<p class="red-text big">Out of stock</p>
<!-- good: names the meaning -->
<p class="stock-status stock-status-out">Out of stock</p>Naming by appearance guarantees a future contradiction: the day the design changes to orange, class="red-text" is a lie that survives in the codebase for years.
A naming pattern worth knowing
BEM - block, element, modifier - is the most widely used convention:
<article class="card card--featured">
<h2 class="card__title">Design course</h2>
<p class="card__summary">Three years, studio based.</p>
<a class="card__link card__link--primary" href="/courses/design">Read more</a>
</article>block- the component:cardblock__element- a part of it:card__titleblock--modifier- a variant:card--featured
It is verbose, and it makes every selector a single flat class with identical specificity, which removes nesting battles entirely. You do not have to use BEM, but pick some convention and hold to it.
State classes
<div class="menu is-open">
<button class="btn is-loading">
<li class="tab is-active">An is- prefix for states that scripts toggle makes it obvious which classes are dynamic. A data- attribute is an alternative for states that are mutually exclusive.
Do not style ids that are there for other reasons
<!-- the id is for the fragment link and the script; the class is for styling -->
<section id="fees" class="content-section">
<h2>Fees</h2>
</section>Keeping the two jobs on two attributes means renaming a style hook never breaks a bookmark, and changing a link target never breaks the design.
Important rules
- An id must be unique. Duplicates break fragment links, label association, ARIA references and
getElementById. - Both are case sensitive.
- An element may have many classes and one id.
- Class order in the attribute does not affect the cascade; order in the stylesheet does.
- Ids and classes are invisible to assistive technology.
- An id can be a target for CSS
:target, scroll anchoring and browser find.
Common mistakes
- Reusing an id across several elements.
- Styling through ids and creating a specificity problem.
- Class names describing colour or size.
- A different naming convention in every file.
- Case mismatches between the markup and the stylesheet.
- Using a class where a label needs an id, so the label never binds.
- Fifteen classes on one element because none of them could be reused.
Best practices
- Style with classes. Use ids for links, labels, ARIA and script hooks.
- Name by meaning, never by appearance.
- Pick one naming convention and apply it everywhere.
- Prefix state classes with
is-or use a data attribute. - Keep selectors flat and specificity low.
- Keep ids stable; they appear in bookmarks and inbound links.
Practice
- Set a background with an id selector, then try to override it with three chained classes. What did it take?
- Rename every appearance based class in a file to a meaning based one.
- Mark up a card component using BEM.
- Duplicate an id on two elements and see which one a fragment link and
getElementByIdreach.