Alternatively, how to overlay an image on top of an element without interfering with clickable links underneath:

Intro

I first saw this effect on a deviantART profile page following their “v6″ redesign. Each profile has a long box of links to areas of interest regarding the profile owner. The box is clipped and fades to transparency in its default state. When hovered over, the box expands to its full height, and the fade disappears.

deviantART profile links

Honestly, I’m not crazy about the particular usage by deviantART. I think it obscures important links in a way that isn’t obvious to new users (most on-hover features are plagued by this disadvantage). However, the technique is useful whenever there is a long stream of continuous content that won’t be missed by your readers. For instance, I developed the trick behind this technique styling the “elsewhere” listing (by Lifestream) on the sidebar of this blog.

First steps: the fade gradient

The example I will present involves two divs adjacent in the markup: a faded element and an overlayed fade element. This was a constraint in my styled markup, though with a little tinkering, it could also work for an overlay element inside a container element.

Consider the following HTML markup:

<div class="faded">
  <a href="#">How to make</a>
  <a href="#">an element fade away</a>
  <a href="#">to transparency</a>
  <a href="#">using CSS</a>
</div>
<div class="fade"></div>

With today’s CSS, I know of no standard way to mask the opacity of an element’s content with an image. Because of this, we’ll have to settle for merely the illusion of doing so. To produce the fade effect, we’ll give the faded element a solid background color and style the overlayed fade element with a gradient image from 0% opacity at the top to the background color at the bottom (here’s an example).

This way, any content within the faded element will transition to the background color, giving the illusion that it is fading away (while it is actually being obscured):

.faded {
  background-color: #555;
}
 
.fade {
  height: 100px;
  background: url(/wordpress/wp-content/uploads/2008/12/fade.png) repeat-x;
}

To position the fade on top of the faded content, I used a negative top margin. Since the height of my gradient is 100px, I displaced it upwards 100 pixels so that the bottom would be at the base of the target faded element.

.fade { margin-top: -100px; }

Finally, to superimpose the fade element over the faded element, we’ll set a z-index value greater than 0. Since z-index only applies to positioned elements, we’ll need to also set both elements to have relative positioning.

.faded {
  position: relative;
}
 
.fade {
  position: relative;
  z-index: 10;
}

With these styles in place, we achieve a result that’s perfect visually:

Alas, the moment you try to click one of the links, you’ll realize that the fade element is obscuring the element below both visually and in terms of functionality. If you wanted to put clickable elements under the fade at this point, you’d be out of luck.

Making links clickable

A simple solution to this problem is to use CSS to remove the fade element when the mouse pointer is above it. We can achieve this by using the :hover pseudo-class to give the fade a negative z-index when it is hovered over, placing it underneath the faded element.

.fade:hover { z-index: -10; }

Unfortunately, there’s a problem with this proposal. If you’ve ever worked with selectors using the :hover pseudo-class, you may have encountered the flicker. As an illustrating example, try hovering your mouse pointer over this:

The problem is that the instant the fade element falls beneath the faded element, it is no longer being hovered over by the pointer. It then switches back to its normal style, placing it over the faded element, where it is once again being hovered over. This creates an infinite loop: the browser rapidly switches between the :hover and non-:hover styles for the fade element.

A solution

Fortunately, there is a simple trick to stop the flicker and make this technique work. Ironically, the trick came to me as a direct result of my horrific abuse of :hover pseudo-classes in the hurts_my_eyes subreddit. The key is to ensure that the fade element cannot return to being above the faded element when it loses :hover status.

To break the flicker cycle, we’ll give the faded element z-index of 20 when it is hovered over:

.faded:hover { z-index: 20; }

Like before, when the fade element is hovered over, it gets z-index: -10 and drops below, leaving the faded element hovered over. With this new rule since the faded element is hovered, it assumes a z-index of 20. Next, since the fade element is no longer hovered, it returns to its normal z-index of 10. Because the faded element now has higher z-index, and will as long as it is hovered over, no flicker cycle is created. The fade is effectively hidden until the mouse pointer leaves the area. Since the fade is displaced, links and other children of the faded element will be clickable.

Here’s an example employing this new rule, identical to the one at the top of this post.

Conclusion

When dealing with the :hover pseudo-class, the straightforward way to style a behavior can sometimes introduce flicker. This happens when the :hover style results in the element no longer being hovered upon, creating an infinite loop. The trick to resolving the flicker is to find a way to break the cycle, ensuring that the element with :hover styling will not be hovered over twice. In the case of this howto, the addition of a single CSS rule made all the difference.

The core of the z-index trick is an interesting two-step process where the :hover style of the fade element on top triggers the :hover style of the faded element underneath. Utilizing this second :hover was the key to breaking the cycle. This technique enables us to complete the effect we were after using only simple CSS.