7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (2024)

DigitalOcean provides cloud products for every stage of your journey. Get started with $200 in free credit!

CSS ::before and ::after pseudo-elements allow you to insert “content” before and after any non-replaced element (e.g. they work on a <div> but not an <input>). This effectively allows you to show something on a web page that might not be present in the HTML content. You shouldn’t use it for actual content because it’s not very accessible in that you can’t even select and copy text inserted on the page this way —  it’s just decorative content.

In this article, I’ll walk you through seven different examples that showcase how ::before and ::after can be used to create interesting effects.

Table of contents

  • Styling Broken images
  • Custom blockquote
  • Icon Bullet List
  • Animated toggle switch
  • Gradient border
  • Gradient overlays
  • Custom radio buttons
  • Wrapping up

Note that for most examples, I am only explaining the parts of the code that deal specifically with CSS pseudo-elements. That said, all of the CSS is available in the embedded demos if you want to see the code for additional styling.

Styling Broken images

When a user visits your website, their internet connection (or a factor beyond your control) might prevent your images from downloading and, as a result, the browser shows a broken image icon and and the image’s alt text (if it’s actually there).

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (1)

How about showing a custom placeholder instead? You can pull this off using ::before and ::after with a bit of CSS positioning.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (2)

First, we need to use relative positioning on the image element. We are going to use absolute positioning on one of the pseudo-elements in a bit, so this relative position makes sure make sure the pseudo-element is positioned within the content of the image element, rather than falling completely out of the document flow.

img { display: block; /* Avoid the space under the image caused by line height */ position: relative; width: 100%}

Next, let’s create the region of the broken image effect using the image’s ::before pseudo-element. We’re going to style this with a light gray background and slightly darker border to start.

img::before { background-color: hsl(0, 0%, 93.3%); border: 1px dashed hsl(0, 0%, 66.7%); /* ... */}

<img> is a replaced element. Why are you using ::before pseudo-element on it? It wont work!. Correct. In this scenario the pseudo-element will show in Chrome and Firefox when the image fails to load, which is exactly what you want. Meanwhile, Safari only shows the styling applied to the alt text.

The styling is applied to the top-left corner of the broken image.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (3)

So far, so good. Now we can make it a block-level element (display: block) and give it a height that fills the entire available space.

img::before { /* ... */ display: block; height: 100%;}
7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (4)

We can refine the style a little more. For example, let’s round the corners. We should also give the alt text a little breathing room by giving the pseudo-element full width and absolute positioning for better control placing things where we want.

img::before { /* ... */ border-radius: 4px; content: ""; position: absolute; width: 100%;}

If you stopped here and checked your work, you might be scratching your head because the alt text is suddenly gone.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (5)

That’s because we set content to an empty string (which we need to display our generated content and styles) and cover the entire space, including the actual alt text. It’s there, we just can’t see it.

We can see it if we display the alt text in an alternate (get it?) way, this time with help form the ::after pseudo-element. The content property is actually capable of displaying the image’s alt attribute text using the attr() function:

img::after { content: attr(alt); /* Some light styling */ font-weight: bold; position: absolute; height: 100%; left: 0px; text-align: center; top: 1px; width: 100%;}

This is awesome! In Chrome, at least.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (6)

But, in Firefox, not so much.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (7)

A quick fix is to target the alt attribute directly using an attribute selector (in this case, img[alt]), and target similar styles there so things match up with Chrome.

img[alt] { text-align: center; font-weight: bold; color: hsl(0, 0%, 60%);}

Now we have a great placeholder that’s consistent in Chrome and Firefox.

Custom blockquote

Blockquotes are quotes or an excerpts from a cited work. They’re also provide a really great opportunity to break up a wall of text with something that’s visually interesting.

There are all kinds of ways to style blockquotes. Chris has a set of five styles that go all the way back to 2007.

I want to look at another technique, one that incorporates ::before and ::after. Like we saw with the last example, we can use the content property to display generated content, and apply other properties to dress it up. Let’s put large quotation marks at the start and end of a blockquote.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (8)

The HTML is straightforward:

<blockquote> <!-- Your text here --></blockquote>

A few cosmetics in the CSS:

