CSS element overlap by using relative and absolute position

Published
29

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