What is a CSS ID selector?

A CSS ID selector lets you style an element by targeting its id attribute. In HTML, an ID looks like id="hero". In CSS, you select it with #hero.

IDs are meant to be unique in a document. That makes them perfect for things that appear once: a header, a main content area, a specific call-to-action, a single modal, a specific section you link to, etc.

#hero-title {
  font-weight: 800;
}
  
#hero-title {
  font-weight: 800;
  letter-spacing: 0.05em;
}
  
#hero-title {
  font-weight: 800;
  letter-spacing: 0.05em;
  text-decoration: underline;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  padding: 18px;
  border: 2px solid #111;
  border-radius: 14px;
  max-width: 520px;
}

h2 {
  margin: 0 0 8px;
}

p {
  margin: 0;
  opacity: 0.9;
}
  

Hello, I’m a hero title

This paragraph is not targeted by the ID selector. Only the element with id="hero-title" is.

The basic syntax: #id matches id="…"

The rule is simple:

  • HTML uses id="some-name"
  • CSS uses #some-name

IDs are case-sensitive in HTML/CSS matching in practice (and you should treat them that way). So #Header and #header are not the same.

#note {
  background: #fff7d6;
}
  
#note {
  background: #fff7d6;
  border-left: 6px solid #111;
}
  
#note {
  background: #fff7d6;
  border-left: 6px solid #111;
  padding: 12px 14px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  max-width: 520px;
  border: 2px solid #111;
  border-radius: 14px;
  padding: 16px;
}

p {
  margin: 0;
}
  

I have id="note", so #note can style me.

Combining ID selectors with other selectors

You can combine an ID selector with other selectors to be more specific about what you’re targeting. This is useful when the same ID appears in different contexts (for example, across different pages), or when you want to express intent clearly.

ID + element selector

Writing h3#pricing-title means: “Select the h3 element whose ID is pricing-title.”

h3#pricing-title {
  font-size: 22px;
}
  
h3#pricing-title {
  font-size: 22px;
  text-transform: uppercase;
}
  
h3#pricing-title {
  font-size: 22px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  max-width: 520px;
  border: 2px solid #111;
  border-radius: 14px;
  padding: 16px;
}

h3 {
  margin: 0 0 6px;
}

p {
  margin: 0;
  opacity: 0.9;
}
  

Pricing

The selector h3#pricing-title targets only this heading.

ID + class together

You can also write #card.featured, which means: “Select the element with ID card that also has class featured.”

#card.featured {
  outline: 3px solid #111;
}
  
#card.featured {
  outline: 3px solid #111;
  transform: translateY(-4px);
}
  
#card.featured {
  outline: 3px solid #111;
  transform: translateY(-4px);
  background: #f2f2f2;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  display: grid;
  gap: 12px;
  max-width: 560px;
}

.card {
  border: 2px solid #111;
  border-radius: 14px;
  padding: 14px;
}

.card h4 {
  margin: 0 0 6px;
}

.card p {
  margin: 0;
  opacity: 0.9;
}
  

Normal card

Same class, but not featured.

That last demo sneakily shows something important: duplicate IDs are invalid HTML. CSS will still “work”, but it can lead to bugs and confusing behavior. Let’s talk about it properly.

IDs must be unique (what happens if they aren’t)

In a well-formed HTML document, each ID value should appear only once. If two elements share the same ID:

  • Your CSS selector #that-id will match both elements (so styling can apply to multiple items).
  • JavaScript methods like document.getElementById() typically return only the first match, which can cause “works on my machine” bugs.
  • Anchor links like #section can jump to the “wrong” element.

The result is a UI that feels haunted. (The friendly kind of haunted. Mostly.)

#warning {
  border: 2px solid #111;
  padding: 10px 12px;
}
  
#warning {
  border: 2px solid #111;
  padding: 10px 12px;
  background: #ffe3e3;
}
  
#warning {
  border: 2px solid #111;
  padding: 10px 12px;
  background: #ffe3e3;
}

#warning strong {
  text-decoration: underline;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  display: grid;
  gap: 10px;
  max-width: 560px;
  border: 2px solid #111;
  border-radius: 14px;
  padding: 16px;
}

p {
  margin: 0;
}
  

First element with id="warning".

Second element with the same ID (invalid HTML, but CSS still matches it).

Specificity: why ID selectors “win” so easily

CSS has a conflict-resolution system called specificity. When multiple rules target the same element and set the same property, the browser chooses the rule with higher specificity.

A selector with an ID like #box usually beats: .box, div, .wrap .box, and a whole parade of other selectors. That’s powerful… and also a reason to be careful with IDs in CSS.

Specificity demo: ID beats class

.box {
  border: 4px dashed #111;
}
  
#box {
  border: 4px solid #111;
}
  
.box {
  border: 4px dashed #111;
}

#box {
  border: 4px solid #111;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  max-width: 560px;
  border: 2px solid #111;
  border-radius: 14px;
  padding: 16px;
}

.demo {
  padding: 14px;
  border-radius: 12px;
  background: #f2f2f2;
}

code {
  font-family: ui-monospace, SFMono-Regular, monospace;
}
  
I have class="box" and id="box". When both rules apply, the ID rule wins.

Why high specificity can be a problem

If you style lots of things using IDs, you might later find it hard to override styles without:

  • adding even more specific selectors,
  • rearranging your CSS order,
  • or reaching for !important (which is basically CSS duct tape).

This is why many CSS methodologies recommend using classes for styling and reserving IDs for unique anchors or JavaScript hooks.

Learn more about specificity in the CSS Specificity Interactive Tutorial, and about !important in the CSS !important Interactive Tutorial.

