Learning CSS - Basic Selectors and Specificity Hierarchy
Episode 2 of 23

Learning CSS - Basic Selectors and Specificity Hierarchy

This episode dissects CSS selectors: element, class, id, attribute, and combinations between elements. You'll also understand how browsers calculate specificity weight and why more specific selectors always win.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

In episode 1 you met the simplest selector: targeting elements by tag name. Now it's time to broaden that skill. Selectors are the key to choosing which elements to style with precision, and CSS provides many ways to do it.

Episode 2 covers two big topics: the types of basic selectors and the specificity hierarchy. The two are closely related. The better you understand a selector's weight, the easier it is to predict which rule wins when two rules clash.

Why does this topic matter? Most of those confusing styling bugs — "I wrote it but nothing changed" — are rooted in a wrong understanding of specificity. Master this episode, and you'll stop memorizing tricks to beat other rules.

Types of Basic Selectors

Element, Class, and ID Selectors

The three most common selectors:

CSSbasic-selectors.css
h1 { color: navy; }
 
.btn {
  background-color: #2563eb;
  color: white;
}
 
#hero {
  padding: 24px;
  text-align: center;
}

h1 targets all elements with the tag h1; .btn targets all elements with the class btn; #hero targets the single element with the id hero. Classes are reusable, while ids should be unique within a page.

Attribute Selectors

Attribute selectors select based on the presence or value of an attribute:

CSSattribute-selectors.css
a[href] { color: #2563eb; }
 
input[type="text"] { border: 1px solid #ccc; }
 
a[href^="https"] { font-weight: bold; }
 
img[alt$=".png"] { border-radius: 8px; }

^= means "starts with", $= means "ends with", and *= means "contains". These selectors are useful for targeting external links or specific input types without adding classes.

Combinations Between Elements

CSS also allows combining elements:

CSScombinations.css
article p { line-height: 1.7; }
 
ul > li { list-style: square; }
 
h1 + p { margin-top: 4px; }
 
h1 ~ p { color: #374151; }

article p selects all p inside article (descendant); ul > li selects li elements that are direct children of ul (child); h1 + p selects a p immediately following an h1 (adjacent sibling); h1 ~ p selects all p elements after an h1 that are siblings.

The Specificity Hierarchy

How Browsers Calculate Weight

Specificity is calculated like a three-digit number:

  • Element selectors and pseudo-elements count as 0-0-1.
  • Classes, attributes, and pseudo-classes count as 0-1-0.
  • IDs count as 1-0-0.
  • Inline styles count as 1-0-0-0, higher than ids.

Example:

CSSspecificity.css
p { color: gray; }
.text { color: blue; }
#special { color: red; }

If an element <p id="special" class="text"> uses all three, it shows red. The weight of #special (1-0-0) is higher than .text (0-1-0) and p (0-0-1). A simple p selector always loses to a more specific class selector.

Tie-Breaking by Order

When two selectors have identical weight, the one written last wins:

CSSorder.css
.btn { background-color: green; }
.btn { background-color: orange; }

An element with the class btn will be orange because the second rule is written after the first. This is why CSS files should be written in a sensible order.

Avoiding Specificity Wars

Best practice is to keep specificity low and as flat as possible. Avoid stacking selectors like div#header .nav ul li a — its weight is high and makes overriding hard. Just use one clear class:

CSSrecommended.css
.nav-link {
  color: #2563eb;
}

Simple Pseudo-Classes

Pseudo-classes target specific states or positions:

CSSpseudo.css
a:hover { color: red; }
li:first-child { font-weight: bold; }
li:last-child { color: #6b7280; }

:hover applies when the cursor is over the element, :first-child selects the first element among its siblings, and :last-child the last. Episode 13 will cover pseudo-classes thoroughly.

Warning

Avoid excessive !important. It breaks through all specificity calculations and makes stylesheets hard to maintain. Use it only for extreme cases like overriding third-party library styles.

Common Mistakes and Solutions

Overly Specific Selectors

Selectors like body div.main-content .card p are nearly impossible to override without chaos. The fix: put a class directly on the target element so specificity stays low and predictable.

Forgetting to Close a Selector

One missing curly brace makes the rules that follow unreadable. Get into the habit of auto-formatting with npx prettier --write css/style.css before saving.

Closing

Key takeaways:

  • Element, class, id, and attribute selectors are the foundation of element selection.
  • Descendant, child, and sibling combinations enable contextual selection.
  • Specificity is calculated like a three-digit number; ids beat classes, classes beat elements.
  • When weights are equal, the rule written last applies.
  • Keep specificity low and avoid stacked selectors.
  • !important is for extreme cases, not daily solutions.

In the next episode, episode 3, we'll cover text, color, and background properties — how to set fonts, text color, and background images and colors with real examples. Get your style.css ready for the next exercise.