CSS Selectors and Syntax
1. CSS Syntax Fundamentals and Structure
| Component | Syntax | Description | Example |
|---|---|---|---|
| Rule Set | selector { property: value; } |
Complete CSS rule with selector and declarations | h1 { color: blue; } |
| Selector | element, .class, #id |
Targets HTML elements for styling | div, .container, #main |
| Declaration Block | { prop1: val1; prop2: val2; } |
Contains one or more declarations wrapped in braces | { margin: 0; padding: 10px; } |
| Declaration | property: value; |
Single property-value pair with semicolon | font-size: 16px; |
| Property | color, margin, display |
CSS attribute to style elements | background-color |
| Value | keyword | length | % |
Assigned to property, can be keyword, number, color, etc. | red, 10px, 50%, auto |
| Comments | /* comment */ |
Single or multi-line comments ignored by browser | /* Main header styles */ |
| At-Rules | @rule { } |
Special instructions starting with @ | @media, @import, @keyframes |
| Multiple Selectors | sel1, sel2, sel3 { } |
Comma-separated selectors share same declarations | h1, h2, h3 { margin: 0; } |
Example: Complete CSS rule structure
/* Comment describing the rule */
.container {
/* Property: Value pairs */
display: flex;
padding: 20px;
background-color: #f0f0f0;
}
/* Multiple selectors */
h1, h2, h3 {
font-family: Arial, sans-serif;
color: #333;
}
2. Basic Selectors (element, class, id, universal)
| Selector Type | Syntax | Description | Example | Specificity |
|---|---|---|---|---|
| Universal | * |
Selects all elements in document | * { margin: 0; } |
0,0,0 |
| Type/Element | element |
Selects all elements of specified type | p { line-height: 1.5; } |
0,0,1 |
| Class | .classname |
Selects all elements with specific class attribute | .button { padding: 10px; } |
0,1,0 |
| ID | #idname |
Selects single element with specific id attribute | #header { width: 100%; } |
1,0,0 |
| Multiple Classes | .class1.class2 |
Selects elements with all specified classes | .btn.primary { } |
0,2,0 |
| Element + Class | element.class |
Selects specific element type with class | div.container { } |
0,1,1 |
Example: Basic selector usage
/* Universal - affects all elements */
* { box-sizing: border-box; }
/* Element selector */
p { color: #333; }
/* Class selector */
.alert { background: yellow; }
/* ID selector */
#main-nav { position: fixed; }
/* Multiple classes */
.btn.primary { background: blue; }
/* Element with class */
button.submit { font-weight: bold; }
3. Advanced Selector Patterns and Combinators
| Combinator | Syntax | Description | Example |
|---|---|---|---|
| Descendant | A B |
Selects B elements inside A (any level deep) | div p { color: red; } |
| Child | A > B |
Selects B elements that are direct children of A | ul > li { margin: 5px; } |
| Adjacent Sibling | A + B |
Selects B immediately following A (same parent) | h1 + p { font-size: 1.2em; } |
| General Sibling | A ~ B |
Selects all B siblings after A (same parent) | h1 ~ p { margin-top: 10px; } |
| Column Combinator | A || B |
Selects B elements belonging to column A (tables) | col.selected || td { } |
Example: Combinator usage patterns
/* Descendant - any level */
.container p { padding: 10px; }
/* Direct child only */
nav > ul { list-style: none; }
/* Adjacent sibling - immediately after */
label + input { margin-left: 10px; }
/* General siblings - all after */
h2 ~ p { color: gray; }
/* Complex combination */
article > header + section p { line-height: 1.6; }
Note: Descendant selector (
A B) has lower
performance than child selector (A > B) since it traverses entire DOM tree.
4. Attribute Selectors and Values
| Selector | Syntax | Description | Example |
|---|---|---|---|
| Has Attribute | [attr] |
Selects elements with specified attribute | [disabled] { opacity: 0.5; } |
| Exact Match | [attr="value"] |
Attribute value exactly matches | [type="text"] { border: 1px; } |
| Contains Word | [attr~="value"] |
Attribute contains value as complete word | [class~="active"] { } |
| Starts With | [attr^="value"] |
Attribute value starts with specified string | [href^="https"] { } |
| Ends With | [attr$="value"] |
Attribute value ends with specified string | [src$=".pdf"] { } |
| Contains Substring | [attr*="value"] |
Attribute contains substring anywhere | [href*="example"] { } |
| Starts With (dash) | [attr|="value"] |
Value exactly or followed by hyphen (lang codes) | [lang|="en"] { } |
| Case Insensitive | [attr="value" i] |
Case-insensitive attribute matching | [href$=".PDF" i] { } |
| Case Sensitive | [attr="value" s] |
Case-sensitive matching (default in most cases) | [type="Text" s] { } |
Example: Attribute selector patterns
/* Has attribute */
input[required] { border-color: red; }
/* Exact value */
input[type="email"] { background: #f0f0f0; }
/* Starts with */
a[href^="https://"] { color: green; }
a[href^="http://"] { color: orange; }
/* Ends with */
a[href$=".pdf"]::after { content: " (PDF)"; }
/* Contains */
img[src*="thumbnail"] { width: 100px; }
/* Case insensitive */
[data-state="active" i] { font-weight: bold; }
/* Multiple attributes */
input[type="text"][required] { border: 2px solid red; }
5. Pseudo-classes and Pseudo-elements (:hover, :focus, ::before, ::after)
Common Pseudo-classes
| Pseudo-class | Description |
|---|---|
| :hover | Mouse pointer over element |
| :active | Element being activated (clicked) |
| :focus | Element has keyboard focus |
| :focus-visible | Focus via keyboard only |
| :visited | Visited link |
| :link | Unvisited link |
| :target | Element matching URL fragment |
| :disabled | Disabled form element |
| :enabled | Enabled form element |
| :checked | Checked checkbox/radio |
| :valid | Valid form input |
| :invalid | Invalid form input |
| :required | Required form field |
| :optional | Optional form field |
Structural Pseudo-classes
| Pseudo-class | Description |
|---|---|
| :first-child | First child of parent |
| :last-child | Last child of parent |
| :only-child | Only child of parent |
| :first-of-type | First of its element type |
| :last-of-type | Last of its element type |
| :only-of-type | Only of its element type |
| :nth-child(n) | Nth child (1-indexed) |
| :nth-last-child(n) | Nth from end |
| :nth-of-type(n) | Nth of element type |
| :nth-last-of-type(n) | Nth of type from end |
| :empty | No children or text |
| :root | Document root element |
| :not(selector) | Does not match selector |
| Pseudo-element | Syntax | Description | Use Case |
|---|---|---|---|
| ::before | element::before { content: ""; } |
Inserts content before element's content | Icons, decorative elements |
| ::after | element::after { content: ""; } |
Inserts content after element's content | Clearfix, decorative elements |
| ::first-line | p::first-line { } |
Styles first line of block element | Drop caps, emphasis |
| ::first-letter | p::first-letter { } |
Styles first letter of block element | Drop caps, initial letter |
| ::selection | ::selection { } |
User-selected text portion | Custom highlight colors |
| ::placeholder | input::placeholder { } |
Input placeholder text | Placeholder styling |
| ::marker | li::marker { } |
List item marker (bullet/number) | Custom bullet colors |
| ::backdrop | dialog::backdrop { } |
Backdrop behind dialog/fullscreen element | Modal overlays |
Example: Pseudo-classes and pseudo-elements
/* User interaction pseudo-classes */
a:hover { color: blue; }
button:active { transform: scale(0.95); }
input:focus { outline: 2px solid blue; }
/* Structural pseudo-classes */
li:first-child { font-weight: bold; }
tr:nth-child(even) { background: #f0f0f0; }
tr:nth-child(odd) { background: white; }
p:not(.special) { color: gray; }
/* Form state pseudo-classes */
input:disabled { opacity: 0.5; }
input:valid { border-color: green; }
input:invalid { border-color: red; }
/* Pseudo-elements */
.quote::before { content: "❝"; }
.quote::after { content: "❞"; }
p::first-letter { font-size: 2em; float: left; }
::selection { background: yellow; color: black; }
Note: Use :: (double colon) for pseudo-elements and : (single colon) for pseudo-classes.
::before and ::after
require content property to display.
6. Specificity Rules and Cascade Resolution
| Specificity Level | Value | Selector Type | Example |
|---|---|---|---|
| Inline Styles | 1,0,0,0 |
Style attribute on element | <div style="color: red"> |
| IDs | 0,1,0,0 |
ID selectors | #header { } |
| Classes/Attributes | 0,0,1,0 |
Class, attribute, pseudo-class | .btn, [type], :hover |
| Elements | 0,0,0,1 |
Element, pseudo-element | div, ::before |
| Universal | 0,0,0,0 |
Universal, combinators | *, >, +, ~ |
| Calculation Example | Selector | IDs | Classes | Elements | Specificity |
|---|---|---|---|---|---|
| Simple | p |
0 | 0 | 1 | 0,0,1 |
| Class | .button |
0 | 1 | 0 | 0,1,0 |
| ID | #main |
1 | 0 | 0 | 1,0,0 |
| Compound | div.container |
0 | 1 | 1 | 0,1,1 |
| Complex | #nav ul li a:hover |
1 | 1 | 3 | 1,1,3 |
| Multiple Classes | .btn.primary.large |
0 | 3 | 0 | 0,3,0 |
Example: Specificity calculation and cascade order
/* Specificity: 0,0,1 */
p { color: black; }
/* Specificity: 0,1,0 - wins over above */
.text { color: blue; }
/* Specificity: 0,1,1 - wins over .text */
p.text { color: green; }
/* Specificity: 1,0,0 - wins over all above */
#main { color: red; }
/* !important overrides specificity */
p { color: purple !important; } /* Wins over everything */
/* Equal specificity - last rule wins */
.box { color: blue; }
.box { color: red; } /* This applies */
Warning: Avoid
!important as it breaks natural cascade and makes debugging
difficult. Use higher specificity instead. Only use for utility classes or overriding third-party styles.
Cascade Order (Priority from highest to lowest)
- User agent !important declarations
- User !important declarations
- Author !important declarations
- Author normal declarations
- User normal declarations
- User agent normal declarations
Within same origin: Inline styles > IDs > Classes/Attributes > Elements
If equal specificity: Last declared wins
7. CSS4 Selector Features (:is, :where, :has) NEW
| Selector | Syntax | Description | Specificity |
|---|---|---|---|
| :is() | :is(sel1, sel2, ...) |
Matches any selector in list; specificity = highest selector | Takes highest |
| :where() | :where(sel1, sel2, ...) |
Same as :is() but always has 0 specificity | 0,0,0 |
| :has() | :has(selector) |
Parent selector - matches element containing selector | From argument |
| :not() | :not(sel1, sel2, ...) |
Negation - matches elements not matching any selector | From argument |
Example: :is() selector simplification
/* Traditional approach - verbose */
header a:hover,
footer a:hover,
aside a:hover {
color: blue;
}
/* Using :is() - much shorter */
:is(header, footer, aside) a:hover {
color: blue;
}
/* Specificity example */
:is(#id, .class) { } /* Specificity: 1,0,0 (from #id) */
:where(#id, .class) { } /* Specificity: 0,0,0 */
Example: :where() for zero specificity
/* Library/framework base styles with 0 specificity */
:where(h1, h2, h3, h4, h5, h6) {
margin: 0;
font-weight: bold;
}
/* User styles easily override without !important */
h1 { margin: 20px 0; } /* Overrides above */
/* Use case: default styles that are easy to override */
:where(.btn) {
padding: 10px;
border: none;
}
.btn { padding: 20px; } /* Easily overrides */
Example: :has() parent/relational selector NEW
/* Style parent based on child */
article:has(> img) {
display: grid;
}
/* Form with invalid input */
form:has(input:invalid) {
border: 2px solid red;
}
/* Card with .featured class inside */
.card:has(.featured) {
background: gold;
}
/* List item containing link */
li:has(> a) {
cursor: pointer;
}
/* Previous sibling selector (works with :has) */
li:has(+ li:hover) {
color: blue;
}
/* Conditional layout */
section:has(> .sidebar) {
display: grid;
grid-template-columns: 3fr 1fr;
}
Example: :not() negation selector
/* All paragraphs except .special */
p:not(.special) {
color: gray;
}
/* Multiple negations (CSS4) */
button:not(.primary):not(.secondary) {
background: white;
}
/* Not with attribute */
input:not([type="submit"]) {
border: 1px solid gray;
}
/* Complex negation */
li:not(:first-child):not(:last-child) {
border-top: 1px solid #ddd;
}
Note:
:has() is powerful but can impact performance with complex queries. Use
specific selectors and avoid deeply nested :has() chains. Test performance in
production environments.