How does CSS know which elements to style? Selectors. They're like a GPS for your stylesheet, telling CSS where to apply your rules.
Selectors are patterns that match HTML elements. Whether you style every button, highlight specific cards, or add hover effects, selectors are your toolkit for precise styling.
The Big Picture
Selectors are the bridge between your HTML structure and CSS styling. Master them, and you'll write cleaner, more maintainable CSS.
The Essentials: Basic Selectors
Element Selectors
Target elements by their HTML tag name - the simplest way to style.
style.css
1/* Targets all <p> elements */2p{3color:#333;4}56/* Targets all heading elements (h1, h2, h3) */7h1, h2, h3{8font-weight:600;9}
Class Selectors
Target elements with specific classes - your go-to for reusable styles.
style.css
1/* Style elements with class "button" */2.button{3padding:0.75rem1.5rem;4background:#3b82f6;5color:white;6}78/* Multiple classes */9.button.primary{10background:#059669;11}
ID Selectors
Target unique elements - use sparingly, mainly for JavaScript hooks.
style.css
1/* Targets the unique element with id="header" */2#header{3background:#1f2937;4color:white;5padding:1rem;6}
Watch out
IDs should be unique within a page. Use classes for styling multiple elements, and reserve IDs for JavaScript hooks or unique page elements.
Try It Yourself: Basic Selectors
Edit the CSS below to see how different selectors work in real time.
Preview
Attribute Selectors: Targeting by Properties
Style elements based on their HTML attributes. Useful for forms and dynamic content.
style.css
1/* Has a title attribute (any value) */2[title]{3cursor: help;4}56/* Title is exactly "Hello" */7[title="Hello"]{8color:blue;9}1011/* Title contains "Hello" anywhere */12[title*="Hello"]{13font-weight: bold;14}1516/* Title starts with "Hello" */17[title^="Hello"]{18text-decoration: underline;19}2021/* Title ends with "World" */22[title$="World"]{23border:1px solid green;24}
Pseudo-classes: State-Based Styling
Target elements based on their current state or position in the document.
style.css
1/* Unvisited link */2a:link{3color:#2563eb;4}56/* Already visited link */7a:visited{8color:#7c3aed;9}1011/* Mouse hovers over the link */12a:hover{13color:#1d4ed8;14}1516/* Link being clicked */17a:active{18color:#1e40af;19}2021/* First item in a list */22li:first-child{23font-weight: bold;24}2526/* Last item in a list */27li:last-child{28border-bottom: none;29}3031/* Every even-numbered item */32li:nth-child(even){33background:#f3f4f6;34}
Pseudo-elements: Creating Virtual Elements
Add content or style parts of elements that aren't in your HTML.
style.css
1/* Inserts content before the element */2.quote::before{3content:'"';4}56/* Inserts content after the element */7.quote::after{8content:'"';9}1011/* Styles only the first line of text */12p::first-line{13font-weight: bold;14}1516/* Styles only the first letter (drop cap effect) */17p::first-letter{18font-size:3rem;19float: left;20}
Combinators: Connecting Selectors
Define relationships between elements to create precise targeting.
style.css
1/* Descendant: any <p> inside <article> (any depth) */2article p{3margin-bottom:1rem;4}56/* Child: only direct <p> children of <article> */7article > p{8font-size:1.1rem;9}1011/* Adjacent sibling: first <p> immediately after <h2> */12h2 + p{13color:#6b7280;14}1516/* General sibling: all <p> elements after <h2> */17h2 ~ p{18text-indent:1rem;19}
Modern Magic: Advanced Selectors
The :has() Selector - Style Parents Based on Children
Style a parent element based on what's inside it.
style.css
1/* Card that contains an image gets a grid layout */2.card:has(img){3display: grid;4grid-template-columns:200px1fr;5}67/* Form group turns red when its input is invalid */8.form-group:has(input:invalid){9border-left:3px solid #ef4444;10}1112/* Card gets a shadow when any button inside is hovered */13.card:has(button:hover){14box-shadow:010px30pxrgba(0,0,0,0.2);15}
Game Changer
:has() is supported in all modern browsers since 2023.
The :is() Selector - Group Multiple Selectors
Clean up repetitive selectors with :is().
style.css
1/* Without :is() — repetitive selector list */2h1, h2, h3, h4, h5, h6{3font-family:'Inter', sans-serif;4}56/* With :is() — same result, cleaner syntax */7:is(h1, h2, h3, h4, h5, h6){8font-family:'Inter', sans-serif;9}1011/* Combine with other selectors for even cleaner code */12article :is(h1, h2, h3){13color:#1f2937;14margin-top:2rem;15}
The :where() Selector - Zero Specificity
Like :is(), but with zero specificity. Good for base styles.
style.css
1/* :where() has zero specificity — easy to override */2:where(h1, h2, h3){3margin:0;4padding:0;5}67/* This wins because any class has higher specificity than :where() */8.custom-heading{9margin:2rem0;10}
Pro Tip
Use :is() for normal specificity, :where() for easily overridable base styles.
Focus Selectors - Smart Focus Management
Handle focus states for better UX.
style.css
1/* Highlights the form when any input inside is focused */2.form:focus-within{3border-color:#3b82f6;4box-shadow:0003pxrgba(59,130,246,0.1);5}67/* Shows outline only for keyboard navigation (Tab key) */8button:focus-visible{9outline:2px solid #3b82f6;10outline-offset:2px;11}1213/* Hides outline for mouse clicks */14button:focus:not(:focus-visible){15outline: none;16}
The :not() Selector - Exclude Elements
Style everything except what you don't want.
style.css
1/* All buttons except those with class "primary" */2button:not(.primary){3background:#6b7280;4}56/* All list items except the last one get a bottom border */7li:not(:last-child){8border-bottom:1px solid #e5e7eb;9}1011/* All inputs except checkboxes and radios */12input:not([type="checkbox"]):not([type="radio"]){13width:100%;14padding:0.5rem;15}
Container Queries - Size-Based Styling
Style elements based on their container size, not the viewport.
style.css
1/* Define a named container to query against */2.card-container{3container-type: inline-size;4container-name: card;5}67/* When container is at least 400px wide */8@container card (min-width:400px){9.card{10display: grid;11grid-template-columns:200px1fr;12}13}1415/* When container is at least 600px wide */16@container card (min-width:600px){17.card{18grid-template-columns:300px1fr;19gap:2rem;20}21}
Why Container Queries?
Components adapt to their container size rather than the viewport. Ideal for reusable components.
Specificity: The Rules of CSS Priority
CSS specificity determines which rules win when multiple rules target the same element.
Specificity Hierarchy
From highest to lowest: Inline styles > ID selectors > Class selectors > Element selectors. :where() has zero specificity, while :is() and :has() take the specificity of their most specific argument.
style.css
1/* Specificity: 0-0-1 (one element) */2p{3color:black;4}56/* Specificity: 0-1-1 (one class + one element) */7p.highlight{8color:yellow;9}1011/* Specificity: 1-0-0 (one ID) */12#main-text{13color:red;14}1516/* Specificity: 1-1-1 (one ID + one class + one element) — WINS! */17#main-text p.highlight{18color:blue;19}
I build fast, accessible, and delightful digital experiences for the web. Whether you have a project in mind or just want to connect, I'd love to hear from you.