Every time we have to modify a CSS style on our web, Toni and I play rock-paper-scissors to see who is the “lucky guy” who gets to do the task. How come, you may ask? Well, for a long time working with HTML and CSS has been a pain in the a**, as fixing something on one end broke a lot of things elsewhere.

But the truth is CSS has changed a lot in recent years and if you take advantage of its new functionalities, it’s much easier to layout and style your website properly and effectively. In my opinion, two of the great advances in CSS we’ve recently seen are the inclusion, first, of flex
(to layout rows and columns) and, a little later, grid
(to layout grids).
CSS is full of features that can simplify your work. And today we are going to see two of them: pseudo-elements and pseudo-selectors.
How to “Create Content” with CSS Pseudo-Elements
CSS pseudo-elements are a mechanism to access parts of the HTML that do not have an associated node in the DOM. For example, a “part of our document” might be “the first line of a paragraph,” “the first letter of a paragraph,” or “the selection made by the user,” none of which has an associated node. But pseudo-elements are also a way to create content before or after an existing element through CSS.
The pseudo-elements available in CSS3 are:
::before
: adds content before an element::afte
r: adds content after an element::first-letter
: selects the first letter of “block” element (that is, those whosedisplay
property is set toblock
,inline-block
,table-cell
, etc.)::first-line
: selects the first line of a “block” element::selection
: refers to the parts of the document that the visitor has selected
As you can see, pseudo-elements are characterized by starting with a pair of colons (::
). And this is how you use them.
Selecting Parts of the Document
Suppose, for example, that we want a certain paragraph to have the first line in orange and underlined. Well, just do something like this:
p::first-line {
color: orange;
text-decoration: underline;
}
and you’ll get the correct result:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum mollis leo in turpis interdum, at pharetra velit elementum. Nam eget lacus sed lacus dictum scelerisque. Proin porta ligula sed mi semper, vel interdum massa auctor. Pellentesque et massa congue, tincidunt erat ac, tincidunt elit. Sed ac dolor metus. Nam commodo metus sed ligula consectetur interdum. Curabitur odio est, tempor id egestas nec, aliquam at nisl.
If, on the other hand, you want to modify the selection, the approach is exactly the same. Just keep in mind the number of CSS properties we can tweak is limited to color
, background
, cursor
and outline
:
p::selection {
background: #21acde;
color: white;
}
You can see the result in the following paragraph, assuming you select something:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum mollis leo in turpis interdum, at pharetra velit elementum. Nam eget lacus sed lacus dictum scelerisque. Proin porta ligula sed mi semper, vel interdum massa auctor. Pellentesque et massa congue, tincidunt erat ac, tincidunt elit. Sed ac dolor metus. Nam commodo metus sed ligula consectetur interdum. Curabitur odio est, tempor id egestas nec, aliquam at nisl.
Creating New Content
You also have the option to dynamically add content to your page. For example, imagine you have a list of items like this:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
Usually, this is how lists look like:
- One
- Two
- Three
but you can tweak it so that it each element is separated from the next one using a blue bar:
- One
- Two
- Three
using the ::after
pseudo-element on each item in the list as follows:
ul li {
display: inline;
}
ul li::after {
color: #21acde;
content: " | ";
display: inline-block;
}
With ::before
and ::after
pseudo-elements you can do many great things . For instance, you can combine multiple backgrounds in a single element, display the URLs of the links when the page is printed, order the floating elements, label blocks, beautify your typography, and so on.

Nelio Forms
A fantastic contact plugin using the block editor. In its simplicity lies the true power of this plugin. I love it, very versatile and it worked perfectly for me.

