Using Gradients To Build A Group Hover Effect

Gradients do a lot more than fill backgrounds. They can create texture, simulate depth, and even hide portions of an element through CSS masking. Another useful trick is using them to make one element respond visually when a different element is hovered. With a carefully placed gradient and the right selectors, you can make several elements change appearance at once based on a single hover target.

Depth And Shadows Versus Gradients

box-shadow is a common way to add depth on hover — it makes a button look pressed or lifted. Gradients can do something similar, and they open up other possibilities too. For example, a gradient can be positioned so that hovering one card affects all cards in a group, not just the one under the cursor.

The general idea looks like this: hover a single item and it gets the darkest, boldest background while the surrounding items fade into lighter shades of the same color. It is important to note that hover effects should never rely on color alone to communicate state, per WCAG 2.1 guidelines. The technique below is a base you can extend with more obvious visual cues for production use.

Setting Up The HTML And Base Styles

The markup is straightforward — six <div> elements inside a <section>. Five of them are interactive, and the sixth acts as the gradient layer that covers all five:

<section>
  <div></div>
  <div></div>
  <div</div>
  <div></div>
  <div></div>
  <div><!-- backdrop --></div>
</section>

The container needs position: relative so the absolutely positioned gradient stays inside the section boundaries:

section {
  position: relative;
  width: min(90vw, 400px);
}

All five interactive divs share styling. You can target them without touching the gradient layer using :not():

div:not(:last-of-type) {
  height: 40px;   
  background-color: rgb(0 128 0);
  border-block: 5px #fff solid;
}

Two details matter here. First, use CSS variables to keep values maintainable:

section {
  --c1: hsl(0 0% 0%); /* Black base color */
  --bg-color: rgb(0 128 0); /* Green */
  --height: 40px;
  --border: 5px white solid;
}

/* Style all divs but the last one */
div:not(:last-of-type) {
  height: var(--height);   
  background-color: var(--bg-color);
  border-block: var(--border);
  mix-blend-mode: screen;
}

Second, the white top and bottom borders create the illusion of space between items. This is essential because mix-blend-mode mixes the gradient against those borders. The middle three divs need them most; the first and last sort of cap the group:

div:nth-of-type(1) {
  border-block-start: 0;
}
div:nth-of-type(5) {
  border-block-end: 0;
}

The Gradient Layer

The last div starts with a solid background. The gradient only appears on hover, built from a linear gradient that fades between dark and light before blending with the divs behind it:

div:last-of-type {
  background: lightgrey;
  inset-block-start: 0;
  height: 100%;
  position: absolute;
  width: inherit;
  z-index: -1;
}

Now the geometry. The gradient height and color arrangement depend on the number of bars and the hovered position. More CSS variables keep the math honest:

section {
  --c1: hsl(0 0% 0%); /* Black base color */
  --c2: hsl(0deg 0% 20%); /* This and the rest are grays */
  --c3: hsl(0deg 0% 40%);
  --c4: hsl(0deg 0% 60%);
  --c5: hsl(0deg 0% 80%);
  --bars: 5;
  --color-stop: calc(100% / var(--bars));
  --bg-color: rgb(0, 128, 0); /* Green */
  --height: 40px;
  --border: 5px white solid;

  /* etc. */
}
  • --bars — the count of interactive divs (the last gradient div is excluded).
  • --color-stop — the gradient height divided by the number of bars, multiplied per color stop so no magic numbers are hardcoded.

Applying The Gradient On Hover

Hovering the first div amounts to a sibling rule: target the last div, but only when the first is in a hovered state:

div:nth-of-type(1):hover ~ div:last-of-type {
  background: linear-gradient(
    var(--c1) var(--color-stop), 
    var(--c2) var(--color-stop), 
    var(--c2) calc(var(--color-stop) * 2), 
    var(--c3) calc(var(--color-stop) * 2), 
    var(--c3) calc(var(--color-stop) * 3), 
    var(--c4) calc(var(--color-stop) * 3), 
    var(--c4) calc(var(--color-stop) * 4), 
    var(--c4) calc(var(--color-stop) * 4));
}

That selector reads roughly as “when the first div is hovered, style the last div.” The same pattern repeats for every other item. The only difference is the ordering of the color variables — hovered items get the darkest shade, while lighter shades shift around them:

div:nth-of-type(2):hover ~ div:last-of-type {
  background: linear-gradient(
    var(--c2) var(--color-stop), 
    var(--c1) var(--color-stop), 
    var(--c1) calc(var(--color-stop) * 2), 
    var(--c2) calc(var(--color-stop) * 2), 
    var(--c2) calc(var(--color-stop) * 3), 
    var(--c3) calc(var(--color-stop) * 3), 
    var(--c3) calc(var(--color-stop) * 4), 
    var(--c4) calc(var(--color-stop) * 4));
}

All you are really changing is the order of color variables. The --c1 variable moves down a level each time so the lighter stops frame the hovered card. Repeating that pattern for each div gives you the full assembly:

See the Pen [Gradient Hover [forked]](https://codepen.io/smashingmag/pen/JjwoVpZ) by Preethi Sam.

See the Pen Gradient Hover [forked] by Preethi Sam.

The same concept transfers beyond divs. You can apply it to text elements and other layouts as long as the geometry stays predictable:

See the Pen [Gradient Hover 2 [forked]](https://codepen.io/smashingmag/pen/abPzrQe) by Preethi Sam.

See the Pen Gradient Hover 2 [forked] by Preethi Sam.

Feel free to experiment with color palettes and gradient angles. Just remember that effective interaction design gives users more cues than color — shape, motion, or text changes help make the state unmistakable.