Icon for parent category 'Websites'

Pseudo-Elements

Last chapter, I remarked how I found the name pseudo-classes a bit unhelpful. This chapter, however, might shed some light on why they chose that name.

Because pseudo-elements is a good name for what this chapter will discuss. A pseudo-element is a visual element added to the page that isn’t actually part of the original HTML.

In other words, a “fake element”. A “pseudo-element.”

What does that mean? For example, think back to the chapter about lists. By default, lists receive a bullet (or number) in front of them. This is a visual element … which isn’t part of the original HTML! They’re a pseudo-element that the browser adds automatically.

How would you style those? Exactly, you’d use the correct pseudo-element to target them in a selector.

Syntax

You can use the same syntax as pseudo-classes, although the “correct” syntax is to use two double colons (::) instead.

For example, to select the first letter of a paragraph, you’d use p::first-letter. Or see the example below to style the first-line.

Again, the complete list of Pseudo-Elements is extremely long. There are many little visual elements that browsers add by default, especially when it comes to media or input/forms.

Even worse, they all decided to name them differently, requiring different prefixes. (Such as -webkit- for Google Chrome and -moz- for Mozilla Firefox.)

This chapter talks about the most common and most useful ones. For more advanced styling, you’ll always have to reference the latest status of the docs and browser compatibility.

Marker

Earlier, I gave the example of styling the list bullets.

How do you style these? By selecting them with the ::marker pseudo-element, then changing their content.

But wait, you might say, how do I add content inside something that doesn’t exist in the HTML?

Ah, good question! Pseudo-elements have a unique property that can’t be used anywhere else: content. It accepts any string.

The content property

This property is even more powerful than it might seem (at first glance).

You can also combine multiple strings, simply by typing them with a space in between.

When would I need that? Well, for example, what if you need the content to be dynamic? Some part of it is fixed (typed by you), but another part should be updated as the page is loaded?

You can use the attr(<attribute>) keyword!

This reads the value of the given attribute on the HTML element and places it in the content.

See the example below. Part of the content is a string typed by us, the other part reads an attribute (which we invented ourselves) from the element being styled.

Selection

Users can select parts of a webpage. (By tapping and then moving their mouse/finger.) When they do, the elements get a different color, to indicate that it’s selected.

You guessed it: the browser creates a pseudo-element to display this!

And you can control that with the ::selection pseudo-element.

Try selecting a part of the paragraph in the example below!

You’ll notice that my last rule (about font-style) doesn’t do anything. Why’s that?

Well, pseudo-elements are still fake elements. They don’t support everything. In fact, they only support very little of the full might of CSS. Don’t expect them to work magic—and if a rule doesn’t seem to be applied, it’s probably not an error on your part, but simply unsupported.

Before & After

These two pseudo-elements are the most versatile. They insert an extra element into the visual design. As expected, ::before inserts itself before the actual element, whereas ::after inserts itself after the actual element.

Example

You might’ve noticed that many buttons on this website have an arrow attached to them. (Which animates when you hover over the button.) With a few exceptions, this is done using a ::before element! There isn’t an actual arrow HTML element, nor did I manually add the arrow to each button.

By using a pseudo-element, I am able to insert a new visual element before all buttons, without cluttering the HTML document.

See the example below. It automatically inserts a label before each paragraph, which isn’t actually present in the HTML.

Support me and this website!

Want to support me?

Buy one of my projects. You get something nice, I get something nice.

Donate through a popular platform using the link below.

Simply giving feedback or spreading the word is also worth a lot.