I often have to do this thing again: Cover one element with another.
The key CSS technique is the same every time: The first element is positioned relative, and the second will be marked as absolute.
.original-element {
position: relative;
}
.covering-element {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
Often it’s a heading or caption that needs to cover an image, sometimes with a translucent background color or gradient. (I’d refer to this as an overlay.)
Usually, it’s a direct child of the first element which is being overlaid, but not always. Sometimes I want to overlay a pseudo-element, maybe even transition or animate it for a hover state. Either way, I do it so often that it makes sense to create a utility class that covers it, rather than writing out the CSS properties longhand every time.
Utility classes
Utility classes are single-purpose classes that can be applied to any element in our web application code. They usually (but not always) consist of a single CSS property and value. There are whole frameworks, like the increasingly-popular Tailwind CSS, that encourage a utility-first CSS methodology, where virtually all your CSS consists of applying utility classes. Even for those who have no wish to adopt such an extreme approach, many web projects include a sprinkling of utility classes to help things along.
As a utility class for our overlaid element would include several properties, it’s more verbose than most. Nevertheless, it does the job.
We can create a utility we’ll call .overlay
to cover an element:
.overlay {
position: absolute;
content: '';
top: 0;
right: 0;
bottom: 0;
left: 0;
}
While very flexible as a utility, using position: absolute
sets the element’s position in relation to the nearest relative-position ancestor, so we need to remember to set position: relative
on the element we want to cover (and ensure it’s an ancestor of the covering element).
In most cases, the element I want to use as an overlay is a direct child or a pseudo-element, so it might make sense to create further utilities to apply in those cases, which means we don’t additionally need to set position: relative
.
Any of these three classes could instead be applied to the parent – that is, the original element that we want to cover.
.overlay-child,
.overlay-before,
.overlay-after {
position: relative;
}
.overlay-child > *,
.overlay-before::before,
.overlay-after::after {
position: absolute;
content: '';
top: 0;
right: 0;
bottom: 0;
left: 0;
}
For the pseudo-elements, we need the extra property content
(in this case with a value of an empty string).
We now have three utilities – overlay-child
(to position a direct child element), overlay-before
(to position a ::before
pseudo-element) and overlay-after
(to position a ::after
pseudo-element), in addition to overlay
, which would apply when we want to target the element doing the covering. An example of when you might use overlay
instead of one of the parent-targeting classes is if the covering element is not a direct child but a descendent further down the DOM tree.
And we will have a result like this:
See the source