The hidden powers of CSS…

Let’s talk about pseudo-elements and discover the hidden parts of the HTML DOM tree, revealed thanks to CSS!

This article is also available on Medium.

Last week, I talked about pseudo-classes and states in CSS, and I discussed how even leveraging just “basic” CSS, you can already add quite a lot of dynamism to your webpages.

But today, I want to dive even deeper into CSS and focus on another amazingly powerful feature of the language: pseudo-elements.

Where did that element come from?

When you start to work in web dev, one of the first tools you’ll discover and get used to working with is the browser developer tools, and in particular the JavaScript console and the DOM inspector. The first is useful to get all your logs and errors, while the second allows you to directly inspect the HTML tree structure of the page you are currently viewing.

This neat tool is handy to examine how others do it (since it lets you peek – to a certain extent – under the hood of other websites and check out their DOM structure), but it’s also essential to making sure that all the elements you created are here, and in the right place.

For example, if I write this very basic HTML structure, and then examine the tree in the browser, I do get a nice reassuring match:

But, then, someday you might find something like this:

It surely doesn’t look like an HTML tag (such as <div>, <p>, <ul>…), and it doesn’t even have any content or attributes! So – what is that ::after thingy?

This is a CSS pseudo-element: it is a “subpart” of your real HTML element (the <div> that is just before) that was accessed and “shown” because it was specifically styled thanks to CSS. Here, for example, I wrote the following CSS:

Which allows me to add a stylish arrow at the end of the line of my <h2> tag:

Remember how, in the other article, we used pseudo-classes to apply specific styles to our elements depending on their current state and context? Pseudo-elements are another way of styling part of an element, or its direct surroundings.

If you take a look at the MDN reference, you’ll see that there are way less pseudo-elements as there are pseudo-classes… but those few “specifiers” can already go a long way! Let’s take a look at some cool things we can do with pseudo-elements 🙂

Level 1: Using :first-letter to create a drop cap layout

Let’s say you’re working on a site with quite a lot of content, and an ancient/formal vibe. Then perhaps you’ll want to implement drop-cap letters on your paragraphs, to get this old “print-formatted” feel.

This kind of layout is straight-forward to do with pseudo-elements: you just need to use the :first-letter selector and some floating positioning to get a nice drop-cap on all your paragraphs:

Note: this CSS example is taken directly from a really nice gallery of usual layouts, – if you’re interested in modern layouts and slick designs, you should definitely take a look! 🙂

Level 2: Marking all required inputs in a form

Another common use case for pseudo-elements is adding some additional content around an element to highlight it somehow. This is possible thanks to two pseudo-elements: ::before (or :before) and ::after (or :after).

Those pseudo-elements can use the CSS content property to display some additional text or unicode symbols in a virtual “slot” around your main HTML element… and they can of course be styled just like normal elements!

So, for example, if you have a form and you wish to clearly differentiate between required and optional fields, you could use the ::after pseudo-element to automatically add a little red asterisk after every <label> with the “required” class:

This way, users instantly know what is required and, as the dev, you don’t have to manually add stars after each required field! 🙂

Level 3: Customising a progress bar!

Time to spice it up a little: this time, we are going to use several pseudo-elements to re-style an HTML tag: the <progress>. This is a native HTML element that has a native display in our modern browsers:

This display is nice and simple, but what if you want to relook your progress bar? For example, what if you’re working on some custom video player and you want you to make your video time bar all reddish and flashy like YouTube’s, on a dark background…?

Then you’ll obviously want to style your <progress>, so you might go for some naive CSS rules like this:

But this clearly doesn’t work! In fact, the progress selector only gives you access to some global context and it seems to completely “overwrite” the inner components like the progress bar fill, or the background colour of the remaining part. Those are subparts of the <progress>, so surely this sounds like we should use pseudo-elements, right?

Except we said there were only a handful of pseudo-elements, and none of those were about progress styling. How come? Ok so – I sort of lied earlier… 🙂

If you take a look at the MDN reference of some specific HTML tags, like the <progress>, and scroll down to the “See also” section, you’ll see that some of that related links look a lot like extra pseudo-elements:

And that’s because they are!

Basically, in addition to the “standard” base pseudo-elements that all browsers implement, you also have browser-specific pseudo-elements that will exist or not depending on the browser you’re currently using. Those pseudo-elements are prefixed by browser-specific labels:

Because those don’t exist on all browsers, to properly use them you’ll want to “stack” them and essentially handle as many cases as possible for your custom element (here, I show the page in Firefox in the top-right corner and in Brave in the bottom-right corner):

This way, you’ll have a chance that the user’s browser can take advantage of at least one of the browser-specific blocks and apply your custom style! 😉

However, you might notice that we don’t have the exact same result in the two browsers, and that it severely complicates our CSS stylesheet… And that’s the tricky thing with pseudo-elements: they are fairly hard to master and it can be difficult to insure a specific design across all platforms.

Beware the pseudo-elements…

If used improperly, pseudo-elements can “damage” the accessibility of a web page, and create inconsistent behaviours from one browser to another.

The ::before and ::after pseudo-elements are pretty standards and they work virtually everywhere; but lots of other pseudo-elements (::placeholder, ::target-text…) are still experimental and should be avoided in production code, because they could break on some devices or browsers.

And most importantly, as we saw with the third example, pseudo-elements often require you to handle quite a lot of cases for cross-browser compatibility, otherwise you’ll just remove native behaviours and reduce the accessibility!


All in all, CSS pseudo-elements are pretty powerful because they allow you to modify the internal subparts of your HTML elements, and even add some content around them thanks to ::before or ::after. But they also require a bit of getting used to, and, when you start working at that level of detail, you’ll need to stay sharp if you want to re-implement fully cross-browser interactivity… 😉

What about you: do you use pseudo-elements a lot? Do you know some interesting tricks with those? Feel free to share them in the comments, or to tell me if you other ideas of web-related articles and tutorials I could write!

Leave a Reply

Your email address will not be published.