How-to

How to capture hover animations

Hover animations vanish the moment you move to DevTools. How to force :hover, freeze the page, handle JavaScript mouseenter effects and capture the real motion.

· 6 min read

Hover animations are some of the nicest details on the web: a card that lifts, a button whose arrow slides, a link whose underline draws itself. They are also the hardest to inspect. The moment you move the mouse over to DevTools, the hover ends and the animation runs backwards.

This guide explains why hover is tricky, the techniques that work in Chrome DevTools, and how to capture the real motion, including hover effects driven by JavaScript.

Why hover animations are hard to inspect

Three things work against you.

So the first job is to work out which kind of hover you are looking at.

Technique 1: force :hover in the Styles pane

For CSS hover rules, this is the quickest fix.

  1. Inspect the element that the user actually hovers. If you are not sure, start with the moving element and walk up the tree.
  2. Open the Animations panel first, so it can record the transition: three-dot menu > More tools > Animations.
  3. Click :hov in the Styles pane toolbar and tick :hover. You can also right-click the node in the Elements tree and choose Force state > :hover.
  4. Watch the transition in the Animations panel. Set the speed to 25% or 10% and replay to see it slowly.
  5. Read the rule. The hover styles now show in the Styles pane, with the transition on the base rule. Click the curve icon next to the timing function to see the easing.
  6. Untick :hover to see the exit transition. It often has a different duration or easing from the entry.

The DevTools workflow is covered in more depth in how to inspect CSS animations in Chrome DevTools.

Technique 2: freeze the page mid-hover

When forcing the state does nothing, the hover is probably handled in JavaScript. You can still freeze it with a delayed breakpoint. Paste this into the Console:

setTimeout(() => { debugger; }, 3000);

Now move the mouse back to the page and hover the element within three seconds. When the timer fires, the debugger pauses the page. The hover state, the JavaScript-added classes and the inline styles all stay as they are, so you can inspect the element in Elements.

This gives you a single frozen frame, not the timing. It is useful for finding which classes or inline styles change on hover, and for reading the end state.

Technique 3: send the events yourself

If you know the element listens for mouseenter or pointerenter, you can dispatch those events from the console while the Animations panel is open:

const el = $0; // the element selected in Elements
el.dispatchEvent(new PointerEvent('pointerover', { bubbles: true }));
el.dispatchEvent(new PointerEvent('pointerenter'));
el.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
el.dispatchEvent(new MouseEvent('mouseenter'));

// later, to trigger the exit animation
el.dispatchEvent(new PointerEvent('pointerleave'));
el.dispatchEvent(new MouseEvent('mouseleave'));

Synthetic events run the page's JavaScript handlers, but they do not set the CSS :hover state. For effects that combine both, you may need to force :hover and dispatch the events. Some handlers also check the pointer position or event.isTrusted, and then synthetic events will not work at all.

If the hover animation runs with the Web Animations API, it will now show in the Animations panel and in document.getAnimations(). If it runs with GSAP, you will see inline styles changing but no animation to read.

Which technique for which hover

How the hover is builtForce :hoverFreeze with debuggerDispatch events
CSS :hover with a transitionWorks, timing readableEnd state onlyNo effect
JS adds a class, CSS transitions itNo effectShows the classWorks, timing readable
JS calls element.animate()No effectOne frameWorks, timing readable
GSAP on mouseenterNo effectOne framePlays, but no timing to read
Lottie on hoverNo effectOne framePlays, but no timing to read

The bottom two rows are where manual inspection runs out. You can watch the motion, but DevTools has no animation object to show you its keyframes or easing. See how to find the easing curve of an animation for the few options left.

Technique 4: capture a real hover with Capture Motion

The Capture Motion extension handles hover differently. Instead of forcing a CSS state or faking events, it triggers a real :hover state through the Chrome DevTools Protocol. The protocol connection is attached only during the capture. The page reacts the way it would to a real pointer, and the extension records what plays.

  1. Open the page and start Capture Motion from the Chrome toolbar.
  2. Pick the element that is hovered. For a card with a moving arrow inside, pick the card.
  3. Play the hover. The extension triggers the hover state and records the keyframes, durations, delays and easing of every animated property, whether the motion comes from CSS transitions and keyframes, the Web Animations API, GSAP or Lottie.
  4. Preview it. The capture replays in the extension. No account is needed to capture and preview, and captures stay in your browser unless you save them.
  5. Copy it. With a free account, copy the code from the CSS, React or GSAP tab in the popup, or download an HTML and CSS file. To design with it, click Capture Motion to copy the capture and paste it into the Capture Motion Figma plugin, which rebuilds it as a Figma Motion timeline.

If the next stop is code, animation to code describes each export. If it is design, see how to import a website animation into Figma.

A note on pointer-following effects

Some hover effects are not animations with a start and an end. Magnetic buttons, tilting cards and spotlight gradients follow the pointer on every mousemove and set styles from its position. There is no fixed timeline to read, because the motion depends on where the user moves.

For these, the useful data is the mapping, not the timing: how far the element moves per pixel of pointer travel, the maximum tilt angle, and how it eases back when the pointer leaves. The return to rest is usually a normal transition, which you can read with the techniques above. The rest is easier to rebuild from the site's behaviour than to copy, so test a few pointer positions and note the limits.

Tips for rebuilding hover animations

For ready examples, the Capture Motion gallery has ready animated components, such as liquid tabs, that you can customize and export.

Questions

How do I keep a hover state active in Chrome DevTools?

Select the element in the Elements panel, click :hov in the Styles pane and tick :hover. You can also right-click the node and choose Force state > :hover. The state stays on until you untick it.

Why does forcing :hover not trigger the animation?

Forcing :hover only changes which CSS rules match. It does not send mouseenter, mouseover or pointer events, so hover effects started by JavaScript, including most GSAP hover animations, never run.

How can I freeze a page while hovering?

Run setTimeout(() => { debugger; }, 3000) in the Console, then hover the element within three seconds. When the debugger pauses, the page stops in its hovered state and you can inspect it.

Does Capture Motion trigger hover animations?

Yes. It sets a real :hover state through the Chrome DevTools Protocol, attached only during the capture, and records the keyframes, durations, delays and easing that play.