Reducing The Need For Pseudo-Elements
Per the W3C spec, “a pseudo-element represents an element not directly present in the document tree". They have been around since version 1 of the CSS specification, when ::first-letter
and ::first-line
were introduced. The popular ::before
and ::after
pseudo-elements were added in version 2 — these represent content that does not exist in the source document at all. They can be thought of as two extra elements you can “tack onto” their originating element. When front-end developers hear “pseudo-elements”, we think of ::before
and ::after
more often than not, as we use them in various ways to add decorations to our elements.
There are additional pseudo-elements beyond these. They are listed in the spec across three categories: typographic, highlight, and tree-abiding.
Interestingly, after years of web development, I never found myself using ::first-line
, but it’s pretty neat and responds well to window resizing! Check it out.
Pseudo-Element Version
Many of you reading this will be accustomed to a pseudo-element version:
- We use a relatively positioned wrapper element with large right padding to accommodate our angle — this is our
<button>
; - Many of us, students of the sliding doors technique, are accustomed to nesting an element to take on the button’s background-color;
- Finally, we absolutely position a pseudo-element with its border rules into our
<button>
’s right padding empty space — we use::before
for this.
Aside from those steps, our hover styles must account for both our nested element and pseudo-element. This might seem manageable for you, but the more complicated our button designs get, the more overhead we have with hover styles. Also, with this version, buttons with word wrapping just plain fail.
Visit the final showcase to see these other button styles made easier without pseudo-elements. In particular, the blue bevel button’s pseudo-element version is pretty brutal. The amount of overall work is greatly reduced thanks to clip-path
.
Button Wipes
A wiping effect is a popular button style. I’ve included left-to-right and top-to-bottom wipes.
Pseudo-Element Version
This can be achieved by transitioning
a pseudo-element’s transform
.
- We absolutely position a
::before
pseudo-element and give it atransform: scaleX(0)
so it’s not visible. - We also must explicitly set its
transform-origin: 0 0
to ensure the wipe comes in from the left rather than center (transform-origin
defaults to center). - We set up
transitions
on thetransform
for some smooth jazz animation on/off hover. - Because our pseudo-element is absolutely positioned, we require a nested element to hold the button’s text,
position: relative
on this nested element creates a new stacking context so our text stays on top of our wiping pseudo-element. - On hover, we can target our pseudo-element and
transition
itsscaleX
to now be1 (transform: scaleX(1))
.
See the Pen Button wipe with pseudo-element by Marcel.
No Pseudo-Element Version
Why worry about nested elements, pseudo-element positioning, stacking contexts, and sprawling hover rules if we don’t have to?
We can reach for linear-gradient()
and background-size
to nail this down.
- We give our
<button>
abackground-color
for its default state, while also setting up alinear-gradient
viabackground-image
— but thebackground-size
will be0
, so we won’t see anything by default. - On hover, we transition the
background-size
to100% 100%
which gives us our wipe effect!
Remember, linear-gradient()
uses the background-image
property and background-image
supersedes background-color
, so this is what takes precedence on hover.
That’s it. No nested element required. Want a vertical wipe? Just change the linear-gradient
direction and the background-size
values. I’ve changed those via CSS custom properties.
See the Pen Button wipe with NO pseudo-element by Marcel.
Tiles With Screen Color Overlays
This is a common pattern where a semi-transparent color overlays a tile/card. Our example’s tile also has a background-image. It’s often important in this pattern to retain a set aspect-ratio so that tiles look uniform if more than one appears in a set.
Pseudo Version
Some of the same things come into play with our pseudo-element version:
- We use the aspect-ratio “padding-trick”, setting a 60% padding-top value (5:3 ratio) for our tile.
- We must position our screen color overlay pseudo-element, giving it a 100%
width
andheight
to fill the tile — we target this pseudo-element on hover to change itsbackground-color
. - Due to the pseudo-element’s absolute positioning, we must use a nested element for our text content, also giving it
position: absolute
in order for it to appear above our screen color overlay in the stacking order and to ensure it appears where it should within the tile.
See the Pen Tile screen color overlay with pseudo-element by Marcel.
No Pseudo-Element Version
It can be much simpler thanks to the aspect-ratio and background-blend-mode properties.
Note: aspect-ratio
does not work in Safari 14.x, but will in version 15.
That said, as of this writing, caniuse lists it with 70%+ global support.
- The “padding-trick” is replaced by
aspect-ratio: 400/240
(we could use any 5:3-based value here). - We use both
background-image
andbackground-color
properties in conjunction withbackground-blend-mode
— simply change thebackground-color
of our tile element on hover.
Background-blend-mode
background-blend-mode
blends a background-color
with an element’s background-image
. Any Photoshop users reading this will find background-blend-mode
reminiscent of Photoshop’s blending modes. Unlike mix-blend-mode
, background-blend-mode
does not create a new stacking context! So no z-index
hell!
See the Pen Tile screen color overlay with NO pseudo-element by Marcel.
- You can find the full showcase demo here →
Front-end development is exciting and fast-moving. With newer CSS properties, we can brush the dust off our old techniques and give them another look. Doing this helps foster reduced and simpler code. Pseudo-elements are helpful, but we don’t need to reach for them as much.