blockquote { font-style: italic; line-height: 1.618; font-size: 1.2em; width: 30em; position: relative; padding: 40px 80px;}

Note the position: relative in there because, as you’ll learn, it’s essential for positioning the blockquotes.

As you’ve probably guessed, we’re going to use ::before for the first quotation mark, and ::after for the closing one. Now, we could simply call the content property on both and generate the marks in there. But, CSS has us covered with open-quote and close-quote values.

blockquote::before { content: open-quote; /* Place it at the top-left */ top: 0; left: 0;}blockquote::after { content: close-quote; /* Place it at thee bottom-right */ bottom: 0; right: 0;}

This gets us the quotation marks we want, but allow me to button up the styles a bit:

blockquote::before,blockquote::after { background-color: #cccccc; display: block; width: 60px; height: 60px; line-height: 1.618; font-size: 3em; border-radius: 100%; text-align: center; position: absolute;}

Icon Bullet List

We have ordered (<ol>) and unordered (<ul>) lists in HTML. Both have default styling dictated by the browser’s User Agent stylesheet. But with ::before pseudo-element, we can override those “default” styles with something of our own. And guess what? We can use emojis (😊) on the content property!

.name-list li::before { content: "😊"; margin-right: 15px; font-size: 20px;}

While this is great and all, it’s worth noting that we could actually reach for the ::marker pseudo-element, which is designed specifically for styling list markers. Eric Meyer shows us how that works and it’s probably a better way to go in the long run.

Animated toggle switch

One of the neatest tricks for styling forms is creating a toggle switch out of a standard HTML checkbox. In fact, Preethi Sam recently shared one approach for it when showing off a handful of other checkbox styling tricks using CSS masks.

True to its name, a toggle switch is used to toggle or switch between the checked and unchecked states of a checkbox element.

<form class="container"> <label class="switch"> <input type="checkbox" /> </label></form>

The customization is all thanks to modifications added to the <input> element via the ::before and ::after pseudo-elements. But first, here is some baseline CSS for the <form> element:

.container { background: #212221; background: linear-gradient(to right, #1560bd, #e90); border-radius: 50px; height: 40px; position: relative; width: 75px; }
7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (9)

We’re going to “hide” the checkbox’s default appearance while making it take up the full amount of space. Weird, right? It’s invisible but still technically there. We do that by:

  • changing its position to absolute,
  • setting the appearance to none, and
  • setting its width and height to 100%.
input { -webkit-appearance: none; /* Safari */ cursor: pointer; /* Show it's an interactive element */ height: 100%; position: absolute; width: 100%;}

Now, let’s style the <input> element with its ::before pseudo-element. This styling will change the appearance of the input, bringing us closer to the final result.

input::before { background: #fff; border-radius: 50px; content: ""; height: 70%; position: absolute; top: 50%; transform: translate(7px, -50%); /* Move styling to the center of the element */ width: 85%;}

What, wait? You’d think that ::before wouldn’t work with a replaced element, like <input>. And that’s true, but only when the input type is image which is equivalent to an <img> element. Other form controls, like a checkbox, are defined as non-replaced elements in the HTML spec.

Next, we need to create the “toggle” button and it just so happens we still have the ::after pseudo-element available to make it. But, there are two things worth mentioning:

  1. The background is a linear-gradient.
  2. The “toggle” button is moved to the center of the <input> with the transform property.
input::after { background: linear-gradient(to right, orange, #8e2de2); border-radius: 50px; content: ""; height: 25px; opacity: 0.6; position: absolute; top: 50%; transform: translate(7px, -50%); transition: all .4s; width: 25px;}

Try clicking on the toggle button. Nothing happens. That’s because we’re not actually changing the checked state of the <input>. And even if we were, the result is… unpleasant.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (10)

The fix is to apply the :checked attribute to the ::after pseudo-element of the <input>. By specifically targeting the checked state of the checkbox and chaining it to the ::after pseudo-element, we can move the toggle back into place.

input:checked::after { opacity: 1; transform: translate(170%, -50%);}

Gradient border

We can decorate images with borders to make them stand out or fit more seamlessly within a design. Did you know we can use a gradient on a border? Well, we can with ::before (there are other ways, too, of course).

The core idea is to create a gradient over the image and use the CSS z-index property with a negative value. The negative value pulls the gradient below the image in the stacking order. This means the image always appears on top as long as the gradient has a negative z-index.

.gradient-border::before { /* Renders the styles */ content: ""; /* Fills the entire space */ position: absolute; top: 0; left: 0; bottom: 0; right: 0; /* Creates the gradient */ background-image: linear-gradient(#1a1a1a, #1560bd); /* Stacks the gradient behind the image */ z-index: -1;}figure { /* Removes the default margin */ margin: 0; /* Squeezes the image, revealing the gradient behind it */ padding: 10px;}

Gradient overlays

This is similar to what we did in the previous example, but here, we’re applying the gradient on top of the image. Why would we do that? It can be a nice way to add a little texture and depth to the image. Or perhaps it can be used to either lighten or darken an image if there’s text on top it that needs extra contrast for legibility.

While this is similar to what we just did, you’ll notice a few glaring differences:

figure::before { background-image: linear-gradient(to top right, #1a1a1a, transparent); content: ""; height: 100%; position: absolute; width: 100%;}

See that? There’s no z-index because it’s OK for the gradient to stack on top of the image. We’re also introducing transparency in the background gradient, which lets the image bleed through the gradient. You know, like an overlay.

Custom radio buttons

Most, if not all, of us try to customize the default styles of HTML radio buttons, and that’s usually accomplished with ::before and ::after, like we did with the checkbox earlier.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (11)

We’re going to set a few base styles first, just to set the stage:

/* Centers everything */.flex-center { align-items: center; display: flex; justify-content: center;}/* Styles the form element */.form { background: #ccc; height: 100vh; width: 100%;}/* Styles the inputs */.form-row { background: #fff; border-radius: 50px; height: 40px; margin: 10px; overflow: hidden; position: relative; width: 150px;}

Now let’s remove the default styling of the radio buttons, again, with appearance: none;

.form-input { -webkit-appearance: none; /* Safari */ appearance: none;}

::before should be positioned at the top-left corner of the radio button, and when it’s checked, we change its background color.

.form-input::before { /* Renders the styles */ content: ''; /* Shows that it's interactive */ cursor: pointer; /* Positions it to the top-left corner of the input */ position: absolute; top: 0; left: 0; /* Takes up the entire space */ height: 100%; width: 100%;}/* When the input is in a checked state... */.form-input:checked::before { /* Change the background color */ background: #21209c;}

We still need to iron a few things out using ::after. Specifically, when the radio button is checked, we want to change the color of the circular ring to white because, in its current state, the rings are blue.

.form-input::after { /* Renders the styles */ content: ''; /* Shows that it's interactive */ cursor: pointer; /* A little border styling */ border-radius: 50px; border: 4px solid #21209c; /* Positions the ring */ position: absolute; left: 10%; top: 50%; transform: translate(0, -50%); /* Sets the dimensions */ height: 15px; width: 15px;}/* When the input is in a checked state... */.form-input:checked::after { /* Change ::after's border to white */ border: 4px solid #ffffff;}

The form label is still unusable here. We need to target the form label directly to add color, and when the form input is checked, we change that color to something that’s visible.

.form-label { color: #21209c; font-size: 1.1rem; margin-left: 10px;}

Click the buttons, and still nothing happens. Here what’s going on. The position: absolute on ::before and ::after is covering things up when the radio buttons are checked, as anything that occurs in the HTML document hierarchy is covered up unless they are moved to a new location in the HTML document, or their position is altered with CSS. So, every time the radio button is checked, its label gets covered.

You probably already know how to fix this since we solved the same sort of thing earlier in another example? We apply z-index: 1 (or position: absolute) to the form label.

.form-label { color: #21209c; font-size: 1.1rem; margin-left: 10px; z-index: 1; /* Makes sure the label is stacked on top */ /* position: absolute; This is an alternative option */}

Wrapping up

We covered seven different ways we can use the ::before and ::after pseudo-elements to create interesting effects, customize default styles, make useful placeholders, and add borders to images.

By no means did we cover all of the possibilities that we can unlock when we take advantage of these additional elements that can be selected with CSS. Lynn Fisher, however, has made a hobby out of it, making amazing designs with a single element. And let’s not forget Diana Smith’s CSS art that uses pseudo-elements in several places to get realistic, painting-like effects.

7 Practical Uses For The ::before And ::after Pseudo-Elements In CSS | CSS-Tricks (2024)


What is the use of before and after pseudo elements in CSS? ›

The CSS :before and :after properties are what also known as pseudo elements. They are used to add something before or after the content of an element.

When to use :: before and :: after? ›

In fact, MDN defines ::before as “the first child of the selected element” and ::after as “the last child of the selected element”. Because these pseudo elements appear within the selected element, they can only be used for container tags and not for empty tags.

What is the use of :: in CSS? ›

Syntax. For example, ::first-line can be used to change the font of the first line of a paragraph. Double colons ( :: ) are used for pseudo-elements. This distinguishes pseudo-elements from pseudo-classes that use single colon ( : ) in their notation.

What is the use of :: after in HTML? ›

Definition and Usage

The ::after selector inserts something after the content of each selected element(s).

What is the point of using :: after? ›

In CSS, ::after creates a pseudo-element that is the last child of the selected element. It is often used to add cosmetic content to an element with the content property.

What is the use of CSS pseudo code? ›

A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s). For example, the pseudo-class :hover can be used to select a button when a user's pointer hovers over the button and this selected button can then be styled.

What is the meaning of before and after? ›

Main uses of before (earlier than) and after (later than): • As a preposition: after lunch. before dinner. After thanking them I left.

What is the use of :: selection in CSS? ›

The ::selection CSS pseudo-element applies styles to the part of a document that has been highlighted by the user (such as clicking and dragging the mouse across text).

What does a :: first letter mean in CSS? ›

::first-letter. The ::first-letter CSS pseudo-element applies styles to the first letter of the first line of a block container, but only when not preceded by other content (such as images or inline tables).

What are pseudo-elements and pseudo-classes? ›

Pseudo-classes enable you to target an element when it's in a particular state, as if you had added a class for that state to the DOM. Pseudo-elements act as if you had added a whole new element to the DOM, and enable you to style that.

What is :: before in HTML CSS? ›

::before. In CSS, ::before creates a pseudo-element that is the first child of the selected element.

What is the :: marker in HTML? ›

Definition and Usage

The ::marker selector selects the marker of a list item. This selector works on any element set to display:list-item.

How to use after using CSS? ›

The CSS ::after selector can be used to insert content after the content of the selected element or elements. It's used by attaching ::after to the element it is to be used on. In the example above, we're appending " - Buzz Lightyear" in blue to the element with the class buzz .

Which property is required for pseudo-elements before and after? ›

The content attribute. This property is used with the :before and :after pseudo-elements to generate content in a document. Values have the following meanings: none - The pseudo-element is not generated.

What is the purpose of the pseudo class in CSS? ›

Use CSS Pseudo-classes to Highlight User's Position

When a user points to an object on a web page with a mouse, it's helpful if that object responds in some way. For example, when a user hovers over a link, the color and background-color of that link could be reversed.

Can I use a before or after pseudo element on an input field? ›

They are used for container-type elements. While the input tag is not a container-type element. It cannot contain other elements inside it. Note: We cannot use ::before and ::after with an input field.

How to use two pseudo-elements in CSS? ›

Multiple pseudo-elements can be created with the ::before(ordinal) and ::after(ordinal) notation, where 'ordinal' is a positive integer. ::before pseudo-elements are ordered descending by 'ordinal' from the host element's content edge.

Top Articles
Latest Posts
Article information

Author: Kareem Mueller DO

Last Updated:

Views: 6593

Rating: 4.6 / 5 (66 voted)

Reviews: 89% of readers found this page helpful

Author information

Name: Kareem Mueller DO

Birthday: 1997-01-04

Address: Apt. 156 12935 Runolfsdottir Mission, Greenfort, MN 74384-6749

Phone: +16704982844747

Job: Corporate Administration Planner

Hobby: Mountain biking, Jewelry making, Stone skipping, Lacemaking, Knife making, Scrapbooking, Letterboxing

Introduction: My name is Kareem Mueller DO, I am a vivacious, super, thoughtful, excited, handsome, beautiful, combative person who loves writing and wants to share my knowledge and understanding with you.