For most of us, CSS selectors fall into one of two categories: the ones we use every day, and the obscure ones we've never bothered to memorize. We've seen the latter around, but they aren't the first things we reach for.
However, if you’re looking to save time and markup, then adding a few more selectors to your process can make a huge difference.
The best part?
These aren't fancy, experimental features that only work on the latest browsers. These are practical tools you can start using today!
1. The Child Combinator (X > Y)
li {
color: black; // Default list color
}
ul.main-nav > li {
color: blue;
}
This is similar to the classic descendant combinator (X Y
) except this one only targets the direct children of the first element.
For example, in the HTML below, you could target the li
elements directly inside the ul.main-nav
, but not the li
elements inside the ul.dropdown-nav
.
<ul class="main-nav">
<li></li> <!-- Target this -->
<li> <!-- And this -->
<ul class="dropdown-nav">
<li></li> <!-- But not this -->
<li></li> <!-- Or this -->
</ul>
</li>
</ul>
As you can see, this is perfect for multi-level lists. It means we can change the text color in our main navigation without having to remove that style again in our dropdown menu.
2. Adjacent Sibling Combinator (X + Y)
h2 + p {
font-weight: bold;
}
In this example, we're targeting paragraphs, but only paragraphs that directly follow an h2 element in the DOM. Nothing else is affected!
<h2></h2>
<p></p> <!-- Target this -->
<p></p> <!-- But not this -->
Note: this also works with classes. The example below is from a client site where we gave them the ability to add different colored bands, and we had to adjust the styles accordingly.
// If another gray band follows this, remove its top padding.
section.gray-background + section.gray-background {
padding-top: 0;
}
// If a white band follows this, add extra padding.
section.gray-background + section.white-background {
padding-top: 2rem;
}
3. X:first-child / X:last-child
ul li:first-child {
border-top: none
}
ul li:last-child {
border-bottom: none
}
Ever been in a situation where you had to add .first
or .last
classes to your li
elements or grid items? This selector serves the same purpose, sparing you from that extra markup.
<ul class="menu">
<li></li> <!-- :first-child -->
<li></li>
<li></li>
<li></li>
<li></li> <!-- :last-child -->
</ul>
Saving some extra classes might not seem like a big deal on a Craft site where you have full control of your templates, but this can be a lifesaver on systems that generate their markup dynamically.
4. X:nth-child(n) / X:nth-last-child(n)
ul.alternating-bands li:nth-child(2n) {
background-color: white;
}
Similar to the last selector, but with a few differences. If you have a list, li:nth-child(1)
will select the first item on that list, li:nth-child(2)
will select the second, etc.
But the best part about this selector is its ability to target a variable set of children.
li:nth-child(2n)
will target every list item that's a multiple of 2 (an even number.) You can also use :nth-child(odd)
or :nth-child(even
).
Ever wonder about those lists or bands with alternating background colors? This is one of the easiest ways to achieve that effect using only CSS.
<ul class="alternating-bands">
<li></li>
<li></li> <!-- :nth-child(2n) -->
<li></li>
<li></li> <!-- :nth-child(2n) -->
<li></li>
<li></li> <!-- :nth-child(2n) -->
</ul>
Now, let's say you have a long, dynamically generated list with an unknown number of items. What would you do if you needed to select the second-to-last item on that list?
That's where X:nth-last-child(n)
comes in!
li:nth-last-child(2) {
bakground-color: red;
}
This works the same way as :nth-child(2
), only it starts from the end rather than the beginning.
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li> <!-- li:nth-last-child(2) -->
<li></li>
</ul>
Overall, this is one of the more complicated selectors on this list, and there's a lot more you can do with it. For a more detailed explanation, Wes Bos published a useful video here.
5. Negation Pseudo-Class (X:not(Y))
section:not(.white-background) {
color: white
}
Like many of the above selectors, the negation pseudo-class is useful when we want to keep our code clean and avoid repeating ourselves. The above example would change every section's text color to white except for those with a class of .white-background
.
<section class="black-background"></section>
<section class="gray-background"></section>
<section class="white-background"></section> <!-- Don't target this -->
<section class="blue-background"></section>
You can even combine this with the previous selectors in this post.
For example:
p:not(:first-child) {}
article:not(:last-child) {}
div:not(:nth-child(2)) {}
section:not(nth-last-child(2)) {}
6. Attribute Selectors (X[href="Y"])
a[href="https://www.gomasuga.com"] {
color: #4a7d90
}
With this selector, we can move beyond selecting elements to selecting elements with specific attributes. The example above will style all anchor elements that link to gomasuga.com. All other links will be ignored.
On its own, this tool is only so useful. But things get interesting when we introduce regular expressions to the mix.
For example, we can use the carat symbol (^
) to target just the beginning of the URL like this:
a[href^="http"] {
&:after {
// External link icon.
}
}
Depending on your setup, this is one way to differentiate between external links and relative links using only CSS.
You can also use the dollar sign ($
) to target just the end of a URL:
a[href$=".pdf"] {
&:after {
// PDF icon.
}
}
This is a great way to differentiate between web page links and other filetypes like PDFs.
If you found this article helpful, then there's always more to learn. Here are some more comprehensive resources regarding CSS selectors:
Mozilla Web Docs - CSS Selectors
W3 Schools CSS Selector Reference