Types of Selectors
1. Element Selector (Type Selector)
Targets all elements of a specific type.
p { } /* All paragraphs */
header { } /* All headers */
div { } /* All divs */
2. Class Selector - Most Used! ⭐
Targets elements with a specific class attribute.
.header { } /* Elements with class="header" */
.product-card { } /* Elements with class="product-card" */
Class selectors are the most commonly used in modern CSS because they’re reusable and have good specificity.
3. ID Selector
Targets a single element with a specific ID.
#main-nav { } /* Element with id="main-nav" */
Avoid using ID selectors for styling - they have high specificity and aren’t reusable. Use classes instead.
4. Universal Selector
Targets all elements.
* {
box-sizing : border-box ;
}
Attribute Selectors
Target elements based on their attributes.
/* Has attribute */
[ data-active ] { } /* Has data-active attribute */
/* Exact match */
[ type = "text" ] { } /* type equals "text" */
/* Starts with */
[ href ^= "https" ] { } /* href starts with "https" */
/* Ends with */
[ href $= ".pdf" ] { } /* href ends with ".pdf" */
/* Contains */
[ href *= "google" ] { } /* href contains "google" */
Real Example: Cart Counter
.header__nav-link--cart [ data-cart-count ] :not ([ data-cart-count = "0" ]) ::after {
content : attr ( data-cart-count );
background-color : var ( --color-error );
/* Shows cart count badge */
}
Pseudo-Classes (States)
Target elements in specific states.
Interactive States
:hover /* Mouse is over element */
:focus /* Element has focus */
:active /* Being clicked */
:visited /* Link was visited */
:focus-visible /* Focus via keyboard only */
.header__nav-link {
color : var ( --color-gray-600 );
transition : background-color var ( --transition-fast );
}
.header__nav-link:hover {
background-color : rgba ( 0 , 0 , 0 , 0.05 );
}
Structural Pseudo-Classes
:first-child /* First child of parent */
:last-child /* Last child of parent */
:nth-child ( n ) /* Nth child */
:nth-child ( odd ) /* 1st, 3rd, 5th... */
:nth-child ( even ) /* 2nd, 4th, 6th... */
:not (selector) /* Negation */
Odd/Even Rows
First & Last
Negation
/* Stripe table rows */
table tr :nth-child ( odd ) {
background-color : var ( --color-gray-100 );
}
table tr :nth-child ( even ) {
background-color : var ( --color-white );
}
Pseudo-Elements (Parts)
Create and style parts of elements.
::before /* Content before element */
::after /* Content after element */
::first-letter /* First letter */
::first-line /* First line */
::placeholder /* Input placeholder text */
Example: Cart Counter Badge
.header__nav-link--cart::after {
content : attr ( data-cart-count );
position : absolute ;
top : -4 px ;
right : -8 px ;
min-width : 18 px ;
height : 18 px ;
padding : 0 var ( --spacing-xs );
background-color : var ( --color-error );
color : var ( --color-white );
font-size : var ( --font-size-xs );
border-radius : var ( --border-radius-full );
display : flex ;
align-items : center ;
justify-content : center ;
}
Placeholder Styling
.header__search-input::placeholder {
color : var ( --color-gray-400 );
}
Combinators
Combine selectors to target specific relationships.
/* Descendant - any level */
.header .nav-link { } /* nav-link inside header (any depth) */
/* Child - direct child only */
.header > .nav { } /* nav that's a direct child of header */
/* Adjacent sibling - immediately after */
.title + .subtitle { } /* subtitle immediately after title */
/* General sibling - any following */
.title ~ .paragraph { } /* any paragraph after title */
Real Example: Image Zoom on Card Hover
/* When card is hovered, scale the image inside */
.product-card:hover .product-card__image {
transform : scale ( 1.05 );
}
Specificity
When multiple rules target the same element, specificity determines which wins.
Specificity Values (from lowest to highest):
Element : 0,0,0,1 (p, div, header)
Class : 0,0,1,0 (.class)
ID : 0,1,0,0 (#id)
Inline : 1,0,0,0 (style=”…”)
!important : Wins always (avoid!)
Calculating Specificity
Low Specificity (0,0,0,1)
Medium (0,0,1,0)
Higher (0,0,2,0)
Very High (0,1,0,0)
Best Practices
Use classes for styling - they’re reusable and have good specificity
Keep specificity low to make styles easier to override
Avoid nesting selectors too deeply (max 2-3 levels)
Avoid ID selectors for styling - use for JS/links only
Never use !important unless absolutely necessary
Grouping Selectors
Apply the same styles to multiple selectors.
/* Same styles for multiple elements */
input :focus ,
textarea :focus ,
button :focus-visible ,
a :focus-visible {
outline : 2 px solid var ( --color-secondary );
outline-offset : 2 px ;
}
Hidden Elements (Accessibility)
Two ways to hide elements with different accessibility impacts:
display: none (Not Accessible)
Visually Hidden (Accessible)
/* Completely hidden - screen readers won't read */
.hide-mobile {
display : none !important ;
}
Practice Example
Let’s build navigation link styles using various selectors:
/* Base link styles */
.header__nav-link {
display : flex ;
align-items : center ;
gap : var ( --spacing-xs );
padding : var ( --spacing-xs ) var ( --spacing-sm );
font-size : var ( --font-size-sm );
color : var ( --color-gray-600 );
border-radius : var ( --border-radius-sm );
transition : background-color var ( --transition-fast );
}
/* Hover state (pseudo-class) */
.header__nav-link:hover {
background-color : rgba ( 0 , 0 , 0 , 0.05 );
}
/* Cart link modifier (class) */
.header__nav-link--cart {
position : relative ;
}
/* Cart counter badge (attribute + pseudo-element) */
.header__nav-link--cart [ data-cart-count ] :not ([ data-cart-count = "0" ]) ::after {
content : attr ( data-cart-count );
position : absolute ;
top : -4 px ;
right : -8 px ;
background-color : var ( --color-error );
color : var ( --color-white );
/* ... more styles ... */
}
Next Steps
BEM Methodology Learn to write maintainable selector names
Box Model Control spacing and sizing