Table of Contents
- Introduction to CSS Selectors
- Basic Selectors
- Combinators
- Attribute Selectors
- Pseudo-classes
- Pseudo-elements
- Advanced Selectors
- CSS Specificity
- The Cascade
- Inheritance
- Selector Performance
- Modern Selectors (CSS3+)
- Practical Examples
- Best Practices
- Selector Quiz
Introduction to CSS Selectors
CSS selectors are patterns used to select and style HTML elements. They are the bridge between your HTML structure and your CSS styling rules. Understanding selectors and specificity is crucial for writing maintainable, efficient, and bug-free CSS.
What are Selectors?
/* Basic selector structure */
selector {
property: value;
}
/* Example */
h1 {
color: blue;
font-size: 24px;
}
Why Selectors Matter
- Precision: Target exactly the elements you want to style
- Efficiency: Write less code by grouping elements
- Maintainability: Make your CSS easier to update
- Specificity Control: Manage which styles take precedence
- Reusability: Create reusable style patterns
Basic Selectors
Universal Selector (*)
/* Selects all elements */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Selects all elements inside a specific container */
.container * {
font-family: Arial, sans-serif;
}
/* Selects all elements that are direct children */
.parent > * {
margin-bottom: 10px;
}
/* Use with caution - can be performance intensive */
* {
outline: 1px solid red; /* Debugging only! */
}
Type/Element Selector
/* Selects all elements of a given type */
h1 {
color: #333;
font-size: 2em;
}
p {
line-height: 1.6;
margin-bottom: 1em;
}
div {
background-color: #f5f5f5;
padding: 20px;
}
/* Grouping multiple type selectors */
h1, h2, h3 {
font-family: 'Helvetica', sans-serif;
font-weight: bold;
}
/* Nested type selectors */
article p {
text-indent: 20px;
}
Class Selector (.)
/* Selects all elements with a specific class */
.highlight {
background-color: yellow;
padding: 2px 5px;
}
.button {
display: inline-block;
padding: 10px 20px;
border-radius: 4px;
text-decoration: none;
}
/* Element specific class */
p.intro {
font-size: 1.2em;
font-weight: 300;
}
/* Multiple classes on one element */
.button.primary {
background-color: #007bff;
color: white;
}
.button.large {
font-size: 1.2em;
padding: 15px 30px;
}
/* Class combinations */
.card.featured {
border: 2px solid gold;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
ID Selector (#)
/* Selects a single element with a specific ID */
#header {
background-color: #333;
color: white;
padding: 20px;
}
#main-content {
max-width: 1200px;
margin: 0 auto;
}
#footer {
margin-top: 50px;
border-top: 1px solid #ccc;
}
/* IDs should be unique - avoid overusing */
#logo {
width: 200px;
height: auto;
}
/* Combining ID with element (usually unnecessary) */
div#sidebar {
width: 300px;
}
Class vs ID Comparison
/* Class - reusable */
.card { } /* Can be used many times */
.button { } /* Can be used many times */
.error-message { } /* Can be used many times */
/* ID - unique */
#header { } /* Only one per page */
#main-nav { } /* Only one per page */
#submit-button { } /* Only one per page */
/* Specificity comparison */
.card { } /* Specificity: 0,0,1,0 */
#header { } /* Specificity: 0,1,0,0 (wins over class) */
Combinators
Descendant Combinator (space)
/* Selects elements inside other elements */
article p {
line-height: 1.6;
color: #333;
}
/* Multiple levels of nesting */
div .content .article .text {
font-size: 14px;
}
/* Practical examples */
.nav-menu li a {
text-decoration: none;
color: #333;
}
.blog-post .meta .date {
font-style: italic;
color: #666;
}
/* Can be overly specific - use with care */
body div .container .row .col p {
margin: 0; /* Too specific! */
}
Child Combinator (>)
/* Selects only direct children */
ul > li {
list-style-type: square;
}
.container > p {
margin: 10px 0;
}
/* Doesn't select grandchildren */
nav > ul > li > a {
color: blue; /* Only top-level menu items */
}
/* Multiple child combinators */
body > main > section > article {
padding: 20px;
}
/* Practical example - dropdown menu */
.nav > li {
position: relative;
}
.nav > li > ul {
display: none;
position: absolute;
}
.nav > li:hover > ul {
display: block;
}
Adjacent Sibling Combinator (+)
/* Selects element immediately after another */
h2 + p {
font-weight: bold;
margin-top: 0;
}
/* Practical examples */
label + input {
margin-top: 5px;
}
.error + .help-text {
color: red;
display: block;
}
/* Multiple adjacent */
h1 + p + p {
color: #666;
}
/* Form styling */
input + button {
margin-left: 10px;
}
General Sibling Combinator (~)
/* Selects all siblings after an element */
h2 ~ p {
color: #666;
font-size: 0.9em;
}
/* Practical examples */
input:checked ~ .toggle-content {
display: block;
}
.error ~ .field {
border-color: red;
}
/* Styling all siblings */
.title ~ * {
margin-left: 20px;
}
/* Tab interface */
.tab.active ~ .tab-content {
display: none;
}
Combinator Combinations
/* Complex combinations */
nav > ul > li > a:hover + .dropdown {
display: block;
}
/* Multiple combinators in one selector */
section.intro > h1 + p + p ~ blockquote {
font-style: italic;
}
/* Practical layout example */
.sidebar > h3:first-child + p {
font-size: 1.2em;
}
.grid > .row > .col + .col {
border-left: 1px solid #ccc;
}
Attribute Selectors
Basic Attribute Selectors
/* Elements with a specific attribute */
[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
[hidden] {
display: none;
}
/* Elements with exact attribute value */
[type="text"] {
border: 1px solid #ccc;
padding: 5px;
}
[target="_blank"] {
background: url('external-icon.png') no-repeat right center;
padding-right: 20px;
}
/* Multiple attributes */
[type="email"][required] {
border-left: 3px solid red;
}
[data-role="button"][aria-pressed="true"] {
background-color: #007bff;
color: white;
}
Attribute Selectors with Values
/* Starts with (^=) */
[href^="https"] {
color: green;
}
[class^="col-"] {
float: left;
padding: 0 15px;
}
[data-category^="video"]::before {
content: "🎬 ";
}
/* Ends with ($=) */
[src$=".jpg"] {
border-radius: 5px;
}
[href$=".pdf"] {
background: url('pdf-icon.png') no-repeat left center;
padding-left: 20px;
}
[class$="-dark"] {
background-color: #333;
color: white;
}
/* Contains (*=) */
[href*="example.com"] {
color: #666;
}
[class*="btn-"] {
display: inline-block;
padding: 10px 20px;
}
[data-tooltip*="important"] {
font-weight: bold;
}
Advanced Attribute Selectors
/* Space separated list (~=) */
[rel~="external"] {
background: url('external.png') no-repeat;
}
[class~="featured"] {
border: 2px solid gold;
}
/* Hyphen separated list (|=) */
[lang|="en"] {
font-family: 'Helvetica', sans-serif;
}
[data-country|="us"] {
background: url('us-flag.png') no-repeat;
}
/* Case-insensitivity (i flag) */
[type="email" i] { /* Matches email, EMAIL, Email */
border-color: blue;
}
[class*="btn" i] { /* Case-insensitive contains */
text-transform: uppercase;
}
Practical Attribute Selector Examples
/* Form styling */
input[type="text"],
input[type="email"],
input[type="password"] {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
input[type="checkbox"]:checked + label {
font-weight: bold;
}
input[type="number"][min="0"][max="100"] {
background-color: #f0f0f0;
}
/* Link styling */
a[href^="http"]:not([href*="mysite.com"]) {
color: #0077cc;
}
a[href$=".pdf"]::after {
content: " (PDF)";
font-size: 0.8em;
color: #666;
}
/* Data attributes */
[data-status="success"] {
background-color: #d4edda;
color: #155724;
}
[data-status="error"] {
background-color: #f8d7da;
color: #721c24;
}
[data-count]::before {
content: attr(data-count) " items";
font-weight: bold;
}
Pseudo-classes
Dynamic Pseudo-classes
/* Link states */
a:link {
color: #0066cc;
text-decoration: none;
}
a:visited {
color: #663399;
}
a:hover {
text-decoration: underline;
background-color: #f0f0f0;
}
a:active {
color: #ff0000;
}
/* Focus states */
input:focus {
outline: 3px solid #4A90E2;
border-color: transparent;
}
button:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
}
/* User action pseudo-classes */
button:hover {
background-color: #0056b3;
transform: translateY(-1px);
}
button:active {
transform: translateY(0);
}
/* Form states */
input:enabled {
background-color: white;
}
input:disabled {
background-color: #f5f5f5;
cursor: not-allowed;
}
input:read-only {
background-color: #eee;
}
input:required {
border-left: 3px solid red;
}
input:optional {
border-left: 3px solid #ccc;
}
Structural Pseudo-classes
/* First and last */
li:first-child {
border-top: none;
}
li:last-child {
border-bottom: none;
}
p:first-of-type {
font-size: 1.2em;
}
p:last-of-type {
margin-bottom: 0;
}
/* nth-child patterns */
li:nth-child(2) {
background-color: #f0f0f0;
}
li:nth-child(even) {
background-color: #f9f9f9;
}
li:nth-child(odd) {
background-color: white;
}
li:nth-child(3n+1) {
font-weight: bold;
}
li:nth-child(4n+2) {
margin-left: 20px;
}
/* nth-last-child */
li:nth-last-child(2) {
border-bottom: 2px solid #ccc;
}
li:nth-last-child(-n+3) {
color: red;
}
/* nth-of-type */
p:nth-of-type(2) {
font-style: italic;
}
article:nth-of-type(odd) {
background-color: #f5f5f5;
}
nth-child Formulas
/* Common nth-child patterns */
li:nth-child(1) { } /* First element */
li:nth-child(2) { } /* Second element */
li:nth-child(3) { } /* Third element */
li:nth-child(n) { } /* All elements */
li:nth-child(2n) { } /* Even (2,4,6...) */
li:nth-child(2n+1) { } /* Odd (1,3,5...) */
li:nth-child(3n) { } /* Every third (3,6,9...) */
li:nth-child(3n+1) { } /* First of every three */
li:nth-child(3n+2) { } /* Second of every three */
li:nth-child(-n+3) { } /* First 3 elements */
li:nth-child(n+4) { } /* All except first 3 */
li:nth-child(n+4):nth-child(-n+7) { } /* 4-7 only */
/* Table striping */
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* Complex patterns */
li:nth-child(5n+3):not(:last-child) {
border-bottom: 2px solid red;
}
UI State Pseudo-classes
/* Checkbox and radio states */
input[type="checkbox"]:checked + label {
color: green;
font-weight: bold;
}
input[type="radio"]:checked + label {
background-color: #e0e0e0;
}
/* Range input */
input[type="range"]:in-range {
background-color: green;
}
input[type="range"]:out-of-range {
background-color: red;
}
/* Validation states */
input:valid {
border-color: #28a745;
}
input:invalid {
border-color: #dc3545;
}
input:in-range {
background-color: #d4edda;
}
input:out-of-range {
background-color: #f8d7da;
}
input:placeholder-shown {
background-color: #f9f9f9;
}
Location Pseudo-classes
/* Target pseudo-class */
:target {
background-color: yellow;
border-left: 4px solid #007bff;
padding-left: 10px;
}
/* Scope pseudo-class */
:scope {
background-color: #f0f0f0;
}
/* Practical example - section highlighting */
section:target::before {
content: "►";
color: #007bff;
margin-right: 5px;
}
Language Pseudo-classes
/* Language selection */
:lang(en) {
quotes: "“" "”";
}
:lang(fr) {
quotes: "«" "»";
}
:lang(de) {
quotes: "„" "“";
}
p:lang(en) {
font-family: 'Helvetica', sans-serif;
}
Pseudo-elements
Basic Pseudo-elements
/* First line and first letter */
p::first-line {
font-weight: bold;
font-size: 1.2em;
}
p::first-letter {
font-size: 3em;
float: left;
margin-right: 5px;
color: #007bff;
}
/* Selection styling */
::selection {
background-color: #007bff;
color: white;
}
::-moz-selection {
background-color: #007bff;
color: white;
}
Before and After
/* Basic before/after */
.quote::before {
content: "“";
font-size: 2em;
color: #ccc;
}
.quote::after {
content: "”";
font-size: 2em;
color: #ccc;
}
/* Decorative elements */
.divider::before,
.divider::after {
content: "";
display: inline-block;
width: 50px;
height: 1px;
background-color: #ccc;
margin: 0 10px;
vertical-align: middle;
}
/* Clearfix hack */
.clearfix::after {
content: "";
display: table;
clear: both;
}
/* Tooltips */
[data-tooltip] {
position: relative;
}
[data-tooltip]::before {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
padding: 5px 10px;
background-color: #333;
color: white;
border-radius: 4px;
font-size: 14px;
white-space: nowrap;
display: none;
}
[data-tooltip]:hover::before {
display: block;
}
Marker and Placeholder
/* List marker styling */
::marker {
color: #007bff;
font-size: 1.2em;
}
li::marker {
content: "▶";
}
/* Placeholder styling */
::placeholder {
color: #999;
font-style: italic;
}
input::placeholder {
opacity: 0.7;
}
textarea::placeholder {
font-family: inherit;
}
Backdrop and File Selector
/* Dialog backdrop */
dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(3px);
}
/* File input button */
input[type="file"]::file-selector-button {
background-color: #007bff;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
input[type="file"]::file-selector-button:hover {
background-color: #0056b3;
}
Advanced Selectors
:not() Negation Pseudo-class
/* Simple negation */
input:not([type="submit"]) {
border: 1px solid #ccc;
}
p:not(.intro) {
color: #666;
}
/* Multiple negations */
:not(.hidden):not([disabled]) {
opacity: 1;
}
/* Complex negation */
ul > li:not(:first-child):not(:last-child) {
background-color: #f0f0f0;
}
/* :not with structural pseudo-classes */
tr:not(:first-child):not(:last-child) {
background-color: #f9f9f9;
}
:is() and :where()
/* :is() - matches any of the selectors */
:is(section, article, aside) h1 {
font-size: 1.5em;
}
/* Instead of */
section h1, article h1, aside h1 {
font-size: 1.5em;
}
/* Nested :is() */
:is(header, footer) :is(nav, .menu) a {
color: white;
}
/* :where() - same as :is but with zero specificity */
:where(header, footer) p {
color: #666; /* Specificity: 0,0,1,0 */
}
/* Compare with :is() */
:is(header, footer) p {
color: #333; /* Specificity: 0,0,1,1 */
}
:has() Parent Selector
/* Select parent elements based on children */
article:has(h2) {
border-left: 3px solid #007bff;
}
figure:has(figcaption) {
margin-bottom: 30px;
}
/* Contains specific element */
.card:has(img) {
padding: 0;
}
.card:has(.button) {
background-color: #f9f9f9;
}
/* Does not contain */
.card:not(:has(img)) {
min-height: 200px;
}
/* Contains text matching pattern */
div:has(> p:first-child:empty) {
display: none;
}
/* Complex conditions */
form:has(input:invalid) {
border: 2px solid red;
}
:empty and :blank
/* Empty elements */
p:empty {
display: none;
}
li:empty::before {
content: "Empty item";
color: #999;
font-style: italic;
}
/* Elements with only whitespace */
:blank {
background-color: #f0f0f0;
}
:root and :scope
/* Root element (html) */
:root {
--primary-color: #007bff;
--font-family: 'Helvetica', sans-serif;
font-size: 16px;
}
/* Scope for scoped CSS */
:scope {
background-color: #f5f5f5;
}
CSS Specificity
Understanding Specificity
Specificity determines which CSS rule is applied when multiple rules target the same element. It's calculated as a four-part value: (inline, IDs, classes, elements)
/* Specificity calculation examples */
/* Specificity: 0,0,0,1 */
p {
color: blue;
}
/* Specificity: 0,0,1,0 */
.text {
color: green;
}
/* Specificity: 0,1,0,0 */
#title {
color: red;
}
/* Specificity: 0,0,1,1 */
p.text {
color: purple;
}
/* Specificity: 0,1,1,1 */
#title.text {
color: orange;
}
/* Specificity: 1,0,0,0 */
style="color: pink;" /* Inline styles win */
Specificity Hierarchy
/* From lowest to highest specificity */
/* Level 1: Element selectors */
div { } /* 0,0,0,1 */
p { } /* 0,0,0,1 */
h1 { } /* 0,0,0,1 */
/* Level 2: Class selectors */
.card { } /* 0,0,1,0 */
.button { } /* 0,0,1,0 */
.nav-menu { } /* 0,0,1,0 */
/* Level 3: ID selectors */
#header { } /* 0,1,0,0 */
#sidebar { } /* 0,1,0,0 */
#main-content { } /* 0,1,0,0 */
/* Level 4: Inline styles */
<div style="color: red;"> /* 1,0,0,0 */
/* Level 5: !important */
p {
color: red !important; /* Overrides everything (use sparingly) */
}
Specificity Calculator
/* Let's calculate specificity for complex selectors */
/* Example 1: 0,0,2,3 */
.nav .menu ul li a:hover {
/* Elements: ul, li, a (3) */
/* Classes: .nav, .menu (2) */
/* Pseudo-class: :hover (counts as class) */
/* Total: 0,0,3,3 */
}
/* Example 2: 0,1,2,1 */
#sidebar .widget h3 + p {
/* ID: #sidebar (1) */
/* Classes: .widget (1) */
/* Elements: h3, p (2) */
/* Combinators: + (don't count) */
/* Total: 0,1,1,2 */
}
/* Example 3: 0,0,1,2 */
input[type="text"]:focus {
/* Elements: input (1) */
/* Attribute: [type="text"] (counts as class) */
/* Pseudo-class: :focus (counts as class) */
/* Total: 0,0,2,1 */
}
Specificity Examples Table
| Selector | Specificity | Calculation |
|---|---|---|
* | 0,0,0,0 | Universal selector |
p | 0,0,0,1 | 1 element |
.text | 0,0,1,0 | 1 class |
p.text | 0,0,1,1 | 1 element + 1 class |
#title | 0,1,0,0 | 1 ID |
#title.text | 0,1,1,0 | 1 ID + 1 class |
#title p.text | 0,1,1,1 | 1 ID + 1 element + 1 class |
style="color: red;" | 1,0,0,0 | Inline style |
p !important | Infinite | Overrides all |
Specificity Wars
<div class="container" id="main"> <p class="text highlight" id="intro">Hello World</p> </div>
/* Which color wins? */
/* Specificity: 0,0,1,1 */
p.highlight {
color: red;
}
/* Specificity: 0,0,2,1 */
p.text.highlight {
color: blue; /* This wins - higher class count */
}
/* Specificity: 0,1,0,1 */
#intro {
color: green; /* This actually wins - ID over classes */
}
/* Specificity: 0,1,1,1 */
#intro.highlight {
color: purple; /* Highest specificity */
}
/* Result: purple wins */
The Cascade
Cascade Order
/* The cascade determines which rule applies when specificity is equal */
/* Step 1: Importance */
p {
color: red !important; /* Wins over all normal declarations */
}
/* Step 2: Origin */
/* User !important > Author !important > Author > User > Browser */
/* Step 3: Specificity (covered above) */
/* Step 4: Source Order (last one wins) */
p {
color: red;
}
p {
color: blue; /* Blue wins - comes later */
}
Source Order Examples
/* Source order matters when specificity is equal */
/* Example 1 - Last wins */
.button {
background-color: red;
}
.button {
background-color: blue; /* Blue wins */
}
/* Example 2 - Order in HTML */
<style>
p { color: red; }
</style>
<style>
p { color: blue; } /* Blue wins */
</style>
/* Example 3 - Linked stylesheets */
/* styles1.css */
p { color: red; }
/* styles2.css */
p { color: blue; } /* Blue wins if styles2.css is linked after */
Cascade Layers
/* Modern cascade layering */
@layer reset, base, components, utilities;
@layer reset {
* {
margin: 0;
padding: 0;
}
}
@layer base {
body {
font-family: sans-serif;
line-height: 1.6;
}
}
@layer components {
.card {
padding: 20px;
border-radius: 4px;
}
}
@layer utilities {
.text-center {
text-align: center;
}
}
/* Later layers override earlier layers */
@layer base {
body {
font-family: serif; /* Overrides previous base layer */
}
}
Inheritance
Inherited Properties
/* Properties that inherit by default */
body {
color: #333; /* Inherited */
font-family: Arial; /* Inherited */
font-size: 16px; /* Inherited */
line-height: 1.5; /* Inherited */
text-align: left; /* Inherited */
visibility: visible; /* Inherited */
}
/* Child elements inherit these values */
p {
/* Inherits color, font-family, etc. from body */
}
/* Override inheritance */
p {
color: red; /* Overrides inherited color */
}
Non-inherited Properties
/* Properties that don't inherit */
div {
border: 1px solid black; /* Not inherited */
margin: 10px; /* Not inherited */
padding: 10px; /* Not inherited */
background-color: #f0f0f0; /* Not inherited */
width: 100%; /* Not inherited */
height: auto; /* Not inherited */
position: relative; /* Not inherited */
}
/* Child elements start with default values */
div p {
/* border, margin, etc. are not inherited from parent */
}
Inheritance Control
/* inherit - force inheritance */
.child {
border: inherit; /* Forces border inheritance */
margin: inherit; /* Forces margin inheritance */
}
/* initial - use browser default */
.reset {
color: initial; /* Back to browser default */
display: initial; /* Back to browser default */
}
/* unset - inherit if normally inherited, otherwise initial */
.revert {
color: unset; /* Inherits from parent (color normally inherits) */
border: unset; /* Initial value (border doesn't inherit) */
}
/* revert - revert to user agent styles */
.custom {
color: revert; /* Back to browser default */
}
/* Practical example - resetting nested elements */
.nested * {
all: revert; /* Revert all properties */
}
Selector Performance
Efficient vs Inefficient Selectors
/* ❌ Inefficient selectors (slow) */
* {
box-sizing: border-box; /* Universal selector - slow */
}
html body div .content p {
color: red; /* Overly specific, slow matching */
}
div > p:first-child {
margin: 0; /* Complex pseudo-class - slower */
}
/* ✅ Efficient selectors (fast) */
.class {
property: value; /* Class selectors - fast */
}
id {
property: value; /* ID selectors - fastest */
}
p {
property: value; /* Element selectors - fast */
}
[type="text"] {
property: value; /* Attribute selectors - moderate */
}
Performance Guidelines
/* Good practices for selector performance */
/* 1. Use classes instead of long descendant chains */
/* ❌ Bad */
.container .row .col .module .title {
font-size: 20px;
}
/* ✅ Good */
.module-title {
font-size: 20px;
}
/* 2. Be as specific as necessary, but not more */
/* ❌ Too specific */
html body div#main article.section p {
margin: 10px;
}
/* ✅ Just right */
.section p {
margin: 10px;
}
/* 3. Avoid universal selectors in key areas */
/* ❌ Bad */
.nav * {
margin: 0;
}
/* ✅ Good */
.nav > li {
margin: 0;
}
/* 4. Use child selectors when possible */
/* Slower - checks all descendants */
.nav li a {
color: blue;
}
/* Faster - only checks direct children */
.nav > li > a {
color: blue;
}
Modern Selectors (CSS3+)
CSS3 Selectors Overview
/* Attribute selectors (CSS3) */
[attr^="value"] { } /* Starts with */
[attr$="value"] { } /* Ends with */
[attr*="value"] { } /* Contains */
/* Structural pseudo-classes */
:nth-child(n) { }
:nth-last-child(n) { }
:nth-of-type(n) { }
:last-child { }
:first-of-type { }
:only-child { }
:empty { }
/* UI element states */
:enabled { }
:disabled { }
:checked { }
:indeterminate { }
:default { }
:valid { }
:invalid { }
:in-range { }
:out-of-range { }
:required { }
:optional { }
:read-only { }
:read-write { }
/* Other pseudo-classes */
:not(selector) { }
:target { }
:lang(language) { }
:root { }
CSS4 Selectors (Level 4)
/* Level 4 selectors (modern browsers) */
/* :has() - parent selector */
.parent:has(> .child) { }
div:has(+ p) { }
/* :is() - matches any */
:is(section, article, aside) h1 { }
/* :where() - zero specificity */
:where(header, footer) p { }
/* :focus-visible */
input:focus-visible {
outline: 2px solid blue;
}
/* :focus-within */
form:focus-within {
border-color: blue;
}
/* :placeholder-shown */
input:placeholder-shown {
background-color: #f0f0f0;
}
/* :blank */
:blank {
display: none;
}
/* :dir() - direction */
:dir(ltr) {
text-align: left;
}
:dir(rtl) {
text-align: right;
}
Practical Examples
Example 1: Navigation Menu
<nav class="navbar"> <ul class="nav-menu"> <li><a href="#" class="active">Home</a></li> <li><a href="#">About</a> <ul class="dropdown"> <li><a href="#">Team</a></li> <li><a href="#">History</a></li> <li><a href="#">Careers</a></li> </ul> </li> <li><a href="#">Services</a></li> <li><a href="#">Contact</a></li> </ul> </nav>
/* Navigation styling with selectors */
.navbar {
background-color: #333;
padding: 10px 0;
}
.nav-menu {
list-style: none;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
position: relative;
}
/* Direct children of nav-menu */
.nav-menu > li {
position: relative;
margin: 0 15px;
}
/* First level links */
.nav-menu > li > a {
color: white;
text-decoration: none;
padding: 10px 15px;
display: block;
transition: background-color 0.3s;
}
.nav-menu > li > a:hover {
background-color: #555;
}
.nav-menu > li > a.active {
background-color: #007bff;
}
/* Dropdown menu */
.nav-menu .dropdown {
position: absolute;
top: 100%;
left: 0;
background-color: #444;
min-width: 200px;
list-style: none;
margin: 0;
padding: 0;
display: none;
box-shadow: 0 5px 10px rgba(0,0,0,0.2);
}
/* Show dropdown on hover */
.nav-menu > li:hover > .dropdown {
display: block;
}
/* Dropdown items */
.dropdown li {
border-bottom: 1px solid #555;
}
.dropdown li:last-child {
border-bottom: none;
}
.dropdown a {
color: white;
text-decoration: none;
padding: 10px 15px;
display: block;
}
.dropdown a:hover {
background-color: #666;
}
/* First dropdown item */
.dropdown li:first-child a {
padding-top: 12px;
}
/* Last dropdown item */
.dropdown li:last-child a {
padding-bottom: 12px;
}
/* Responsive: hide on mobile */
@media (max-width: 768px) {
.nav-menu {
flex-direction: column;
}
.nav-menu .dropdown {
position: static;
display: none;
background-color: #555;
}
/* Show on click would require JavaScript */
}
Example 2: Form Styling
<form class="contact-form"> <div class="form-group"> <label for="name">Name:</label> <input type="text" id="name" name="name" required> <span class="error-message">Name is required</span> </div> <div class="form-group"> <label for="email">Email:</label> <input type="email" id="email" name="email" required> <span class="error-message">Valid email required</span> </div> <div class="form-group"> <label for="age">Age:</label> <input type="number" id="age" name="age" min="18" max="120"> <span class="hint">Must be 18 or older</span> </div> <div class="form-group"> <label for="country">Country:</label> <select id="country" name="country"> <option value="">Select country</option> <option value="us">United States</option> <option value="ca">Canada</option> <option value="uk">United Kingdom</option> </select> </div> <div class="form-group checkbox-group"> <input type="checkbox" id="subscribe" name="subscribe" checked> <label for="subscribe">Subscribe to newsletter</label> </div> <div class="form-group"> <label for="message">Message:</label> <textarea id="message" name="message" rows="5" placeholder="Your message..."></textarea> </div> <button type="submit" class="submit-btn" disabled>Submit</button> </form>
/* Form styling with selectors */
.contact-form {
max-width: 600px;
margin: 30px auto;
padding: 30px;
background-color: #f9f9f9;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
/* Form groups */
.form-group {
margin-bottom: 25px;
position: relative;
}
/* Labels */
.form-group > label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #333;
}
/* Required field indicator */
.form-group > label:has(+ input:required)::after,
.form-group > label:has(+ select:required)::after {
content: " *";
color: red;
}
/* Input styling */
input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
transition: all 0.3s;
}
/* Focus state */
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0,123,255,0.1);
}
/* Validation states */
input:required:valid {
border-color: #28a745;
}
input:required:invalid:not(:placeholder-shown) {
border-color: #dc3545;
}
/* Placeholder styling */
::placeholder {
color: #999;
font-style: italic;
}
/* Checkbox styling */
.checkbox-group {
display: flex;
align-items: center;
gap: 10px;
}
.checkbox-group input[type="checkbox"] {
width: auto;
cursor: pointer;
}
.checkbox-group label {
margin: 0;
cursor: pointer;
}
.checkbox-group:has(input:checked) label {
color: #28a745;
font-weight: bold;
}
/* Error messages */
.error-message {
display: none;
color: #dc3545;
font-size: 14px;
margin-top: 5px;
}
input:required:invalid:not(:placeholder-shown) + .error-message {
display: block;
}
/* Hint text */
.hint {
display: block;
color: #666;
font-size: 12px;
font-style: italic;
margin-top: 5px;
}
/* Submit button */
.submit-btn {
background-color: #007bff;
color: white;
border: none;
padding: 12px 30px;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
}
.submit-btn:hover:not(:disabled) {
background-color: #0056b3;
}
.submit-btn:disabled {
background-color: #ccc;
cursor: not-allowed;
opacity: 0.7;
}
/* Enable submit when form is valid */
form:valid .submit-btn {
background-color: #28a745;
cursor: pointer;
opacity: 1;
}
form:valid .submit-btn:hover {
background-color: #218838;
}
Example 3: Card Grid with Hover Effects
<div class="card-grid"> <div class="card" data-category="tech"> <img src="tech.jpg" alt="Technology"> <div class="card-content"> <h3 class="card-title">Technology News</h3> <p class="card-text">Latest updates in tech world</p> <span class="card-tag">Tech</span> </div> </div> <div class="card" data-category="science"> <img src="science.jpg" alt="Science"> <div class="card-content"> <h3 class="card-title">Science Discoveries</h3> <p class="card-text">Amazing scientific breakthroughs</p> <span class="card-tag">Science</span> </div> </div> <div class="card" data-category="health"> <img src="health.jpg" alt="Health"> <div class="card-content"> <h3 class="card-title">Health & Wellness</h3> <p class="card-text">Tips for healthy living</p> <span class="card-tag">Health</span> </div> </div> </div>
/* Card grid with complex selectors */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
padding: 20px;
}
/* Card styling */
.card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
transition: all 0.3s;
position: relative;
}
/* Card hover effects */
.card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
/* Image container */
.card img {
width: 100%;
height: 200px;
object-fit: cover;
transition: transform 0.5s;
}
.card:hover img {
transform: scale(1.1);
}
/* Card content */
.card-content {
padding: 20px;
background: white;
position: relative;
}
/* Title styling */
.card-title {
margin: 0 0 10px 0;
color: #333;
font-size: 1.2em;
}
/* Card text */
.card-text {
color: #666;
line-height: 1.5;
margin: 0 0 15px 0;
}
/* Category tag */
.card-tag {
display: inline-block;
padding: 3px 10px;
border-radius: 20px;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 1px;
}
/* Category-specific colors using attribute selector */
.card[data-category="tech"] .card-tag {
background-color: #007bff;
color: white;
}
.card[data-category="science"] .card-tag {
background-color: #28a745;
color: white;
}
.card[data-category="health"] .card-tag {
background-color: #ff6b6b;
color: white;
}
/* Different styles based on category */
.card[data-category="tech"]:hover {
box-shadow: 0 5px 15px rgba(0,123,255,0.3);
}
.card[data-category="science"]:hover {
box-shadow: 0 5px 15px rgba(40,167,69,0.3);
}
/* First card special styling */
.card:first-child {
grid-column: span 2;
}
.card:first-child img {
height: 300px;
}
/* Last card special styling */
.card:last-child {
border: 2px solid gold;
}
/* Cards with images */
.card:has(img) {
padding: 0;
}
/* Cards with long content */
.card:has(p:empty) {
display: none;
}
/* Even cards background */
.card:nth-child(even) {
background-color: #f9f9f9;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.card:first-child {
grid-column: span 1;
}
}
Best Practices
Selector Organization
/* 1. Group related selectors */
/* ❌ Scattered */
.header { }
.nav { }
.header .logo { }
.nav .menu { }
/* ✅ Organized by section */
/* Header section */
.header { }
.header .logo { }
.header .nav { }
/* Main content */
.main { }
.main .sidebar { }
.main .content { }
/* Footer section */
.footer { }
.footer .copyright { }
.footer .social-links { }
Specificity Management
/* 2. Keep specificity low */
/* ❌ Too high */
body div#container .main-content section p {
color: red;
}
/* ✅ Better */
.content p {
color: red;
}
/* 3. Avoid IDs in CSS */
/* ❌ IDs too specific */
#sidebar {
width: 300px;
}
/* ✅ Use classes */
.sidebar {
width: 300px;
}
/* 4. Use class for styling, ID for JavaScript */
/* HTML: <div id="user-profile" class="profile-card"> */
/* CSS - use class */
.profile-card {
border: 1px solid #ccc;
}
/* JavaScript - use ID */
document.getElementById('user-profile');
Naming Conventions
/* 5. Use consistent naming conventions */
/* BEM naming */
.card { } /* Block */
.card__title { } /* Element */
.card__image { } /* Element */
.card__button { } /* Element */
.card__button--primary { } /* Modifier */
.card__button--large { } /* Modifier */
/* Component-based */
.btn { }
.btn-primary { }
.btn-large { }
/* Utility classes */
.text-center { }
.mt-2 { }
.hidden { }
Performance Best Practices
/* 6. Optimize for performance */
/* ❌ Slow - deep descendant */
body > div > main > section > article > p {
color: red;
}
/* ✅ Fast - single class */
.article-text {
color: red;
}
/* ❌ Slow - universal selector with important */
* {
box-sizing: border-box !important;
}
/* ✅ Fast - direct element */
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
/* ❌ Slow - overly complex */
ul li:nth-child(2n+1):not(:last-child):hover {
background: red;
}
/* ✅ Faster - simpler */
li.odd:not(:last-child):hover {
background: red;
}
Maintainability Tips
/* 7. Comment complex selectors */
/* Featured product cards - special treatment for first and last */
.product-card:first-child,
.product-card:last-child {
border: 2px solid gold;
}
/* 8. Avoid over-qualifying */
/* ❌ Unnecessary */
div.container {
width: 960px;
}
/* ✅ Sufficient */
.container {
width: 960px;
}
/* 9. Use :is() and :where() for grouping */
/* ❌ Repetitive */
header h1,
main h1,
footer h1 {
font-size: 2em;
}
/* ✅ Cleaner */
:is(header, main, footer) h1 {
font-size: 2em;
}
/* 10. Limit nesting depth */
/* ❌ Too deep */
.nav .menu .item .link .icon {
width: 20px;
}
/* ✅ Flatten if possible */
.nav-icon {
width: 20px;
}
Selector Quiz
Test your knowledge of CSS selectors and specificity!
Question 1: Basic Selectors
What selector would you use to select all paragraphs with the class "intro"?
a) .intro b) p.intro c) p .intro d) #intro
Answer: b) p.intro
Question 2: Specificity
Which selector has the highest specificity?
a) p { }
b) .text { }
c) #title { }
d) p.text { }
Answer: c) #title { } (ID selector has higher specificity than class or element)
Question 3: Combinators
What does the selector div > p select?
a) All p elements inside any div b) p elements that are direct children of div c) div elements that are direct children of p d) All p elements that come after a div
Answer: b) p elements that are direct children of div
Question 4: Pseudo-classes
Which pseudo-class selects the third child element?
a) :nth-child(3) b) :child(3) c) :nth(3) d) :third-child
Answer: a) :nth-child(3)
Question 5: Attribute Selectors
What does [href^="https"] select?
a) Links that contain "https" b) Links that end with "https" c) Links that start with "https" d) Links that are exactly "https"
Answer: c) Links that start with "https"
Question 6: Pseudo-elements
Which is a valid pseudo-element?
a) :before b) ::before c) both are valid d) neither is valid
Answer: c) both are valid (Single colon for backwards compatibility, double colon for CSS3)
Question 7: Specificity Calculation
What's the specificity of #header .nav a:hover?
a) 0,1,1,1 b) 0,1,2,1 c) 0,2,1,1 d) 1,1,1,1
Answer: b) 0,1,2,1 (ID:1, Classes: .nav and :hover = 2, Elements: a = 1)
Question 8: Complex Selector
What does ul li:not(:last-child)::after select?
a) All li elements in ul that are not last, and adds after content b) The last li element in ul and adds after content c) All li elements in ul and adds after content d) The first li element in ul and adds after content
Answer: a) All li elements in ul that are not last, and adds after content
Question 9: Modern Selectors
Which selector allows selecting parent elements based on children?
a) :parent() b) :contains() c) :has() d) :with()
Answer: c) :has()
Question 10: Cascade
If two selectors have equal specificity, which one wins?
a) The first one in the stylesheet b) The last one in the stylesheet c) The one with more elements d) They combine
Answer: b) The last one in the stylesheet
Cheat Sheet
Selector Quick Reference
| Selector | Example | Description |
|---|---|---|
| Universal | * | All elements |
| Type | p | All <p> elements |
| Class | .class | Elements with class="class" |
| ID | #id | Element with id="id" |
| Descendant | div p | <p> inside <div> |
| Child | div > p | <p> direct child of <div> |
| Adjacent | h2 + p | <p> immediately after <h2> |
| General | h2 ~ p | All <p> after <h2> |
| Attribute | [type="text"] | Elements with attribute |
Pseudo-class Quick Reference
| Type | Examples |
|---|---|
| Links | :link, :visited, :hover, :active |
| Forms | :enabled, :disabled, :checked, :valid, :invalid |
| Structural | :first-child, :last-child, :nth-child(), :empty |
| Negation | :not() |
| Target | :target |
| Root | :root |
Pseudo-elements Quick Reference
| Element | Description |
|---|---|
::before | Insert content before element |
::after | Insert content after element |
::first-line | Style first line of text |
::first-letter | Style first letter of text |
::selection | Style selected text |
::placeholder | Style placeholder text |
Specificity Calculation
Inline styles → 1,0,0,0 IDs → 0,1,0,0 Classes → 0,0,1,0 Elements → 0,0,0,1
Specificity Examples
* → 0,0,0,0 p → 0,0,0,1 p.intro → 0,0,1,1 #title → 0,1,0,0 #title.intro → 0,1,1,0 #title p.intro → 0,1,1,1
Conclusion
Mastering CSS selectors and specificity is essential for writing clean, maintainable, and efficient stylesheets.
Key Takeaways
- Start simple - Use basic selectors first, add complexity only when needed
- Keep specificity low - Avoid IDs and long selector chains
- Use classes - They're reusable and have manageable specificity
- Understand the cascade - Know when specificity vs source order matters
- Learn modern selectors -
:is(),:where(),:has()can simplify your code - Test specificity - Use browser dev tools to debug conflicting styles
- Document complex selectors - Comment your code for maintainability
- Consider performance - Efficient selectors improve page load times
- Be consistent - Follow a naming convention like BEM
- Practice - The more you use selectors, the more intuitive they become
Remember: The goal is not to write clever selectors, but to write maintainable, predictable CSS that works across browsers and devices!