3.2: Selectors & Specificity
Master CSS selectors to target specific HTML elements, classes, and IDs for styling. Understand how specificity and the cascade determine which styles are applied when multiple rules conflict.
1. Basic Selectors
Element Selector
Targets all elements of a specific type.
/* Selects all paragraphs */
p {
color: #333;
line-height: 1.6;
}
/* Selects all headings level 2 */
h2 {
color: #2c3e50;
font-size: 32px;
}
/* Selects all links */
a {
color: #42b883;
text-decoration: none;
}
Use case: Base styling for all elements of a type
Class Selector
Targets elements with a specific class attribute.
/* Selects elements with class="button" */
.button {
background: #42b883;
color: white;
padding: 10px 20px;
border-radius: 4px;
}
/* Selects elements with class="card" */
.card {
border: 1px solid #ddd;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
HTML:
<button class="button">Click me</button>
<div class="card">Card content</div>
Best practice: Use classes for reusable styles
ID Selector
Targets a unique element with a specific ID.
/* Selects element with id="header" */
#header {
background: #2c3e50;
padding: 20px;
}
/* Selects element with id="main-content" */
#main-content {
max-width: 1200px;
margin: 0 auto;
}
HTML:
<header id="header">Site Header</header>
<main id="main-content">Main content</main>
Warning: IDs should be unique per page. Prefer classes for styling.
Universal Selector
Targets all elements.
/* Selects EVERYTHING */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Reset all elements in a container */
.container * {
margin: 0;
}
Performance note: Use sparingly - can be slow on large pages
Grouping Selectors
Apply same styles to multiple selectors.
/* Group related elements */
h1, h2, h3, h4, h5, h6 {
font-family: 'Georgia', serif;
color: #2c3e50;
}
/* Multiple classes */
.button, .link, .cta {
cursor: pointer;
transition: all 0.3s ease;
}
2. Attribute Selectors
Target elements based on attributes and their values.
Basic Attribute Selectors
/* Has attribute */
[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
/* Exact value */
[type="text"] {
border: 1px solid #ddd;
padding: 8px;
}
/* Specific class (alternative to .class) */
[class="button"] {
/* styles */
}
HTML:
<button disabled>Disabled</button>
<input type="text" placeholder="Name">
Advanced Attribute Selectors
/* Starts with */
[href^="https"] {
color: green; /* Secure links */
}
[href^="http://"] {
color: orange; /* Non-secure links */
}
/* Ends with */
[href$=".pdf"] {
background: url('pdf-icon.png') no-repeat left center;
padding-left: 20px;
}
[href$=".jpg"],
[href$=".png"] {
/* Image links */
}
/* Contains */
[href*="example.com"] {
font-weight: bold; /* Internal links */
}
[class*="col-"] {
float: left; /* Grid columns */
}
/* Word match (space-separated) */
[class~="active"] {
background: yellow;
}
/* Starts with word (dash-separated) */
[lang|="en"] {
/* Matches en, en-US, en-GB */
}
Practical examples:
/* Style external links */
a[href^="http"]:not([href*="yourdomain.com"]) {
color: blue;
}
a[href^="http"]:not([href*="yourdomain.com"])::after {
content: " ā";
}
/* Required form fields */
input[required] {
border-left: 3px solid red;
}
/* File type icons */
a[href$=".pdf"]::before {
content: "š ";
}
a[href$=".zip"]::before {
content: "š¦ ";
}
3. Combinators
Combinators select elements based on their relationship to other elements.
Descendant Combinator (space)
Selects elements inside another element (any level deep).
/* All paragraphs inside article */
article p {
line-height: 1.8;
}
/* All links inside navigation */
nav a {
color: white;
text-decoration: none;
}
/* Nested example */
.card .header .title {
font-size: 24px;
}
HTML:
<article>
<p>This paragraph is styled</p>
<div>
<p>This nested paragraph is also styled</p>
</div>
</article>
Child Combinator (>)
Selects direct children only.
/* Direct children only */
ul > li {
list-style: square;
}
/* Only direct p children of article */
article > p {
font-size: 18px;
}
Difference:
<ul>
<li>Direct child - styled ā</li>
<li>Direct child - styled ā
<ul>
<li>Nested - NOT styled ā</li>
</ul>
</li>
</ul>
/* This styles ALL li (descendant) */
ul li { color: red; }
/* This styles only DIRECT li (child) */
ul > li { color: blue; }
Adjacent Sibling Combinator (+)
Selects the immediate next sibling.
/* Paragraph immediately after h2 */
h2 + p {
font-weight: bold;
color: #555;
}
/* Image immediately after paragraph */
p + img {
margin-top: 20px;
}
HTML:
<h2>Heading</h2>
<p>This paragraph is styled (immediately after h2)</p>
<p>This paragraph is NOT styled</p>
General Sibling Combinator (~)
Selects all following siblings.
/* All paragraphs after h2 */
h2 ~ p {
margin-left: 20px;
}
/* All images after the first image */
img ~ img {
margin-left: 10px;
}
HTML:
<h2>Heading</h2>
<p>Styled ā</p>
<div>Some content</div>
<p>Also styled ā</p>
<p>Also styled ā</p>
4. Pseudo-Classes
Pseudo-classes select elements based on their state or position.
Interactive States
/* Link states (must be in this order: LVHA) */
a:link {
color: blue;
}
a:visited {
color: purple;
}
a:hover {
color: red;
text-decoration: underline;
}
a:active {
color: orange;
}
/* Focus state (keyboard navigation) */
input:focus,
button:focus {
outline: 2px solid #42b883;
outline-offset: 2px;
}
/* Disabled state */
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Enabled state */
input:enabled {
background: white;
}
Mnemonic: LoVe Hate (link, visited, hover, active)
Form Pseudo-Classes
/* Checked checkboxes/radios */
input:checked + label {
font-weight: bold;
color: green;
}
/* Valid input */
input:valid {
border-color: green;
}
/* Invalid input */
input:invalid {
border-color: red;
}
/* Required fields */
input:required {
border-left: 3px solid orange;
}
/* Optional fields */
input:optional {
border-left: 1px solid #ddd;
}
/* In range */
input[type="number"]:in-range {
border-color: green;
}
/* Out of range */
input[type="number"]:out-of-range {
border-color: red;
}
/* Placeholder shown */
input:placeholder-shown {
font-style: italic;
}
Structural Pseudo-Classes
/* First child */
li:first-child {
font-weight: bold;
}
/* Last child */
li:last-child {
border-bottom: none;
}
/* Only child */
p:only-child {
margin: 0;
}
/* nth-child examples */
li:nth-child(2) {
/* Second item */
}
li:nth-child(odd) {
/* 1st, 3rd, 5th... */
background: #f9f9f9;
}
li:nth-child(even) {
/* 2nd, 4th, 6th... */
background: white;
}
li:nth-child(3n) {
/* Every 3rd: 3, 6, 9... */
color: blue;
}
li:nth-child(3n+1) {
/* 1, 4, 7, 10... */
color: red;
}
/* First of type */
p:first-of-type {
font-size: 1.2em;
}
/* Last of type */
p:last-of-type {
margin-bottom: 0;
}
/* nth-of-type */
p:nth-of-type(2) {
/* Second paragraph */
}
Difference: nth-child vs nth-of-type
<div>
<h2>Title</h2>
<p>First paragraph</p>
<p>Second paragraph</p>
</div>
/* Selects second paragraph (3rd child) */
p:nth-child(3) { color: red; }
/* Selects second paragraph (2nd p element) */
p:nth-of-type(2) { color: blue; }
Other Useful Pseudo-Classes
/* Empty elements */
div:empty {
display: none;
}
/* Not selector */
li:not(.special) {
color: gray;
}
/* Target (URL fragment) */
:target {
background: yellow;
}
/* Root element (html) */
:root {
--primary-color: #42b883;
}
5. Pseudo-Elements
Pseudo-elements create and style parts of elements.
::before and ::after
Insert content before/after an element.
/* Add content before */
.quote::before {
content: """;
font-size: 3em;
color: #ddd;
}
.quote::after {
content: """;
font-size: 3em;
color: #ddd;
}
/* Decorative elements */
.heading::before {
content: "";
display: inline-block;
width: 4px;
height: 30px;
background: #42b883;
margin-right: 10px;
vertical-align: middle;
}
/* Icon font */
.icon-download::before {
content: "ā¬";
margin-right: 5px;
}
/* External link indicator */
a[href^="http"]::after {
content: " ā";
font-size: 0.8em;
}
Note: content property is required (can be empty content: "";)
::first-letter
Styles the first letter (drop cap effect).
.article::first-letter {
font-size: 3em;
font-weight: bold;
float: left;
line-height: 1;
margin: 5px 10px 0 0;
color: #42b883;
}
::first-line
Styles the first line of text.
.intro::first-line {
font-weight: bold;
font-size: 1.2em;
color: #2c3e50;
}
::selection
Styles selected text.
::selection {
background: #42b883;
color: white;
}
p::selection {
background: yellow;
color: black;
}
::placeholder
Styles input placeholder text.
input::placeholder {
color: #999;
font-style: italic;
opacity: 0.7;
}
Practical Examples
Custom list markers:
ul {
list-style: none;
}
ul li::before {
content: "ā ";
color: green;
font-weight: bold;
margin-right: 8px;
}
Clearfix (float clearing):
.clearfix::after {
content: "";
display: table;
clear: both;
}
Ribbon/badge:
.new-badge::after {
content: "NEW";
position: absolute;
top: 10px;
right: -10px;
background: red;
color: white;
padding: 5px 10px;
font-size: 12px;
font-weight: bold;
}
6. Specificity Deep Dive
Specificity Calculation
Specificity is calculated as: (inline, IDs, classes/attributes/pseudo-classes, elements/pseudo-elements)
Examples:
/* 0,0,0,1 - One element */
p { }
/* 0,0,1,0 - One class */
.text { }
/* 0,0,1,1 - One class + one element */
p.text { }
/* 0,0,2,0 - Two classes */
.header.active { }
/* 0,1,0,0 - One ID */
#main { }
/* 0,1,1,2 - One ID + one class + two elements */
div#main .content p { }
/* 0,0,1,0 - Attribute selector counts as class */
[type="text"] { }
/* 0,0,1,0 - Pseudo-class counts as class */
a:hover { }
/* 0,0,0,1 - Pseudo-element counts as element */
p::before { }
/* 0,0,2,1 - Attribute + pseudo-class + element */
input[type="text"]:focus { }
Specificity Comparison
Which wins?
/* 0,0,0,1 */
div { color: red; }
/* 0,0,1,0 - WINS */
.text { color: blue; }
/* 0,1,0,0 - WINS */
#intro { color: green; }
/* 0,1,1,1 - WINS (highest) */
div#intro.text { color: purple; }
Specificity Strategies
Increase specificity without changing HTML:
/* Low specificity */
.button { }
/* Higher specificity */
.header .button { }
/* Even higher */
#page .header .button { }
/* Highest (avoid) */
#page #header .button { }
Defensive CSS (high specificity):
/* Hard to override */
body div.container div.content p.text {
/* Very specific */
}
Better approach (lower specificity):
/* Easy to override */
.content-text {
/* Use specific class names */
}
() and Specificity
/* Specificity: 0,0,1,1 (class + element) */
p:not(.special) {
color: gray;
}
/* :not() doesn't add specificity, but its argument does */
/* This has same specificity as p.special */
7. Selector Performance
Fast Selectors
/* Fast - direct class/ID */
.button { }
#header { }
/* Fast - single element */
p { }
/* Fast - child combinator */
.menu > li { }
Slow Selectors
/* Slow - universal selector */
* { }
/* Slow - deep descendant */
html body div.container div.content ul li a { }
/* Slow - attribute with partial match */
[class*="col-"] { }
Best Practices
DO:
- ā Use classes for reusable styles
- ā Keep selectors short (3 levels max)
- ā Use child combinator (>) when possible
- ā Use specific class names
DON'T:
- ā Over-qualify selectors:
div.classā.class - ā Chain too many selectors
- ā Use descendant combinator excessively
- ā Rely on element selectors for layout
Good:
.card { }
.card-title { }
.card-content { }
Bad:
div.container div.row div.col-md-6 div.card h2.title { }
8. Practical Exercises
Exercise 3.2.1: Selector Challenge
Given this HTML:
<div class="container">
<h1 id="title">Main Title</h1>
<p class="intro">Introduction</p>
<ul>
<li>First</li>
<li class="active">Second</li>
<li>Third</li>
</ul>
<a href="https://example.com">External</a>
<a href="/page">Internal</a>
</div>
Write selectors to:
- Make the second list item bold
- Style external links differently
- Add a border to the first paragraph after h1
- Style odd list items
Exercise 3.2.2: Pseudo-Elements
Create a custom blockquote with:
- Large quote marks using ::before and ::after
- First letter drop cap
- Custom selection color
Exercise 3.2.3: Specificity Battle
Calculate specificity for:
#header .nav li.active { }
.container .header .nav li { }
div#header nav ul li.active { }
Which one wins?
Exercise 3.2.4: Form Styling
Style a form with:
- Red border for required fields
- Green border for valid fields
- Custom checkbox using ::before
- Focus states with ::focus
9. Knowledge Check
Question 1: What's the difference between child (>) and descendant (space) combinators?
Show answer
Child (>) selects only direct children, while descendant (space) selects all nested elements at any level.Question 2: What's the specificity of .container #main p.text?
Show answer
0,1,2,1 (1 ID + 2 classes + 1 element) = 121Question 3: Can ::before and ::after work without the content property?
Show answer
No, the content property is required (even if empty: content: "";)Question 4: What's the difference between
Show answer
:first-child selects if element is the first child of its parent. :first-of-type selects the first element of that type among siblings.Question 5: What's the correct order for link pseudo-classes?
Show answer
LVHA: :link, :visited, :hover, :active (mnemonic: LoVe HAte)Question 6: How does
Show answer
:not() itself has no specificity, but its argument does. p:not(.special) has the same specificity as p.special.10. Common Mistakes to Avoid
ā Wrong Pseudo-Element Syntax
/* Wrong - single colon (old syntax) */
.element:before {
content: "";
}
/* Correct - double colon (modern) */
.element::before {
content: "";
}
ā Over-Qualifying Selectors
/* Bad - unnecessary element */
div.container { }
/* Good - class is enough */
.container { }
ā Forgetting Content Property
/* Won't work */
.element::before {
display: block;
width: 20px;
}
/* Correct */
.element::before {
content: "";
display: block;
width: 20px;
}
ā Incorrect Link Order
/* Wrong order - hover won't work after visited */
a:hover { }
a:visited { }
/* Correct order: LVHA */
a:link { }
a:visited { }
a:hover { }
a:active { }
11. Advanced Techniques
Attribute Selector Patterns
/* Language-specific styling */
[lang="zh"] {
font-family: "Microsoft YaHei", sans-serif;
}
/* Data attributes */
[data-status="success"] {
color: green;
}
[data-priority="high"] {
font-weight: bold;
}
/* ARIA attributes */
[aria-hidden="true"] {
display: none;
}
Complex Selectors
/* First paragraph that's not in a sidebar */
.main p:first-of-type:not(.sidebar p) {
font-size: 1.2em;
}
/* Links that are not external and not in navigation */
a:not([href^="http"]):not(nav a) {
color: inherit;
}
/* Checked radio's label */
input[type="radio"]:checked + label {
font-weight: bold;
}
12. Key Takeaways
ā
Basic selectors - element, class, ID, attribute, universal
ā
Combinators - descendant (space), child (>), adjacent (+), sibling (~)
ā
Pseudo-classes -
13. Further Resources
Official Documentation:
Interactive Learning:
- CSS Diner - Selector game
- Specificity Calculator
Reference:
- CSS Tricks Almanac
- Can I Use - Browser support
Next Steps
Excellent! You now have mastery over CSS selectors and can target any element precisely.
In Lesson 3.3: Box Model & Layout Fundamentals, you'll learn how CSS calculates element dimensions, spacing, and the foundation of layout.