CSS has grown exponentially during the past few years in terms of features for developers. And much of that goes unnoticed by your everyday programmer and could take years for these features to gain any kind of popularity.
While most of us are familiar with the basics like classes, IDs, and element selectors, mastering more advanced CSS selectors can make your stylesheets cleaner, more efficient, and flexible.
In this article, I shall explore advanced CSS selectors that are often overlooked but can help you craft highly specific and nuanced styles. By the end, you'll be able to write CSS that does more with less and create effects that were previously only possible with JavaScript.
1. Attribute Selectors
Attribute selectors allow you to target elements based on their attributes. This can be handy for targeting input fields, links, or any element with a specific attribute value, such as 'text' or 'checkbox'.
Example: Targeting specific input types
input[type="text"] {
border: 1px solid #000;
}
input[type="checkbox"] {
margin: 10px;
}
This selector targets <input> elements that have a type attribute with a specific value. Beyond targeting types, attribute selectors are useful for:
[attribute^="value"] – element where the attribute starts with a specific value
[attribute$="value"] – element where the attribute ends with a specific value
[attribute="value"]* – contains a value
Example: Targeting links based on their href value:
a[href^="https"] {
color: green;
}
a[href$=".pdf"] {
text-decoration: underline;
}
Here, links starting with "https" are green, and links ending with .pdf are underlined.
2. :nth-child() and :nth-of-type()
The :nth-child() selector is a powerful tool for targeting specific elements based on their position within a parent element. It allows for much more complex and nuanced selections than simply styling all children in an element.
Example: Style every other row in a table
tr:nth-child(even) {
background-color: #f2f2f2;
}
You can use the nth-child function with even, odd, or a formula to create a variety of patterns.
Example: Style every third element
div:nth-child(3n) {
color: red;
}
The nth-of-type() works similarly but targets elements of a specific type within their parent. This is useful if you want to apply styles to the third 'p' element in a parent, for instance, and ignore other types of elements.
In a real world scenario, you might see this used in news feeds where the first element is typically designed to stand out more.
3. :not()
The :not() selector allows you to exclude elements from being selected. It’s perfect for when you want to apply styles to almost everything but a few exceptions.
Example: Style all links except external ones
a:not([href^="https"]) {
color: blue;
}
In this case, all links that are not external (i.e., those that don’t start with https) are styled in blue. This is an efficient way to manage exceptions without needing extra classes or IDs.
4. General Sibling Selector (~)
The general sibling selector selects all elements that are siblings of a specified element, which appear after it.
Example: Style paragraphs that follow any heading
h2 ~ p {
margin-top: 20px;
color: #555;
}
This rule applies to every 'p' element that comes after an 'h2', making it great for targeting content in blog posts or documents with hierarchical structure.
5. Adjacent Sibling Selector (+)
While the general sibling selector (~) targets all following siblings, the adjacent sibling selector (+) only applies to the very next sibling.
Example: Style the first paragraph after a heading
h2 + p {
font-weight: bold;
margin-top: 0;
}
This rule will only style the first paragraph after any 'h2', leaving the rest unaffected.
6. ::before and ::after Pseudo-Elements
The ::before and ::after pseudo-elements allow you to insert content before or after an element’s actual content. While commonly used for decorative purposes, these pseudo-elements can also be handy for adding icons or other stylistic elements without adding extra markup.
Example: Add a quote icon before blockquotes
blockquote::before {
content: '“';
font-size: 50px;
position: absolute;
left: -20px;
top: 0;
}
Here, the ::before selector is used to add a large quotation mark before every 'blockquote'.
7. :empty
The :empty pseudo-class targets elements that have no children. This is useful for identifying and styling placeholders or elements that may have been mistakenly left empty.
Example: Style empty divs with a background
div:empty {
background-color: lightgrey;
height: 100px;
border: 1px solid #ddd;
}
8. :checked
The :checked pseudo-class targets any checkbox or radio button that is currently selected. It’s great for applying styles dynamically based on form selections.
Example: Highlight a checked checkbox
input[type="checkbox"]:checked + label {
background-color: #cfc;
}
In this case, when a checkbox is checked, its adjacent label will have a background color applied to it.
9. :focus-within
The :focus-within selector allows you to apply styles to an element when any of its descendants have focus. This is particularly useful for form containers.
Example: Highlight a form when its input is focused
form:focus-within {
border: 2px solid blue;
}
When any input inside the form gets focused, the entire form receives a blue border.
10. :target
The :target selector targets an element that matches the ID in the URL’s fragment. This is most often seen in anchor links.
Example: Style an element targeted by a URL fragment
#section1:target {
background-color: yellow;
}
When the URL changes to #section1, the corresponding section is highlighted with a yellow background.
Conclusion
Advanced CSS selectors are a game-changer for building more efficient, clean, and maintainable stylesheets. By mastering these often-overlooked tools, you can reduce redundancy, avoid bloated markup, and apply more dynamic styles directly in your CSS.