CSS Selectors and Specificity
CSS selectors are the foundation of styling web pages. They determine which HTML elements get styled and how. Understanding selectors and specificity is crucial for writing maintainable CSS. This tutorial covers the different types of selectors and how specificity works to resolve style conflicts.
What are CSS Selectors?
Selectors are patterns that match HTML elements on a page. When a selector matches an element, the CSS rules inside the curly braces {} are applied to that element.
/* Selector */
h1 {
/* Declaration */
color: blue;
font-size: 24px;
}Basic Selectors
Element Selector (Type Selector)
Selects all elements of a specific type.
p {
color: #333;
}
h1, h2, h3 {
font-family: Arial, sans-serif;
}Class Selector
Selects elements with a specific class attribute. Use a dot (.) followed by the class name.
.highlight {
background-color: yellow;
}
.btn-primary {
background-color: blue;
color: white;
}ID Selector
Selects a single element with a specific id attribute. Use a hash (#) followed by the id.
#header {
background-color: #f0f0f0;
}
#nav-menu {
list-style: none;
}Universal Selector
Selects all elements. Use an asterisk (*).
* {
margin: 0;
padding: 0;
}Attribute Selectors
Select elements based on their attributes.
/* Elements with a title attribute */
[title] {
border-bottom: 1px dotted;
}
/* Elements with href containing "example.com" */
[href*="example.com"] {
color: green;
}
/* Input elements with type="text" */
input[type="text"] {
border: 1px solid #ccc;
}
/* Links starting with "https" */
a[href^="https"] {
background: url(lock.png) no-repeat left;
}Combinator Selectors
Descendant Selector (Space)
Selects all descendants of a parent element.
/* All p elements inside div elements */
div p {
color: red;
}
/* All li elements inside ul elements inside nav */
nav ul li {
display: inline-block;
}Child Selector (>)
Selects direct children of a parent element.
/* Direct children p of div */
div > p {
font-weight: bold;
}
/* Direct children li of ul */
ul > li {
margin-left: 20px;
}Adjacent Sibling Selector (+)
Selects the immediately following sibling.
/* p elements that come directly after h1 */
h1 + p {
margin-top: 0;
}
/* li elements that come directly after another li */
li + li {
border-top: 1px solid #eee;
}General Sibling Selector (~)
Selects all following siblings of the same type.
/* All p elements that follow h1 (not necessarily immediately) */
h1 ~ p {
color: gray;
}Pseudo-Class Selectors
Pseudo-classes select elements in a specific state.
Link States
a:link {
color: blue;
}
a:visited {
color: purple;
}
a:hover {
color: red;
}
a:active {
color: orange;
}Form States
input:focus {
border-color: blue;
outline: none;
}
input:valid {
border-color: green;
}
input:invalid {
border-color: red;
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}Structural Pseudo-Classes
/* First child */
li:first-child {
font-weight: bold;
}
/* Last child */
li:last-child {
margin-bottom: 0;
}
/* nth-child */
li:nth-child(odd) {
background-color: #f9f9f9;
}
li:nth-child(even) {
background-color: #fff;
}
/* Every 3rd child starting from 1 */
li:nth-child(3n+1) {
color: blue;
}Other Useful Pseudo-Classes
/* Elements that don't match a selector */
div:not(.special) {
opacity: 0.8;
}
/* Elements that have no children */
.empty:empty {
display: none;
}
/* Elements that are the only child */
:only-child {
text-align: center;
}Pseudo-Element Selectors
Pseudo-elements create virtual elements that don’t exist in the HTML.
/* First line of text */
p::first-line {
font-weight: bold;
color: blue;
}
/* First letter of text */
p::first-letter {
font-size: 2em;
float: left;
margin-right: 5px;
}
/* Content before element */
.quote::before {
content: '"';
font-size: 2em;
}
/* Content after element */
.quote::after {
content: '"';
font-size: 2em;
}
/* Selection styling */
::selection {
background-color: yellow;
color: black;
}Understanding Specificity
Specificity determines which CSS rule applies when multiple rules target the same element. It’s calculated using a point system:
- Inline styles: 1000 points
- ID selectors: 100 points each
- Class, attribute, pseudo-class selectors: 10 points each
- Element, pseudo-element selectors: 1 point each
Examples
/* Specificity: 0,0,0,1 (1 element) */
p {
color: red;
}
/* Specificity: 0,0,1,0 (1 class) */
.text {
color: blue;
}
/* Specificity: 0,1,0,0 (1 ID) */
#header {
color: green;
}
/* Specificity: 0,1,1,1 (1 ID, 1 class, 1 element) */
#header .text p {
color: purple;
}The rule with the highest specificity wins. If specificity is equal, the last rule in the CSS wins.
Specificity in Action
<div id="header">
<p class="text">This paragraph has multiple styles applied</p>
</div>/* Specificity: 0,0,0,1 */
p {
color: red;
}
/* Specificity: 0,0,1,0 */
.text {
color: blue;
}
/* Specificity: 0,1,0,0 - This wins! */
#header p {
color: green;
}
/* Inline style - Highest specificity */
<p class="text" style="color: purple;">This paragraph...</p>!important Declaration
The !important declaration overrides all other declarations, even inline styles. Use sparingly as it breaks the natural cascade.
p {
color: red !important; /* This will always apply */
}Best Practices
- Avoid over-specificity: Don’t chain too many selectors
- Use classes for styling: Prefer classes over IDs for reusable styles
- Avoid !important: Only use when absolutely necessary
- Organize CSS logically: Group related selectors together
- Comment your CSS: Explain complex selectors
Common Selector Patterns
BEM (Block Element Modifier)
/* Block */
.card { }
/* Element */
.card__title { }
.card__content { }
/* Modifier */
.card--featured { }
.card__title--large { }Component-Based CSS
/* Component namespace */
.btn { }
.btn--primary { }
.btn--secondary { }
.btn--large { }Debugging Specificity Issues
Use browser developer tools to inspect specificity:
- Open DevTools (F12)
- Select an element
- Check the “Computed” tab
- Look at which rules are crossed out (overridden)
Complete Example
<!DOCTYPE html>
<html>
<head>
<style>
/* Base styles */
body {
font-family: Arial, sans-serif;
line-height: 1.6;
}
/* Element selectors */
h1, h2, h3 {
color: #333;
margin-bottom: 10px;
}
/* Class selectors */
.highlight {
background-color: #ffff99;
padding: 5px;
}
.btn {
display: inline-block;
padding: 10px 20px;
text-decoration: none;
border-radius: 5px;
}
.btn-primary {
background-color: #007bff;
color: white;
}
/* ID selector */
#header {
background-color: #f8f9fa;
padding: 20px;
border-bottom: 1px solid #dee2e6;
}
/* Descendant selectors */
#header h1 {
margin: 0;
color: #495057;
}
/* Pseudo-classes */
.btn:hover {
opacity: 0.8;
}
.btn:active {
transform: translateY(1px);
}
/* Attribute selectors */
input[type="text"] {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
input[type="text"]:focus {
border-color: #007bff;
outline: none;
}
/* Structural pseudo-classes */
li:first-child {
font-weight: bold;
}
li:last-child {
margin-bottom: 0;
}
/* Pseudo-elements */
p::first-letter {
font-size: 1.2em;
font-weight: bold;
color: #007bff;
}
.quote::before,
.quote::after {
content: '"';
font-size: 1.5em;
color: #6c757d;
}
</style>
</head>
<body>
<div id="header">
<h1>CSS Selectors Tutorial</h1>
</div>
<p class="quote">This is a highlighted paragraph with special styling.</p>
<a href="#" class="btn btn-primary">Primary Button</a>
<input type="text" placeholder="Enter your name">
<ul>
<li>First item (bold)</li>
<li>Second item</li>
<li>Third item</li>
<li>Last item (no bottom margin)</li>
</ul>
</body>
</html>Summary
CSS selectors are powerful tools for targeting HTML elements. Remember:
| Selector Type | Syntax | Specificity Points |
|---|---|---|
| Universal | * | 0 |
| Element | p | 1 |
| Class | .class | 10 |
| Attribute | [attr] | 10 |
| Pseudo-class | :hover | 10 |
| ID | #id | 100 |
| Inline style | style="" | 1000 |
Mastering selectors and understanding specificity will help you write cleaner, more maintainable CSS.
External Resources:
Related Tutorials: