::before and ::after Pseudo‑Elements in CSS

Abstract image used to represent ::before and ::after Pseudo‑Elements in CSS
Image by Jason Dent.

I realise that this type of article is perhaps a little basic amongst the type of people likely to visit my blog in the first place. However, working back over some basic CSS principles with a new junior developer who has joined our team reminded me that, sometimes, these principles get missed, or forgotten, or just aren't covered in enough detail at your average code boot camp. So, for posterity's sake, I wanted to write today about the ::before and ::after pseudoelements.


A brief note about :: vs. :

A brief aside quickly before we begin: the more eagleeyed amongst you may notice that I'm using two colons when speaking about these pseudoelements (e.g.: ::before) rather than the singlecolon mnemonic you might be familiar with (e.g.: :before). I've gone into this difference, and why I'm using :: here, in much more detail in a previous article. CSS3 introduced the doublecolon notation to distinguish pseudoelements from pseudoclasses. Browsers still accept the older singlecolon forms of before and after for compatibility; I use two colons here to make the distinction clear.


Introduction

With that out of the way, let's begin. In CSS, the ::before and ::after pseudoelements offer a powerful way to add (or inject) content before or after an element's main content area without changing the underlying HTML. These pseudoelements, especially when combined with other CSS tools such as pseudoclasses like :hover, offer us a way to enhance the functionality and interactivity of our websites and applications.


What Are the ::before and ::after PseudoElements?

As frontend developers, we use pseudoelements to insert styled content into the user's interface without the need to include it in the document's HTML. More specifically, the ::before and ::after pseudoelements allow us to insert content either directly before or after the selected element's content.


Basic Usage of ::before and ::after

In order to use either ::before or ::after, we also need to include the content property. This dictates what will actually be rendered within the pseudoelement, and without it, nothing will be displayed at all.

Here's a brief example where we inject emojis before and after a title:

h1::before {
  content: '🌟 ';
  color: gold;
}

h1::after {
  content: ' ✨';
  color: gold;
}

With the markup <h1>Lorem ipsum</h1>, the CSS above will result in the user seeing:

🌟 Lorem Ipsum


Practical Applications

Decorative Elements

One of the most common uses for ::before and ::after is to add decorative content, for example, stylised bullet points, icons, or visual separators.

As an example, this CSS will add large, light grey quote marks before and after a blockquote element:

blockquote::before {
  content: '“';
  font-size: 2rem;
  color: #aaa;
}

blockquote::after {
  content: '”';
  font-size: 2rem;
  color: #aaa;
}

Creating a Clearfix

With the widespread adoption of flex and grid, this isn't as relevant as it once was. However, in the world of CSS floats, you would often find a situation where you needed to 'clear' a float, which ensures any elements following the floated element on the page fall beneath it.

The clearfix goes on the container of the floated children. Its after pseudoelement clears those floats, allowing the container to extend beneath them. In this example, display: table creates a CSS table box; it does not add an HTML table element:

.container::after {
  content: '';
  display: table;
  clear: both;
}

Combining ::before and ::after with PseudoClasses

Using ::before and ::after alongside pseudoclasses like :hover can allow us to develop quite intricate and interactive effects that respond to a user's actions. I've previously chatted about how pseudoclasses like :hover work, but combining them with pseudoelements can make your interfaces all the more dynamic.

For example:

button::after {
  content: ' (Click me!)';
  opacity: 0;
  transition: opacity 0.3s ease;
}

button:hover::after {
  opacity: 1;
}

Here, when a user hovers their mouse over a button, some additional text ("Click me!") fades into view, offering the user some visual feedback and an additional prompt to click the button.


Common Pitfalls and Tips

The content Property

This is actually the one that prompted me to write this in the first place. If you do not include a content property, then it will not render at all. If you just want to style the pseudoelement without including text within it, then you'll need to include content: "".

div::before {
  content: '';
  display: block;
  width: 100%;
  height: 5px;
  background-color: #000;
}

Positioning and Layout

By default, ::before and ::after are inline elements. If you intend to use them for more complex elements, then you'll often need to change their display or position properties. I often find myself doing both...


Best Practices for Using ::before and ::after

Only Use Them for Non‑Essential Content

Keep essential information in the HTML. Screen readers may announce generated content, but support varies between browser and assistivetechnology combinations. Decorative content still needs care too: text added through CSS is not automatically hidden from screen readers.

Combine with Transitions

When using ::before and ::after with :hover or other pseudoclasses, adding transitions can create a smoother user experience. Otherwise, they will just appear and disappear, potentially shunting the content around them.


Wrapping Up

The :before and :after pseudoelements are fairly basic, but powerful tools which enable us as frontend developers to add content and style elements outside of the restrictions of the HTML markup.

Whether we're adding decorative touches, creating interactive elements with :hover, or managing content flow, these pseudoelements are invaluable for modern web development.


Planning a platform change?

I help teams make difficult platform work clearer, from architecture decisions and migrations to launch recovery, performance, and search visibility.