Introduction
Creating a design element that includes text and an opacity layer can be tricky. First, I'm going to walk through how not to do it. Then I'll show you a better way of styling your elements.
The goal will be to make something that transitions from this
to this...
The goal will be to make sure that the text doesn't change opacity when the element is hovered or focused. I'm purposely using an image here with a mostly white background so that you can see if the black text changes.
Setup
But before we get any further, let's define the markup we want to use. It can be the same for all cases, and doesn't need to be too complicated. Basically we need
- a link
- a div
- some text
Next let's add a little CSS to handle the link. The goal is to make sure it always covers the whole area of the image and text.
Don't Do This
Let's think about the div that holds the picture and the text for a moment. We know can add an image as a background property to the div and get it to scale with the browser size by setting the position and size. We can also make sure the whole element is the height we want by explicitly setting it.
At this point (if you also styled the text), you would have something that looks like the second image.
From here, you might think you could apply an opacity
to the container and be all set.
Sadly that won't work. Because now, all the text will also have that opacity applied to it. That's because opacity
applies to all the children of the element it's applied to. Not only that, but you'd end up without the ability to tint the opacity layer since you can't really apply both a background-image
and background-color
So you'd end up with an element that looks like this.
A Better Way
What we need is to make sure that the opacity layer has the following characteristics:
- it has no children elements
- it can be tinted
- it can be transitioned from some (0.5) to no (1) opacity
- it adds no extra DOM elements
This is an excellent job for.... pseudo-elements! These are so handy because they can only really be declared in CSS. You can't actually write them into HTML. Nevertheless, they exist when you ask for them. So let's get the div ready to style one correctly.
I want to cover the entire div with the pseudo-element :before
. To do that I'm going to use position: absolute
. However, I want to make sure that the browser knows to keep :before
within the context of the div and not within the context of the larger window. To do that, I set position: relative
on the div.
Next, I can create the pseudo-element by adding the selector and giving it content and a position which takes up the whole area of the div.
If I set a background color of grey on it, you'll see that it takes up the whole area.
Even though we can't see the image behind the grey, that's ok. It's still there. Now we can apply opacity to this background color and the image will show through.
Now we're in a good place.
Next, we want to make sure that when someone hovers or focuses on the link, the opacity changes to 1 and transitions nicely.
It's important to include the focus state so that people using keyboards will be able to get the visual effect of the change as well.