Wajari Velasquez
How to Apply Styles More Precisely Using Pseudo-Classes
CSS pseudo-classes allow us to select elements of our website that either are in a specific state or have some special property that sets them appart. The most common (and oldest) example is probably link pseudo-classes:
a:link
are those links you haven’t visited alreadya:visited
is any link you’ve already visiteda:hover
is the link you’re hoveringa:focus
matches the link that currently is focused (which is similar to being hovered, but using the keyboard instead of the mouse)a:active
matches the link you’re currently clicking on
In CSS there are about 60 pseudo-classes. A vast majority of them allow you to filter items based on their state (for example, you can select read-only elements using, you guessed it, the :read-only
pseudo-class). But there are some interesting “exceptions” to this rule that are worth mentioning.
But before we do, just a quick side-note: notice how you can distinguish a pseudo-class from a pseudo-element because the former starts with a single colon (:
) whereas the latter starts with two (::
).
Selecting an Element’s Children Using “child” and “of-type” Pseudo-Classes
Remember the example we saw earlier where we added a vertical bar to separate the elements of a list? Well, if you look closely, you’ll see that the rule we set doesn’t quite work:
- One
- Two
- Three
because the last element also includes a vertical bar, even though it shouldn’t. If we want to remove it, we can do something like this:
ul li {
display: inline;
}
ul li::after {
color: #21acde;
content: " | ";
display: inline-block;
}
ul li:last-child::after {
display: none;
}
which works exactly as you’d imagine:
- One
- Two
- Three
As you can see, all we are doing is adding a new rule using the pseudo-class :last-child
, which allows us to select the last li
element in our ul
list and, once we have it, hide its pseudo-element ::after
with the display
property set to none
.
Special Features of * -child and * -of-type
There are three variations of the *-child
pseudo-class:
:first-child
matches the first child of an element (duh!):last-child
does the same, but with the latter:nth-child(i)
, you guessed it, selects the ith element (so, for example,:nth-child(2)
matches the second child)
So let’s look at and think about the following CSS:
li strong:first-child {
color: orange;
text-decoration: underline;
}
and the following HTML snippet:
<ol>
<li>Lorem <strong>ipsum</strong> dolor <strong>sit</strong> amet.</li>
<li><em>Lorem</em> <strong>ipsum</strong> dolor <strong>sit</strong> amet.</li>
<li>Lorem <strong>ipsum</strong> dolor <em><strong>sit</strong></em> amet.</li>
</ol>
What do you think will happen? In principle, it seems that in all three cases, the word ipsum will be orange and underline, because ipsum is the first strong
child in each li element, right? Let’s see:
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
Well, close enough. Can you guess why did this happen?
The :first-child
pseudo-class applies to the first child of an element. In the first sentence, ipsum is the first strong
tag, which happens to be the first child to. In the second sentence, the first child node is em
(with the word Lorem) and then comes a strong
tag with the word ipsum. Therefore, this strong tag is not the “first child.” Finally, in the third sentence there are two tags that matched our rule: ipsum (it’s like the first sentence) and sit. Notice how sit is a strong
tag that’s the first child of its parent tag (em
).
So, what if we wanted to underline the first strong
tag of each li
item? Well, we have to use a different pseudo-class and make sure we only match elements that are direct children of li
:
li > strong:first-of-type {
color: orange;
text-decoration: underline;
}
which works as expected:
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
Pretty awesome, huh? Again, there are three variations of this pseudo-class:
x:first-of-type
matches the first sibling whose type isx
x:last-of-type
selects the lastx:nth-of-type(i)
matches the ith sibling whose type isx
Selecting the Opposite with :not
Finally, the pseudo-class I wanted to talk to you about today is :not
. :not
is a pseudo-class that matches those elements that do not meet a certain property. For example, let’s go back to our previous example:
- One
- Two
- Three
To solve the problem of the bar that appears in the last element, we basically (1) added the bar to all the li
elements and (2) overwrite the rule in the last element and hide it:
ul li {
display: inline;
}
ul li::after {
color: #21acde;
content: " | ";
display: inline-block;
}
ul li:last-child::after {
display: none;
}
But this doesn’t seem very optimal, does it? We’re overshooting with the first tule and we then need to fix our styles in the last element. What we really wanted was to add the bar to all the elements except the last one…
Well, we can achieve this by applying the pseudo-class :not
and combining it with :last-child
:
ul li {
display: inline;
}
ul li:not(:last-child)::after {
color: #21acde;
content: " | ";
display: inline-block;
}
which applies the style to all the li
elements that are not the last element (:not(:last-child)
), which perfectly describes our goal and thus solves our problem:
- One
- Two
- Three
In Summary
CSS pseudo-elements and pseudo-classes allow us to be much precise when accessing the different elements of our website. With them, we can write more concise and specific CSS rules, which simplifies its maintenance and avoids the possibilities of having to continually overwrite generic rules for specific cases.
I hope you liked this post and, if you did, please share it with your friends!
Leave a Reply