skip navigation

Fancy Menu Hover Effects

Codrops is a great source of info. One of their articles is about creating cool hover effects for menus. The effects are cool but I’ve never found them easy to implement. And because of that difficulty they’re time consuming to implement so easy to not to bother with. This article is an attempt to get a better understanding of how these work.

Here’s an example of one menu.

How?

There are a number of important principles that underscore these effects. They use some or all of the following:

  • The :hover pseudo-selector obviously (so not much use for mobile)
  • The pseudo-elements ::before and ::after and styling these into shapes and lines or even other words.
  • Because ::before and ::after use the default display: inline; you need to change this display: inline-block or position: absolute so that transform and other CSS properties will work on them. You can also use grid or flex and they will behave as child elements (that can presumabley be re-ordered!).
  • A transition property because animations happen over time, even if it’s only two tenths of a second.
  • A transform property. These allow movement of an element that won’t affect nearby objects. If using more than one keep them together: transform: scale(0.7) opacity: 0.1 translateX(150%);
  • Changing the position value to absolute or relative
  • Using opacity to fade effects in and out.
  • Using the z-index to stack the pseudo-elements. The parent can be set to isolation: isolate to keep the stacking context within itself, thus prevent the pseudo elements ending up behind it.

Optionally some effects may use:

  • a data attribute on the anchor tag: <a href="#" data-hover="menu 1"> that can be used in the ::before or ::after content value: content: attr(data-hover);
  • Some <span> tags inside the anchor tags.
  • The property pointer-events has a default of auto but might need to be set to none, particularly on pseudo-elements to stop them reacting to the cursor. This switches off things like cursor: pointer on links.
  • backface-visibility is used when a 3D rotation takes place. The default value is visible meaning you’ll see text from the other side. You can set it to backface-visibility: hidden if you want to hide it.

Some things to watch out for

  • You often want to style ::before and ::after together. But you cannot use these pseudo elements with :is() and :where().

  • When you hover you are hovering over the anchor element NOT it’s pseudo elements which may not even be visible. Therefore watch your syntax: use a:hover::before and NOT a::before:hover.

  • Using z-index on pseudo elements is tricky.

    Firstly if the parent’s display is neither to grid nor flex it won’t work unless the position value is set to something other than the default of static, eg relative.

    Secondly using postion: relative with a z-index value creates a new stacking context. This means all z-index values are relative to this particular group or parent and child elements.

    Thirdly because although the pseudo-elements are inside their parent element they can end up behind out out of view. You may want something behind the text but still visible. So a::before is inside a. To make this work set the pseudo-element (inside) to a negative value and the parent to a positive one. Setting parent’s z-index from the default of auto sets a new stacking context for it’s chidren. Now they can’t go behind the parent.

    A better way is is to set isolation: isolate on the parent instead of a z-index value. This means the parent’s layering position is not fixed. It is also more obvious what the intention is when we read the code.

  • When setting the position: absolute in the pseudo-elements don’t forget to set position: relative in the parent, ie. in these cases the anchor tag.

Z-index rules

So after writing the above I thought I’d better write a brief synopsis of rules around the z-index.

  1. Only works on elements that have a position set (ie. not the default of static).
  2. When a stacking context is set the root element is at the back, then elements with a negative z-index, then elements with no z-index (default is 0?), then elements with a positive z-index.
  3. If two or more elements have the same z-index (or is unset) the order is determined by their position in the HTML document. Lower down in the doc appear above those lower down.