[Fixed] CSS :after element is not working

A few ways to fix why :after element is not working. 1. We need to check if we are using the right HTML tags, 2. using the content property correctly and 3. Check the browser combatibility.

Apr 20, 2022 | Read time 8 minutes

๐Ÿ”” Table of contents

When creating web designs or interfaces, we can use pseudo-elements to keep our HTML clean. Insteading of adding a heap of HTML tags and styling them, coming up with class names, etc we can just use pseudo elements such as :after.

What is the :after element?

The :after pseudo element combined with the content CSS property creates a child element inside a given element after its contents.

Alternatively the :before pseudo element (when combined with the content property) creates a child element before the elementโ€™s contents. If you are looking for fixing issues specifically for ::before check out my post here How to fix CSS before not working issues

To visualize this, consider the following paragraph HTML element with โ€œHello worldโ€ as its contents. We can see the layout of the HTML element with the :before and :after child elements expanded:

    ::before <!-- the before child element -->
    "Hello World"
    ::after <!-- the after child element -->

To add style to these pseudo elements, we need to use the content CSS property

.my-element::before {
  content: "";

.my-element::after {
  content: "";

๐Ÿ’ก Tip - whats the difference with ::after and :after?

Using ::after (two colons) vs :after (one colon) is just based on the version of CSS. CSS3 version uses the two colons (::) since with this version it also introduced pseudo classes. Having two colons just distingishes from pseudo elements and pseudo classes. The CSS2 version uses one colon (:) - most browsers will support both versions.

Browsers such as IE8 do not support CSS3, so you will need to stick with the single colon (CSS2) syntax.

Reason 1 - not providing the content property

A common reason when using the :after pseudo elements is that your styles is not appearing. We need to delare content:"" property!

Lets say we have the following style - we want a red box inside the .my-element class.

.my-element::after {
  background: red;
  width: 100px;
  height: 100px;

This does not work because we dont have the content property specified. Now the content property does not need to have a value, according to the spec we just need to specify it - even if its a empty string:

.my-element::after {
  content: ""; /* :after will only appear if this content is declared */
  background: red;
  width: 100px;
  height: 100px;

Reason 2 - not valid with the HTML tag

One reason why :after pseudo elements is not working is that you are using replaced elements. So what the heck is a replaced element?

According to the HTML specificiation (https://html.spec.whatwg.org/multipage/rendering.html#replaced-elements) - the following elements can be replaced elements: <audio>, <canvas>, <embed>, <iframe>, <img>, <input>, <object>, and <video>.

Additionally it wont work with <br> elements too.

Basically replaced elements will have all its contents replaced - so when rendered by the browser, we cannot see any :after or :before pseudo elements. Therefore the styling will not apply.

So if you are using :after for the above HTML tags, then most likely it will not work. For example, in the below, we want to add text after and before images. This will not work since <img> is a replaced element!

img::before { /* will not work because its a replaced element */
  content: "before";
img::after { /* will not work because its a replaced element */
  content: "after";

More information can be found here: https://developer.mozilla.org/en-US/docs/Web/CSS/Replaced_element

Reason 3 - content property is not valid

Another common reason why the :after pseudo element is not working and picking up your styles is that you are using the content property incorrectly.

Keep in mind that the content property will not work on regular elements - it only applies to :after and :before

.my-element { 
  content: "before"; /* will not work because content applies only to :after and :before */

๐Ÿ’ก Tip - using HTML in content will not work

.my-element::after { 
  content: "<p>Hello world! </p>"; /* will not worlk */

The content property will only accept the following inputs:

  • a string value - content:"Blah" - string values and even emojis can be used!
  • a empty string content:""
  • image urls - url(/path/to/image.jpg); - the image will be inserted at exact size and cannot be resized
  • counter() function - content: counter(li)
  • attr() function content:attr(data-value) - this will take the string value of the HTML attribute and renders it in the content section

๐Ÿ’ก Tip - to combine strings in content, separate them with a whitespace

Lets say you are using multiple calls to the CSS function of attr() to build up your content value.

.element::after {
    content: attr(class) ' ' attr(data-size) '!';

Unlike programming languages such as JavaScript, to concatenate the strings and values together, we just separate the with whitespace instead of + (plus) or . (dot).

Consider the following HTML, we want to have a :after pseudo element to display the data-name and data-age:

<div class="element" data-name="john" data-age="33"></div>
.element::after {
    content: attr(data-name) '=' attr(data-age) '!';

Browser support and bugs

There are limitations on the use of the :after and :before pseudo elements - so we need to consider browser combatbility. Some common gotchas include:

  • IE9, IE10, IE11 ignore CSS rem units in the line-height property
  • Firefox & Edge do not support :after and :before for input fields
  • Animation and transition support limited on IE, Safari and Safari Mobile. Chrome supports this as of version 26.
  • IE8 only supports the single-colon CSS 2.1 syntax (i.e. :pseudo-class). It does not support the double-colon CSS3 syntax


In this article we went over a few reasons why the :after pseudo element does not work.

To troubleshoot, we can follow the below checklist:

  1. Check that we are providing the content CSS property when defining our :after element. The content property can even be a empty string, but it has to be there to enable the :after element and its styles to appear
  2. Verify that we are using the :after element on the right HTML tags. Replaced elements such as <audio>, <canvas>, <embed>, <iframe>, <img>, <input>, <object>, and <video> will not support :after and :before elements. This is because on render, their whole content will be replaced (including the psuedo elements)
  3. Check that we are using the content CSS property correctly - cannot use HTML tags, make sure it is a string input value, when combining strings and CSS functions such as attr() we can combine them with the space character instead of a + (plus)
  4. Determine browser support - IE uses single colon (CSS2) syntax instead of double colon (CSS3), animation and transition support is limited

๐Ÿ‘‹ About the Author

G'day! I am Huy a software engineer based in Australia. I have been creating design-centered software for the last 10 years both professionally and as a passion.

My aim to share what I have learnt with you! (and to help me remember ๐Ÿ˜…)

Follow along on Twitter , GitHub and YouTube