Advanced-Looking Hover in Webflow (Just CSS)

Intermediate 17:09 webflowcsshoverhas-selectorvariables

Build a card hover interaction in Webflow — darker border, scaling image, desaturated siblings — with no Interactions, just hover states, variables, and a little CSS.

Key takeaways

  • Interactions that look like they need Webflow Interactions often don't — the style panel, hover states, variables, and a few lines of CSS can do it, lighter and cleaner.
  • Webflow's hover state can only style the hovered element itself — to affect a child (or its siblings), you need a little custom CSS.
  • Tie the interaction to a custom attribute (e.g. card-link-hover), not a class name, so the same behavior works on any element regardless of its class.
  • Scale a child image on hover with an attribute selector, and clip it cleanly with overflow: hidden on the wrapper.
  • The :has() selector lets you style siblings from a parent condition — body:has([attr]:hover) [attr]:not(:hover) targets every card except the hovered one.
  • Drive the values with Webflow variables and use Copy CSS to paste the exact variable name into your embed — no manual translating.

Video chapters

  1. 00:00 Intro
  2. 01:30 Breaking down the section structure
  3. 07:08 Setting up the variables
  4. 08:20 Animating the border color
  5. 08:52 Scaling up the image
  6. 12:52 Desaturating the other cards
  7. 16:28 Outro

By the end of this lesson you’ll have built a hover interaction that looks like it needs a whole Interactions timeline — hover a card and its border darkens, its image scales up while staying perfectly clipped, and every other card fades toward black and white — using no Webflow Interactions at all. Just the style panel, hover states, a few variables, and a tiny bit of CSS.

That’s really the point of this one. It’s a cool effect, sure, but it’s also a small lesson in how a few lines of modern CSS can make your Webflow projects feel more powerful, flexible, and intentional than dragging out an interaction for everything.

The starting point is an ordinary CMS grid of blog cards. Two structural details matter up front: the card link has overflow: hidden with a border-radius (so the scaled image stays clipped), and the pieces that will animate — border color, image transform, and filter — already have transitions on them (800ms, ease-out expo) so everything moves consistently.

How it works

The border is the easy part and the one thing the native hover state can do. Select the card link, switch to its hover state, and set the border color to a value from your variables group. Done — it animates on hover using the transition you already defined.

The catch shows up with the image: Webflow’s hover state only styles the element you selected — it can’t reach a child. So to scale the image inside the hovered card, you need a little custom CSS. The clean way to hook into it is a custom attribute, not a class. The card link gets an attribute like card-link-hover, which detaches the behavior from the class name — any element with that attribute gets the interaction, even if its class is different. That turns the interaction into a reusable behavior instead of a one-off style.

With the attribute in place, one rule scales the image:

[card-link-hover]:hover img {
  transform: scale(var(--card-on-hover--image-scale));
}

In plain English: when an element with card-link-hover is hovered, scale the img inside it. The value comes from a Webflow variable — and you don’t translate the name by hand, you use Copy CSS on the variable and paste it straight into scale().

The most satisfying piece — desaturating every card except the hovered one — is also just three lines, thanks to the modern :has() selector:

body:has([card-link-hover]:hover) [card-link-hover]:not(:hover) {
  filter: saturate(var(--card-on-hover--saturation));
}

Read it in parts: body:has([card-link-hover]:hover) means “only when the page contains a hovered card,” and [card-link-hover]:not(:hover) means “target every card except the one being hovered.” Together: when one card is hovered, desaturate all the others. Instead of building an interaction system, you’re describing the relationship directly — if this exists and it’s hovered, style all the others. That’s what makes modern CSS so expressive here.

How to use it

  1. Prep the structure — give the card link overflow: hidden plus a border-radius so the image stays clipped, and add transitions on border-color, filter, and the image’s transform (e.g. 800ms, ease-out expo).
  2. Store your values as variables — a small group (here “card on hover”) holding the sibling saturation, the image scale factor, and the hover border color.
  3. Animate the border — select the card link, switch to its hover state, and set the border color to your variable. That one’s fully native.
  4. Add the attribute — give the card link a custom attribute like card-link-hover so the interaction targets a behavior, not a class.
  5. Add an embed for CSS — drop an Embed element (class global-styles) near the top of the page and open it to add a <style> block.
  6. Scale the image — paste the [card-link-hover]:hover img { transform: scale(...) } rule, using Copy CSS to grab the exact variable name.
  7. Desaturate the siblings — add the body:has(...) rule with filter: saturate(...), again pasting the variable via Copy CSS. Save, and test right in the Designer.

That’s a clean, reusable card interaction with almost no code — and a good first taste of how far a few lines of CSS can take your Webflow builds.

Resources

Frequently asked questions

Can I build a card hover effect in Webflow without using Interactions?
Yes. A darker border, a scaling image, and desaturated siblings can all be done with hover states, Webflow variables, and a few lines of CSS in an embed — no Interactions timeline at all. It's lighter and far easier to reuse.
Why can't Webflow's hover state change a child element?
The hover state in the style panel only styles the element you selected — it can't reach inside to its children. To animate a child (like scaling an image when its card is hovered), add a small custom-CSS rule that targets the child from the hovered parent.
How do I fade or desaturate the other cards when I hover one in Webflow?
Use the :has() selector. body:has([your-attr]:hover) [your-attr]:not(:hover) means "when one card is hovered, select every card except that one" — then apply filter: saturate(). It describes the relationship directly, with no interaction system needed.
How do I use a Webflow variable inside custom CSS?
Open the variables panel, click the three dots next to the variable, and choose Copy CSS. Paste that directly into your rule (inside a scale() or saturate(), for example). Webflow generates the real variable name for you, so you never translate it by hand.
Why tie a Webflow interaction to a custom attribute instead of a class?
An attribute detaches the behavior from the class name, so two elements with different classes but the same structure can share the exact same interaction — just give both the same attribute. It makes your interactions reusable behaviors rather than one-off class styles.

← Back to the course