CodingBanana
CodingBanana
CSS Fundamentals

Pseudo-elements

6 min read📖 Intermediate
A pseudo-element lets you create and style a part of an element that does not exist in your HTML. You insert invisible content from CSS alone using ::before and ::after — and then style it however you want.
.section-title::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 40px;
  height: 3px;
  background-color: #E50914;
}

input::placeholder {
  color: rgba(255, 255, 255, 0.5);
  font-style: italic;
}

Let me ask you something.

Have you ever seen a decorative line next to a heading? Or a quote with a big stylized quotation mark behind it? Or a form input where the placeholder text is a different color from the typed text?

None of that required extra HTML elements. It was all done with CSS pseudo-elements.

A pseudo-element lets you create and style a part of an element that does not actually exist in your HTML. You are essentially inserting invisible content from CSS alone and then styling it however you want.

The Double Colon Syntax

Pseudo-elements use two colons instead of one.

selector::pseudo-element {
  property: value;
}

One colon is for pseudo-classes like :hover and :focus. Two colons are for pseudo-elements like ::before and ::after. That is how you tell them apart.

::before

The ::before pseudo-element inserts content right before the content of an element. It sits inside the element but before anything else in it.

The one rule is that it always needs a content property. Even if you do not want any text you still write content: "" to make it appear.

A red play icon now appears before the heading text without touching the HTML at all.

Here is what is happening.

::before — inserts generated content right before the text inside the element.

content: "▶ " — this is what gets inserted. It can be any text, symbol, or even an empty string. Without this property the pseudo-element will not appear at all.

color: #E50914 — only the pseudo-element turns red. The heading text stays white because we targeted ::before specifically.

::after

The ::after pseudo-element works exactly like ::before but inserts content after the element's content instead of before it.

A short red underline now appears below the heading. Clean, decorative, and not a single extra HTML element needed.

Here is what is happening step by step.

content: "" — empty string. We do not want any text. We just want the element to exist so we can style it as a line.

position: absolute — takes the pseudo-element out of the normal flow so we can place it exactly where we want. This works because the parent has position: relative.

bottom: 0 and left: 0 — places it right at the bottom left of the heading.

width: 40px and height: 3px — makes it a short wide flat line.

background-color: #E50914 — the line is red.

This short underline pattern is one of the most common uses of ::after in real projects. You will see it on section headings, card titles, and feature labels everywhere.

💡

The combination of position: relative on the parent and position: absolute on a ::before or ::after pseudo-element is the most powerful pattern these pseudo-elements offer. It lets you place decorative elements anywhere around the parent without adding a single extra tag to your HTML. Use this for underlines, badges, overlays, and decorative shapes.

A Practical Use — Overlay on Movie Cards

Here is something you will actually use. When someone hovers over a movie card you want a dark overlay to appear on top of the image. You could add an extra div inside every card. But with ::after you can do it in pure CSS with no extra HTML.

Hover over any card and a dark overlay appears on top of the image. Move away and it disappears.

Here is what is happening.

.movie-card::after — creates an invisible overlay covering the entire card. width: 100% and height: 100% make it fill the card completely. background-color: rgba(0,0,0,0) means fully transparent — invisible by default.

.movie-card:hover::after — this is combining a pseudo-class and a pseudo-element together. When the card is hovered the overlay background changes to rgba(0,0,0,0.4) — a dark semi-transparent black. The overlay appears.

position: relative on the card and position: absolute on ::after — the overlay needs to cover exactly the card and nothing else. This combination makes that happen.

This is much cleaner than adding an extra div inside every single card in your HTML. One CSS rule handles all cards at once.

💡

Using ::after for hover overlays on cards is a pattern used on virtually every streaming platform, e-commerce site, and portfolio. It is clean, reusable, and keeps your HTML free of presentational elements. Any time you think you need an extra empty div just for visual effect consider whether ::after can handle it instead.

::placeholder

The ::placeholder pseudo-element styles the placeholder text inside input fields. By default placeholder text is a light gray. You can change its color, size, and style.

The placeholder text is now a soft semi-transparent white and italic. When the user starts typing their text is fully white and not italic because the actual input text is styled by the input selector — not the ::placeholder.

Here is what is happening.

input::placeholder — targets only the placeholder text inside the input. The actual typed text is not affected.

color: rgba(255,255,255,0.5) — semi-transparent white. Subtle enough to feel like a hint rather than real content.

font-style: italic — makes it clearly different from typed text so users know it is just a suggestion.

💡

Styling ::placeholder is one of those small details that makes a form feel genuinely designed rather than thrown together. On a dark background the default gray placeholder is often hard to read. A light semi-transparent white or a muted version of your accent color works much better and keeps the form readable and elegant.

Building the Netflix Clone

Let us bring all three pseudo-elements into our Netflix clone. The section headings get a red underline using ::after. The movie cards get a hover overlay using ::after. The email input gets a styled placeholder using ::placeholder.

Here is what every pseudo-element is doing.

.section-title::after — a short 40px red line sits under the heading. display: inline-block on the parent makes the heading only as wide as its text so the underline does not stretch the full page width.

.movie-card::after — an invisible overlay covers every card at all times. It is there but transparent so you cannot see it.

.movie-card:hover::after — the moment you hover the overlay turns dark. The card does not fade — instead a dark layer appears on top of it. This feels more cinematic than just opacity alone.

input::placeholder — the placeholder text is soft semi-transparent white and italic. Clearly a hint, not real content.

In the next lesson I am going to show you transitions — how to make all these hover states and color changes animate smoothly instead of snapping instantly. One line of CSS and everything starts feeling polished and alive. Come on in.

Learn about CSS Transitions →

Have anything to say about this lesson?

Your feedback helps improve these tutorials. If something was confusing or missing, let us know.

We don't currently reply to feedback — but if we add that feature in the future, we'll reach out to you.