Pseudo-elements are CSS keywords that can be used to style specific parts of an element. Pseudo-elements are declared by the use of double colons (::
) after a CSS selector:
seletor::pseudo-element{
properties: ...
}
Here are some commonly used CSS pseudo-elements:
::first-letter
: declare style for the first letter of a text element::placeholder
: declare the style for the placeholder attribute of an input element::before
: create and style a pseudo-element that represents the first child of an element::after
: create and style a pseudo-element that represents the last child of an element
The content of a pseudo-element is defined through its content property:
seletor::before{
content: "value"
}
Proper use of ::before
and ::after
can improve code maintainability, avoiding the use of unnecessary tags and contents, as we will see in the examples below.
Practical examples
All you will need to follow through the examples below is a text editor and a web browser of your preference.
Each example is structure around two files: index.html
and main.css
. Let us assume index.html
file has the template below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="main.css">
<link rel="stylesheet” type=”text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.1/css/bootstrap.min.css">
</head>
<body>
<!--YOUR EXAMPLE CODE HERE-->
</body>
</html>
This imports the main.css
, which is the file where we will put our stylesheet, and bootstrap.min.css
(fetched from a CDN,) which will provide some styling out of the box for the examples to follow, thus letting us focus on applying the ::before
and ::after
pseudo-elements.
Example 1: required input label
It is a common pattern in user interface design to place an asterisk sign right before the label’s content of a required input field. Consider the HTML snippet below, which implements a form with a required e-mail input field and an optional cellphone number field.
<form class="p-5 d-flex flex-column col-3">
<label class="required" for="email">E-mail</label>
<input required id="email"/>
<label for="cellphone">Cellphone</label>
<input id="cellphone"/>
</form>
The e-mail input field is declared as a required field and its associated label is stylized by the required
CSS class, implemented in our main.css
file:
.required::before{
content: "*";
color: #f80;
}
Click here to see the expected result on Codepen.
Note how this approach enforces styling and markup segregation: even though the asterisk sign could have been easily placed as part of the content of the label tag in the index.html
file, it is, in this context, a stilling mark whose function is to catch the user’s attention to a required input field and, therefore, must be placed in the main.css
file.
Example 2: Badges
The ::before
and ::after
pseudo-elements enable us to create shapes and effects that wouldn’t otherwise be possible by only using CSS classes. In this example, we are going to create a simple "On Beta" badge and use the ::before
and ::after
pseudo-elements to define its shape. Click here to see the expected result on Codepen.
Consider the content below for the index.html
file, where we declare a card containing a div stylized with the my-badge
CSS class.
<div class="card p-4 border-dark col-6 m-5">
<div class="my-badge">BETA</div>
<h1>Card title</h1>
<p>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable.</p>
<p>If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarassing hidden in the middle of text</p>
</div>
This time, our main.css
file will be a little more complex:
.my-badge {
position: absolute;
border-bottom: 30px solid #4d9c40;
border-left: 30px solid transparent;
border-right: 30px solid transparent;
height: 0;
width: 120px;
text-align: center;
transform: rotate(-45deg);
left: -40px;
top: 5px;
color: #fff;
}
.my-badge::before {
content: "";
border-bottom: 11px solid #2d6824;
border-left: 11px solid transparent;
transform: rotate(45deg);
left: -27px;
top: 24px;
position: absolute;
}
.my-badge::after {
content: "";
border-bottom: 11px solid #2d6824;
border-left: 11px solid transparent;
transform: rotate(45deg);
left: 76px;
top: 24px;
position: absolute;
}
The my-badge
CSS class creates a trapezoid and places it at the top left corner of the card. The ::before
and ::after
are then applied to create two darker triangles, which are rotated and placed behind the trapezoid, giving the depth effect in the badge’s background.
Without the ::before
and ::after
pseudo-elements, we would probably need to create two empty div tags and style them:
<div class="my-badge">
<div class="left-shadow"></div>
<div class="right-shadow"></div>
BETA
</div>
This, of course, comes at the cost of breaking styling and markup segregation, since HTML tags are being placed as styling elements.
Example 3: Transitions
The ::before
and ::after
pseudo-elements can be used in conjunction with CSS3 transitions to add awesome live effects to our applications.
In this last example, we are going to create a button with a hover effect. Click here to see the expected result on Codepen. This time, our HTML is going to be simple, just a button with a button
class:
<button type="button" class="button">Hover me</div>
In our stylesheet, we are going to declare the button
CSS class and the ::before
and ::after
pseudo-elements. We are also going to use the CSS pseudo-class :hover
to create the animation which is triggered when the user’s mouse passes over the button.
Our main.css
should look like this:
button {
color: white;
padding: 0.5rem 2rem;
margin: 3rem;
position: relative;
border: none;
z-index: 0;
}
.button::before {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0;
transition: all 0.5s ease-in-out;
border: 1px solid #112e42;
border-left-width: 0;
border-right-width: 0;
transform: scale(0.1, 1);
}
.button::after {
content: "";
position: absolute;
background-color: #4c5f6d;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
transition: all 0.3s ease-out;
z-index: -1;
}
.button:hover {
background-color: #fff;
color: #4c5f6d;
}
.button:hover::before {
opacity: 1;
transform: scale(1, 1);
}
.button:hover::after {
transform: scale(0.1, 1);
opacity: 0;
color: #4c5f6d;
}
In this example, we applied the ::before
to style the top and bottom borders of the button, while the ::after
pseudo-element handles the button’s background color. Thus, these pseudo-elements are applied in conjunction with transform
and transition
properties to provide different animations to different parts of an element.
Conclusion
In this post we had a brief introduction to pseudo-elements and how to use the ::before
and ::after
to improve the quality of our code and create awesome effects. From now on, every time you find HTML elements being used exclusively with a style purpose, think twice if these elements shouldn’t be replaced by pseudo-elements.
Unfortunately, it is impossible to address all the power of these pseudo-elements in a single post, but I hope that, with the examples above, you may see the infinite possibilities that they allow us to create.
For further reading
https://blog.logrocket.com/a-guide-to-css-pseudo-elements/
https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
We want to work with you. Check out our "What We Do" section!