CSS Selectors
A selector is the part of a rule that decides which elements get the styles. Choosing good selectors is half of writing good CSS: too broad and you style things by accident, too narrow and your styles become hard to reuse.
This lesson covers the basic selectors you will use every day. The next lesson, Combinators & Pseudo-classes, shows how to combine them and select elements by their state.
Type selectors
A type selector is just an element name. It matches every element of that type on the page.
p {
line-height: 1.6;
}
button {
font: inherit;
}Type selectors are good for base styles that should apply everywhere, such as readable paragraphs or links that match your brand. They are a poor choice for one-off designs, because a rule for p hits every paragraph, including the ones in the footer and inside cards.
Class selectors
A class selector starts with a dot and matches every element whose class attribute contains that name. Classes are the workhorse of CSS: you choose the names, you can reuse them on any element, and one element can have several.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Class selectors</title>
<style>
body { font-family: system-ui, sans-serif; padding: 1rem; }
.badge {
display: inline-block;
padding: 0.2rem 0.6rem;
border-radius: 999px;
background: #e3e8ef;
font-size: 0.875rem;
}
.veg { background: #d7f5dd; color: #145a24; }
.spicy { font-weight: bold; }
</style>
</head>
<body>
<h2>Kabir's Kitchen, Lucknow</h2>
<p>Paneer tikka <span class="badge veg">Veg</span></p>
<p>Chicken biryani <span class="badge spicy">Spicy</span></p>
<p>Mirchi pakoda <span class="badge veg spicy">Veg</span></p>
</body>
</html>The last badge has three classes: badge, veg and spicy. It picks up the styles from all three rules. This "small classes that combine" approach keeps CSS short and flexible.
You can also join selectors with no space to make them more specific. span.badge means "a <span> that has the class badge", and .badge.veg means "an element that has both classes".
ID selectors
An ID selector starts with # and matches the one element with that id. An id must be unique on the page.
#main-menu {
background: #12355b;
}IDs are very useful in HTML: for link targets (href="#fees"), for connecting a <label> to an input, and for JavaScript. For styling, though, prefer classes. An ID selector is much stronger than a class in the cascade, so a style set with #main-menu is hard to override later, and you cannot reuse it on a second element. You will see exactly how much stronger in Cascade, Specificity & Inheritance.
The universal selector
The universal selector * matches every element. Its most common use is a small reset at the top of a style sheet:
*,
*::before,
*::after {
box-sizing: border-box;
}You will learn what this rule does in The Box Model. Use * for resets like this, not for visual styles such as colours.
Attribute selectors
Attribute selectors match elements by their attributes, written in square brackets. They are great for styling links and form fields without adding extra classes.
| Selector | Matches elements whose attribute... |
|---|---|
[disabled] | exists, whatever its value |
[type="email"] | equals exactly email |
[href^="https"] | starts with https |
[href$=".pdf"] | ends with .pdf |
[href*="results"] | contains results anywhere |
[lang|="hi"] | is hi or starts with hi- |
Here they are in action on a list of downloads:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Attribute selectors</title>
<style>
body { font-family: system-ui, sans-serif; padding: 1rem; }
a[href$=".pdf"] { color: #b3261e; }
a[href$=".pdf"]::after { content: " (PDF)"; font-size: 0.8em; }
a[href^="https"] { font-weight: bold; }
input[type="text"] { border: 2px solid #3a6ea5; }
</style>
</head>
<body>
<h2>Downloads</h2>
<p><a href="timetable.pdf">Exam timetable</a></p>
<p><a href="https://example.com/syllabus">Syllabus on the university site</a></p>
<p><a href="contact.html">Contact the office</a></p>
<p><input type="text" placeholder="Roll number"> <input type="password" placeholder="Password"></p>
</body>
</html>The PDF link turns red and gets a "(PDF)" label added by ::after, so students know they are about to download a file. The external link is bold. Only the text input gets the blue border; the password box keeps the default style.
Add i before the closing bracket to match regardless of letter case: a[href$=".pdf" i] also matches NOTICE.PDF.
Selector lists
When several selectors need the same declarations, separate them with commas. This is called a selector list (or grouping).
h1,
h2,
h3 {
font-family: Georgia, serif;
color: #1d3557;
}Put each selector on its own line in longer lists; it is easier to read and to edit.
Choosing the right selector
- Use type selectors for sensible defaults across the whole site.
- Use classes for almost everything else: components, variations and states.
- Use attribute selectors when the HTML already carries the information, such as
typeorhref. - Avoid IDs for styling. Keep them for links, labels and scripts.
Common mistakes
- Forgetting the dot.
badge { }looks for a<badge>element, which does not exist. Write.badge. - Adding the dot in HTML.
class=".badge"is wrong; the dot belongs only in CSS. - One bad selector in a list. If any selector in a comma list is invalid, the browser drops the whole rule.
h1, h2:hovr { }styles nothing, not evenh1. - Space where none belongs.
p .intro(with a space) means "an element with classintroinside a paragraph".p.intromeans "a paragraph with classintro".
Key points
- Type selectors (
p) match every element of that type; use them for base styles. - Class selectors (
.card) are reusable and combinable; use them for most styling. - ID selectors (
#menu) match one element and are very strong; avoid them for styling. - The universal selector
*matches everything and suits small resets. - Attribute selectors such as
[href$=".pdf"]match elements by their attributes. - A selector list (
h1, h2) shares declarations, but one invalid selector drops the whole rule.
Exercise
Write a page with a short price list for a mobile shop: three products, each in a paragraph. Give every price a price class. Give one product an extra sale class so that it shows in red. Then style any <a> that links to a .pdf file in bold, and add a link to price-list.pdf to test it.
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Isha Mobiles</title>
<style>
.price { font-weight: 600; color: #1d3557; }
.price.sale { color: #c62828; }
a[href$=".pdf"] { font-weight: bold; }
</style>
</head>
<body>
<h1>Isha Mobiles, Pune</h1>
<p>Phone cover: <span class="price">₹299</span></p>
<p>Fast charger: <span class="price sale">₹649</span></p>
<p>Earphones: <span class="price">₹1,299</span></p>
<p><a href="price-list.pdf">Download the full price list</a></p>
</body>
</html>.price.sale only matches elements that carry both classes, so the other prices keep the blue colour.
Quick Quiz
1. Which selector matches every element with class="card"?
A dot selects by class. #card selects by ID and card looks for a <card> element.
2. Why should you prefer classes over IDs for styling?
ID selectors are much stronger in the cascade and must be unique, which makes styles rigid.
3. What does a[href$=".pdf"] match?
$= means "ends with". ^= is "starts with" and *= is "contains".
4. What happens to h1, h2:hovr { color: red; }?
In a normal selector list, one invalid selector makes the browser ignore the entire rule.
Learn CSS with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
