::before and ::after create a virtual element as the first or last child of the selected element. You use them to add decoration without adding to your HTML.
<style>
.price::before { content: "$"; color: #888; }
.new::after { content: " NEW"; background: #d94a00; color: #fff; font-size: 11px; padding: 2px 6px; border-radius: 4px; }
</style>
<p class="price">14.00</p>
<p class="new">The Slow Garden</p>
The content property is required
Without content, the pseudo-element does not exist. Even an empty one needs it:
.thing::before { content: ""; }
content can be:
- a string:
content: "→ " - empty:
content: ""(for shapes and decoration) - the value of an HTML attribute:
content: attr(href) - a counter:
content: counter(step)
Printing a link’s address
<style>
a::after { content: " (" attr(href) ")"; color: #888; font-size: 0.85em; }
</style>
<p>Read <a href="https://example.com/guide">the guide</a> online.</p>
Pseudo-elements behave like inline elements
By default, a pseudo-element is inline. Set display: block or inline-block to give it size, and position to place it. Many shapes and icons are built this way.
<style>
.quote { position: relative; padding-left: 36px; font-style: italic; }
.quote::before { content: "“"; position: absolute; left: 0; top: -8px; font-size: 56px; color: #d94a00; }
</style>
<p class="quote">Reading is a way of staying awake.</p>
Accessibility
Generated text is read out by some screen readers, and cannot be selected or translated. Use it only for decoration. Anything that carries meaning should be in the HTML.
Putting real content in ::before
Exercise: an external-link arrow
Add a small arrow ↗ after every link that starts with https.
Show a possible solution
a[href^="https"]::after { content: " ↗"; }