CSS Series —Post 02: Selectors
Selectors: How CSS Knows
What to Style
You wrote the rule. But how does CSS know which element to apply it to? That's the selector's job — and once you understand it, you're in control.
💬 "Why Did That Style Every Single Thing?"
You wanted to change the color of one heading. So you wrote color: hotpink; — and suddenly every heading on the page turned pink. Not just the one you meant. All of them.
Or the opposite happens: you write a perfectly good CSS rule and nothing changes. You refresh. You triple-check the spelling. Still nothing. The style is just... ignored.
Both problems come down to the same thing: you don't yet control what CSS is targeting. That's what selectors are for. They're the precision tool that tells CSS exactly — and only — what to style.
A selector is a targeting mechanism. Before CSS applies any style, it has to find the right element first. Selectors are how you aim. The more precisely you can aim, the more control you have.
🧠 The Concept: Targeting With Precision
Think about how you'd describe someone in a crowd. "The person" is vague — there are hundreds. "The person in the pink jacket" narrows it down. "The person in the pink jacket in the third row" is exact.
CSS selectors work the same way. Element selectors grab everyone wearing the same tag. Class selectors grab everyone wearing a specific badge you chose. ID selectors grab one single specific person by name. The more specific your selector, the more precise your styling.
There's a quick-reference table of every selector in this post at the bottom of this section. But first — let's walk through each one so you actually understand what you're using.
🧱 The Selectors, One by One
1. Element Selectors — Style by Tag Name
The simplest selector. You write the HTML tag name, and CSS styles every single element with that tag on the page.
/* Targets EVERY <p> element on the page */
p {
color: #9595a8;
line-height: 1.8;
}
/* Targets EVERY <h2> element on the page */
h2 {
font-size: 28px;
font-weight: 700;
}
/* Great for base styles. Risky if you need variations. */Element selectors are useful for setting default base styles — the starting point that applies everywhere. But the moment you need one paragraph to look different from another? Element selectors can't do that. You need something more targeted.
2. Class Selectors — Style by Label
Classes are where CSS gets powerful. You add a class attribute to any HTML element, then target it in CSS with a . prefix. One class can be used on as many elements as you want, and one element can have multiple classes.
<!-- HTML: add a class attribute to any element -->
<div class="card">
<h3 class="card-title">Post Title</h3>
<p class="card-text">Some description here.</p>
</div>
<!-- You can reuse the same class on multiple elements -->
<div class="card">
<h3 class="card-title">Another Post</h3>
<p class="card-text">Another description.</p>
</div>/* .classname — the dot targets anything with that class */
.card {
background: #12121a;
border-radius: 12px;
padding: 24px;
border: 1px solid rgba(255,255,255,0.08);
}
.card-title {
color: #ffffff;
font-size: 20px;
margin-bottom: 8px;
}
.card-text {
color: #9595a8;
font-size: 15px;
}
/* Both card divs get identical styling. Write once, use everywhere. */An element can carry more than one class at a time. Separate them with a space: class="card card-featured". Both .card and .card-featured styles will apply. This is how you layer styles without writing duplicate CSS.
3. ID Selectors — Style One Unique Element
The # selector targets a single element by its id attribute. An ID is supposed to be unique — only one element per page should have a given ID. In CSS, you prefix the ID name with a #.
<!-- HTML: id attribute, must be unique on the page -->
<section id="hero">
<h1>Welcome to my site</h1>
</section>
/* CSS: # prefix targets the element with that id */
#hero {
background: linear-gradient(135deg, #0a0a0f, #1a1a2e);
padding: 80px 24px;
text-align: center;
}IDs have very high specificity — which means they override class styles in ways that are hard to predict and frustrating to debug. They also can't be reused, so they don't scale. Most experienced developers use IDs for JavaScript targeting or anchor links, and use classes for all styling. Future you will thank present you for this habit.
4. Descendant Selectors — Style by Context
Sometimes you don't want to style all p tags — you want to style a p only when it lives inside a specific parent. That's the descendant selector: two selectors separated by a space.
/* Space between selectors = "inside" relationship */
/* Targets <p> only when inside .card */
.card p {
color: #9595a8;
font-size: 14px;
}
/* Targets <a> only when inside .nav */
.nav a {
color: #e0e0e8;
text-decoration: none;
}
/* Paragraphs outside .card are unaffected.
Links outside .nav are unaffected.
Context is everything. */5. Pseudo-class Selectors — Style by State
Elements aren't always in a static state. A button can be hovered. An input can be focused. A link can be visited. Pseudo-classes let you style elements based on what state they're in, using a colon : after the selector.
/* :hover — triggers when the user mouses over an element */
.card:hover {
border-color: rgba(255,105,180,0.4);
transform: translateY(-4px);
box-shadow: 0 12px 32px rgba(255,105,180,0.1);
}
/* :focus — triggers when an input is selected/active */
.input-field:focus {
outline: none;
border-color: #b44aff;
box-shadow: 0 0 0 3px rgba(180,74,255,0.2);
}
/* :first-child — targets the first child of its parent */
.nav-item:first-child {
font-weight: 700;
}The most important one to know right now is :hover. It's the difference between a flat, lifeless page and one that responds when people interact with it. Hover it out — hover those cards below to see it live:
The Box Model
Finally understand why spacing works the way it does.
Flexbox Layout
Stop guessing alignment. Start building with logic.
That lift and glow on hover? That's :hover with transform and box-shadow. Zero JavaScript. Just CSS knowing what state the element is in.
Quick Reference: All Five Selectors
| Selector | Syntax | Targets | Use It For | Frequency |
|---|---|---|---|---|
| Element | p { } | Every <p> on the page | Base / reset styles | common |
| Class | .card { } | Any element with class="card" | Everything. Reusable styles. | use most |
| ID | #hero { } | One element with id="hero" | Unique page sections | rarely |
| Descendant | .card p { } | <p> inside .card only | Context-specific styles | common |
| Pseudo | .btn:hover { } | Element in a specific state | Interaction + feedback | common |
Classes for almost everything. Element selectors for base defaults. Pseudo-classes whenever you want interactivity. Save IDs for JavaScript hooks and anchor links — not styling. If you follow this, your CSS will stay clean and maintainable far longer than you'd expect.
Mini Build: A Styled Card Component
You're going to build a card component using only class selectors — no IDs, no inline styles. One card, styled from scratch, with a hover state. This is the kind of component you'll build on every real project.
Set up your HTML. Add this card structure to your index.html. Notice every element has a class — that's intentional. You name the pieces, CSS styles them.
<div class="card">
<span class="card-tag">Tutorial</span>
<h3 class="card-title">The Box Model</h3>
<p class="card-text">
Finally understand why spacing works the way it does.
</p>
<a href="#" class="card-link">Read More →</a>
</div>Style each class in CSS. Open styles.css and write rules for each class. You're targeting by name — no guessing which element you'll hit.
.card {
background: #12121a;
border-radius: 12px;
padding: 28px;
border: 1px solid rgba(255,255,255,0.07);
max-width: 320px;
transition: all 0.3s ease; /* smooth the hover */
}
.card-tag {
font-size: 12px;
color: #ff69b4;
letter-spacing: 1px;
text-transform: uppercase;
display: block;
margin-bottom: 10px;
}
.card-title {
color: #ffffff;
font-size: 20px;
margin-bottom: 10px;
}
.card-text {
color: #9595a8;
font-size: 14px;
line-height: 1.7;
margin-bottom: 18px;
}
.card-link {
color: #b44aff;
text-decoration: none;
font-size: 14px;
font-weight: 600;
}
/* Step 03: hover state — watch the card react */
.card:hover {
border-color: rgba(255,105,180,0.35);
transform: translateY(-4px);
box-shadow: 0 16px 40px rgba(0,0,0,0.4);
}
.card-link:hover {
color: #ff69b4;
}Open in browser and hover. Your card should lift when you mouse over it. If it's not working, check that transition: all 0.3s ease is on .card — that's what makes the movement smooth instead of a hard jump.
Duplicate and customize. Copy the card HTML twice more. Change the card-tag text, title, and description. All three cards share the same CSS classes — same styles, zero extra work. That's the power of classes.
You built a reusable component. Not a one-off styled element — an actual reusable piece of UI. You can drop that card anywhere on your site and it'll look exactly right every time. That's how real products are built.
💛 You Can Aim Now. That Changes Everything.
Before this post, CSS felt like it either hit everything or nothing. Now you have five targeting tools in your hands — and you know when to use each one.
Here's what you walked away with today:
- Element selectors hit every matching tag — great for base styles
- Class selectors are your main tool — reusable, flexible, scalable
- ID selectors are unique and high-specificity — save them for JS, not styling
- Descendant selectors let you style by context, not just by name
- Pseudo-classes like :hover add interactivity with zero JavaScript
- You built an actual reusable card component from scratch
Next up: the Box Model — the layout concept that explains every weird spacing problem you've ever had. If selectors are how CSS aims, the Box Model is how CSS decides how much space everything takes up.
Okay I have to tell on myself. In my early projects, I used IDs for everything. Every single div had an ID. #mainWrapper. #contentArea. #topHeading. I thought I was being organized.
Then I tried to build a second card that looked like the first one. I'd have to create a whole new ID, copy all the CSS, and then maintain both of them separately. When I wanted to change the style, I was editing in six places at once. My stylesheet became this giant mess of nearly-identical rules that I was terrified to touch.
The day I switched to classes and actually understood why they existed — my CSS cut in half. My files got clean. Changes started making sense. I stopped being scared of my own stylesheet.
If you're currently using IDs for styling: you're not doing it wrong, you're just doing it the hard way. Classes are the upgrade. Take it.