Table of Contents
- Basic Selectors
- Universal Selector
- Type Selector
- Class Selector
- ID Selector
- Attribute Selector
- Combinators
- Descendant Combinator
- Child Combinator
- Adjacent Sibling Combinator
- General Sibling Combinator
- Pseudo-Classes
- State Pseudo-Classes
- Structural Pseudo-Classes
- Negation Pseudo-Class
- Pseudo-Elements
- ::before and ::after
- ::first-line and ::first-letter
- ::selection
- Advanced Selectors & Specificity
- Complex Attribute Selectors
- Combining Selectors
- Specificity: How CSS Decides Which Rule Wins
- Best Practices
- Classes vs. IDs
- Avoid Over-Specificity
- Semantic Selectors
- Performance Considerations
- Reference Table
Basic Selectors
Basic selectors target elements directly based on their type, class, ID, attributes, or a universal match. They form the foundation of CSS styling.
1.1 Universal Selector
Targets all elements on a page. Useful for resetting margins/padding or applying global styles, but use sparingly (see performance notes).
Syntax: *
Example:
/* Reset default margins/padding for all elements */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
Use Case: Global resets or applying styles to every element (e.g., font-family).
1.2 Type Selector
Targets elements by their HTML tag name (e.g., <p>, <div>, <h1>).
Syntax: tagname
Example:
/* Style all <p> tags */
p {
color: #333;
font-size: 16px;
line-height: 1.5;
}
/* Style all <button> tags */
button {
background: #007bff;
color: white;
padding: 8px 16px;
}
Use Case: Styling semantic elements consistently (e.g., all headings or lists).
1.3 Class Selector
Targets elements with a specific class attribute. Classes are reusable and can be applied to multiple elements.
Syntax: .classname
Example:
<!-- HTML -->
<div class="alert">This is a warning!</div>
<p class="alert">Another warning here.</p>
/* CSS */
.alert {
background: #fff3cd;
color: #856404;
padding: 12px;
border-left: 4px solid #ffc107;
}
Use Case: Grouping elements with shared styles (e.g., buttons, cards, alerts).
1.4 ID Selector
Targets a single element with a unique id attribute (IDs must be unique per page).
Syntax: #idname
Example:
<!-- HTML -->
<header id="main-header">Welcome to My Site</header>
/* CSS */
#main-header {
background: #2d3436;
color: white;
padding: 20px;
text-align: center;
}
Note: Avoid overusing IDs—they have high specificity (see specificity) and can’t be reused. Prefer classes for most styling.
1.5 Attribute Selector
Targets elements with a specific attribute or attribute value.
Syntax: [attribute], [attribute="value"], or variations (e.g., [attribute^="value"] for “starts with”).
Common Variations:
| Selector | Description | Example |
|---|---|---|
[attr] | Elements with attr attribute (any value) | [disabled] { opacity: 0.5; } |
[attr="val"] | Elements where attr equals val (exact) | [type="email"] { border: 1px solid blue; } |
[attr^="val"] | attr starts with val | [href^="https"] { color: #28a745; } |
[attr$="val"] | attr ends with val | [src$=".pdf"] { background: #f8d7da; } |
[attr*="val"] | attr contains val (any position) | [class*="btn-"] { padding: 8px 16px; } |
Example:
/* Style links pointing to external sites */
a[href^="http"] {
background: url("external-icon.png") no-repeat right;
padding-right: 18px;
}
/* Style input fields with placeholder text */
input[placeholder] {
border: 1px solid #ced4da;
}
Use Case: Styling form inputs, links, or media elements based on their attributes (e.g., type, href, src).
Combinators
Combinators let you target elements based on their relationship to other elements (e.g., parent-child, siblings).
2.1 Descendant Combinator
Targets an element that is a descendant (child, grandchild, etc.) of another element.
Syntax: ancestor descendant (space-separated)
Example:
<!-- HTML -->
<nav class="main-nav">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
/* CSS: Target all <a> tags inside .main-nav (even nested ones) */
.main-nav a {
color: #2d3436;
text-decoration: none;
}
Note: The <a> tags here are descendants of .main-nav (via <ul> and <li>).
2.2 Child Combinator
Targets an element that is a direct child of another element (no nested levels).
Syntax: parent > child (greater-than symbol)
Example:
<!-- HTML -->
<div class="card">
<h3>Card Title</h3> <!-- Direct child -->
<div class="card-body">
<p>Card content</p> <!-- Grandchild (not a direct child) -->
</div>
</div>
/* CSS: Target only direct children of .card */
.card > h3 {
color: #007bff;
margin-bottom: 12px;
}
Result: Only <h3> (direct child) is styled, not the <p> (grandchild).
2.3 Adjacent Sibling Combinator
Targets an element that is the immediately next sibling of another element (shares the same parent).
Syntax: element + sibling (plus symbol)
Example:
<!-- HTML -->
<h2>Introduction</h2>
<p>First paragraph.</p> <!-- Adjacent sibling of h2 -->
<p>Second paragraph.</p> <!-- Not adjacent -->
/* CSS: Style the first <p> after an <h2> */
h2 + p {
font-weight: bold;
color: #28a745;
}
Result: Only the first <p> (immediately after <h2>) is bold and green.
2.4 General Sibling Combinator
Targets all siblings of an element that appear after it (shares the same parent).
Syntax: element ~ sibling (tilde symbol)
Example:
<!-- HTML -->
<input type="checkbox" id="toggle">
<label for="toggle">Show details</label>
<p class="details">Hidden content</p>
<p class="details">More hidden content</p>
/* CSS: Show .details when checkbox is checked */
#toggle:checked ~ .details {
display: block;
}
.details {
display: none;
}
Result: Both .details paragraphs (siblings of the checkbox) are shown when the checkbox is checked.
Pseudo-Classes
Pseudo-classes (:) target elements based on state (e.g., hover, active) or position (e.g., first child, even/odd rows).
3.1 State Pseudo-Classes
Target elements in a specific state (e.g., user interaction).
| Pseudo-Class | Description | Example |
|---|---|---|
:hover | Element is hovered over (mouse only) | button:hover { transform: scale(1.05); } |
:active | Element is being clicked/activated | button:active { background: #0056b3; } |
:focus | Element has keyboard focus (e.g., input) | input:focus { border: 2px solid #007bff; } |
:visited | Link has been visited by the user | a:visited { color: #6610f2; } |
:disabled | Element is disabled (e.g., input) | input:disabled { opacity: 0.5; cursor: not-allowed; } |
Example:
/* Style a button in different states */
.btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.btn:hover {
background: #0056b3; /* Darken on hover */
}
.btn:active {
transform: translateY(2px); /* Slight press effect */
}
.btn:focus {
outline: 3px solid rgba(0, 123, 255, 0.3); /* Focus ring for accessibility */
}
3.2 Structural Pseudo-Classes
Target elements based on their position in the DOM.
| Pseudo-Class | Description | Example |
|---|---|---|
:first-child | First child of its parent | ul li:first-child { font-weight: bold; } |
:last-child | Last child of its parent | ul li:last-child { margin-right: 0; } |
:nth-child(n) | nth child (n = number, even, odd, or formula like 2n+1) | tr:nth-child(even) { background: #f8f9fa; } |
:only-child | Only child of its parent | div:only-child { margin: 0 auto; } |
:first-of-type | First element of its type among siblings | article p:first-of-type { font-size: 18px; } |
Example:
<!-- HTML -->
<ul class="todo-list">
<li>Buy groceries</li>
<li>Finish CSS project</li>
<li>Call mom</li>
<li>Read book</li>
</ul>
/* CSS: Style odd/even list items */
.todo-list li:nth-child(odd) {
background: #f8f9fa;
}
.todo-list li:nth-child(even) {
background: #e9ecef;
}
/* Style the first and last items */
.todo-list li:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.todo-list li:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
3.3 Negation Pseudo-Class (:not())
Targets elements that do not match a given selector.
Syntax: :not(selector)
Example:
/* Style all buttons except .secondary */
button:not(.secondary) {
background: #007bff;
}
/* Style all inputs except disabled ones */
input:not([disabled]) {
cursor: text;
}
Use Case: Excluding specific elements from a style rule (e.g., “all buttons except the cancel button”).
Pseudo-Elements
Pseudo-elements (::) target specific parts of an element (e.g., the first line of text, or adding content before/after an element).
4.1 ::before and ::after
Insert content before or after an element’s content. Requires the content property (use content: "" for empty content).
Syntax: element::before or element::after
Example:
<!-- HTML -->
<p class="quote">CSS is awesome!</p>
/* CSS: Add quotes around the text */
.quote::before {
content: '"';
font-size: 24px;
color: #6c757d;
}
.quote::after {
content: '"';
font-size: 24px;
color: #6c757d;
}
Result: "CSS is awesome!"
Use Case: Adding icons, decorative elements, or tooltips without cluttering HTML.
4.2 ::first-line and ::first-letter
Target the first line or first letter of text in a block-level element.
Example:
/* Style the first line of a paragraph */
.intro::first-line {
font-weight: bold;
color: #007bff;
}
/* Style the first letter of a heading */
h1::first-letter {
font-size: 2em;
color: #dc3545;
}
Note: Only works on block-level elements (e.g., <p>, <h1>).
4.3 ::selection
Targets text selected by the user (e.g., highlighted with the mouse).
Example:
/* Customize selected text color */
::selection {
background: #ffc107;
color: #2d3436;
}
Use Case: Improving user experience with branded selection colors.
Advanced Selectors & Specificity
5.1 Complex Selector Combinations
Combine basic selectors, combinators, and pseudo-classes for precise targeting.
Example:
/* Target the 3rd <li> in a .nav list that is not active */
.nav li:nth-child(3):not(.active) a {
color: #6c757d;
}
/* Target disabled inputs inside a .form-group */
.form-group input[disabled] {
background: #e9ecef;
}
5.2 Specificity: How CSS Decides Which Rule Wins
When multiple CSS rules target the same element, specificity determines which rule is applied. Think of it as a “score” for selectors: higher scores override lower ones.
Specificity Calculation (from highest to lowest):
| Selector Type | Score Contribution | Example | Score (0,0,0,0) |
|---|---|---|---|
| Inline styles | 1,0,0,0 | <div style="color: red"> | (1,0,0,0) |
| ID selectors | 0,1,0,0 | #header | (0,1,0,0) |
| Class/pseudo-class/attribute | 0,0,1,0 | .btn, :hover, [type] | (0,0,1,0) |
| Type selectors | 0,0,0,1 | div, p | (0,0,0,1) |
Universal selector (*) | 0,0,0,0 | * | (0,0,0,0) |
Example:
/* Score: (0,0,1,0) */
.alert { color: red; }
/* Score: (0,1,0,0) → higher than .alert → wins */
#critical { color: blue; }
/* Score: (0,0,2,0) → higher than (0,0,1,0) → wins over .alert */
.alert.error { color: purple; }
Tip: Use !important to force a rule (e.g., .alert { color: red !important; }), but avoid it—overuse leads to unmaintainable code.
Best Practices
- Prefer Classes Over IDs: IDs are unique and hard to reuse. Classes are flexible and promote reusability.
- Avoid Over-Specificity: Don’t chain selectors unnecessarily (e.g.,
div.container .row .colcan often be simplified to.col). - Use Semantic Selectors: Target elements like
<nav>or<article>instead of generic<div>s for better readability. - Limit Universal Selectors:
*is slow on large pages—use resets like Normalize.css instead. - Test for Accessibility: Ensure state pseudo-classes (e.g.,
:focus) are visible for keyboard users.
Reference Table
| Selector | Syntax | Description | Example |
|---|---|---|---|
| Universal | * | All elements | * { margin: 0; } |
| Type | tag | Elements by tag name | p { color: #333; } |
| Class | .class | Elements with class class | .btn { padding: 8px; } |
| ID | #id | Element with ID id (unique) | #logo { width: 100px; } |
| Attribute | [attr] | Elements with attribute attr | [disabled] { opacity: 0.5; } |
| Descendant | ancestor descendant | Descendant of ancestor | .nav a { color: blue; } |
| Child | parent > child | Direct child of parent | ul > li { list-style: none; } |
| Adjacent Sibling | A + B | B is immediately after A | h2 + p { font-weight: bold; } |
| General Sibling | A ~ B | All B after A | input ~ label { color: #666; } |
:hover | element:hover | Element on hover | button:hover { transform: scale(1.05); } |
:nth-child(n) | element:nth-child(n) | nth child of parent | li:nth-child(odd) { background: #f8f9fa; } |
::before | element::before | Add content before element | .quote::before { content: '"'; } |
Conclusion
Mastering CSS selectors is key to writing efficient, maintainable styles. From basic classes to advanced specificity rules, selectors let you target elements with precision. Practice combining selectors and testing specificity to build robust layouts.
Happy styling! 🚀