Practical uses for ID selectors

If you’re a beginner, here’s a nice rule of thumb:

  • Use classes when many elements share the style.
  • Use an ID when it’s truly a one-of-one element on the page.

Styling a single page section

#newsletter {
  padding: 18px;
  border: 2px solid #111;
  border-radius: 16px;
}
  
#newsletter {
  padding: 18px;
  border: 2px solid #111;
  border-radius: 16px;
  background: #f2f2f2;
}
  
#newsletter {
  padding: 18px;
  border: 2px solid #111;
  border-radius: 16px;
  background: #f2f2f2;
}

#newsletter h3 {
  margin: 0 0 6px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.page {
  font-family: ui-sans-serif, system-ui, sans-serif;
  display: grid;
  gap: 12px;
  max-width: 560px;
}

.section {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 16px;
}

.section h3 {
  margin: 0 0 6px;
}

.section p {
  margin: 0;
  opacity: 0.9;
}
  

Newsletter

One section can get special styling using its unique ID.

Features

This section has an ID too, but we’re not styling it right now.

IDs aren’t just for CSS. They also power “jump links” in URLs:

  • #faq means “scroll to the element with id="faq"”.
  • This is called a fragment identifier (or just “the hash”).

CSS gives you a special pseudo-class called :target that matches the element currently targeted by the URL fragment. That makes it easy to highlight a section after someone clicks a link.

See the Pen IDs and links: fragments and :target by Element How (@elementhow) on CodePen.

Common problems when ID selectors don’t work

If your ID selector feels like it’s being ignored, it’s usually one of these:

1) The ID in HTML doesn’t match the ID in CSS

  • HTML: id="main-title"
  • CSS: #main-title

Common mistakes include typos, missing hyphens, or mismatched casing.

2) You forgot the # symbol

This one is classic: main-title {} won’t target id="main-title". You need #main-title {}.

3) A more specific rule is overriding you

If something else is winning, check:

  • specificity (IDs are strong, but another ID rule could beat you),
  • order (later rules can win when specificity is equal),
  • !important (it changes the game).
#title {
  color: #111;
}
  
#title {
  color: #111;
}

#title {
  color: #b00020;
}
  
#title {
  color: #111;
}

#title {
  color: #b00020 !important;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  max-width: 560px;
  border: 2px solid #111;
  border-radius: 14px;
  padding: 16px;
}

h3 {
  margin: 0;
}
  

Which color wins?

Advanced: IDs with special characters and escaping

Most of the time, you’ll use simple IDs like header or main-nav. But sometimes IDs can contain characters that are awkward in CSS selectors.

Two beginner-friendly tips:

  • Prefer IDs that are easy to type in CSS: letters, numbers, hyphens, underscores.
  • If you inherit “weird” IDs (from a CMS or generated content), you can still select them, but you may need escaping.

Example: an ID that starts with a number

An ID like id="2cool" is allowed in HTML, but #2cool can be confusing in CSS. One common approach is escaping the first character.

#\32 cool {
  border: 3px solid #111;
}
  
#\32 cool {
  border: 3px solid #111;
  background: #f2f2f2;
}
  
#\32 cool {
  border: 3px solid #111;
  background: #f2f2f2;
  padding: 12px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  max-width: 560px;
  border: 2px solid #111;
  border-radius: 14px;
  padding: 16px;
}

p {
  margin: 0;
}
  

My ID starts with a number: id="2cool". In CSS, we used an escape sequence to select it.

If you ever need to do this in JavaScript, there’s also CSS.escape(), which can safely escape selector text before using it in querySelector(). You don’t need it for normal IDs like main or site-header, but it’s good to know it exists.

Best practices: IDs vs classes

Beginners often ask: “Should I use IDs or classes for styling?”

A solid, beginner-friendly answer is:

  • Use classes for reusable styling patterns.
  • Use IDs for unique page landmarks, anchor targets, or one-off exceptions.

Why? Because ID selectors are very specific and can make future overrides harder. Classes are easier to reuse and easier to maintain as your project grows.

A maintainable pattern: classes for style, IDs for anchors

Here’s a nice compromise: give the section an ID for linking, but use a class for styling.

See the Pen A maintainable pattern: classes for style, IDs for anchors by Element How (@elementhow) on CodePen.

Interactive mini-lab: adjust a unique element’s style

Let’s do a quick hands-on example: we’ll use an ID selector to style a single “badge” and tweak it with sliders.

#sale-badge {
  padding: 12px;
  border-radius: 14px;
  letter-spacing: 0.06em;
  border: 2px solid #111;
  display: inline-block;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  font-family: ui-sans-serif, system-ui, sans-serif;
  max-width: 560px;
  border: 2px solid #111;
  border-radius: 14px;
  padding: 16px;
}

p {
  margin: 0 0 10px;
  opacity: 0.9;
}
  

This badge is unique on the page, so an ID selector is totally reasonable here.

Limited time offer

Common ID naming tips

IDs can be almost any string, but some choices make your life easier:

  • Prefer lowercase and hyphens: main-nav, newsletter, pricing.
  • Avoid spaces (spaces create multiple tokens and cause selector headaches).
  • Don’t start IDs with numbers if you can avoid it (it’s selectable, but not beginner-friendly).
  • Make them meaningful: hero is clearer than x12.

Quick recap

  • An ID selector uses #, like #header, and matches id="header".
  • IDs should be unique in the document.
  • ID selectors have high specificity, which is powerful but can make overrides harder.
  • A common best practice is classes for styling and IDs for anchors (and truly unique one-offs).
  • IDs also power URL fragments, and you can style them with :target.