---
title: Animate with transform and opacity instead of layout properties
description: >-
  Animate elements with CSS `transform` and `opacity` instead of layout
  properties like `top` or `left` to avoid triggering layout recalculation and
  CLS on every animation frame.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-transform-for-animations
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-transform-for-animations.md
api_name: liquid
---

# Animate with transform and opacity instead of layout properties

Use CSS `transform` and `opacity` for animations instead of layout properties like `top`, `left`, `right`, or `bottom`, to avoid triggering layout recalculation and CLS on every frame.

***

## Why

Animating layout properties is an anti-pattern. The browser treats every frame of the animation as a layout shift. This causes massive CLS scores, janky animations and laggy scrolls because the browser must recalculate layout on every frame, poor [INP](https://web.dev/inp/) because this work happens on the main thread, and animations aren't hardware-accelerated.

For performant animations, animate only two properties: `transform` and `opacity`. The browser's compositor thread handles these properties, and they don't trigger layout or paint operations. Benefits: no layout shifts (CLS of 0), hardware acceleration for smooth animations, and a free main thread for better INP and scrolling performance.

***

## How

Instead of animating layout properties, use `transform`:

```css
/* Anti-pattern: creates a layout shift on every frame */
@keyframes slideUp {
  from {
    bottom: -100%;
  }
  to {
    bottom: 0;
  }
}


/* Recommended: hardware-accelerated, no layout shift */
@keyframes slideUp {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}
```

Always disable animations for users who prefer reduced motion:

```css
@media (prefers-reduced-motion: reduce) {
  .animated-element {
    animation: none;
    transition: none;
  }
}
```

***

## Examples

### Cookie banners

Cookie consent banners often animate using position properties. Although they don't visibly shift content when they slide in from the bottom, they still register as layout shift because they use position properties. Fix this by changing to a transform-based animation.

### Dialog animations

```css
.modal {
  animation: slideUp 0.3s ease-out;
}


@keyframes slideUp {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}


@media (prefers-reduced-motion: reduce) {
  .modal {
    animation: none;
  }
}
```

***

## Testing

* The [Chrome DevTools Performance panel](https://developer.chrome.com/docs/devtools/performance) shows animation-based layout shifts. Record during an animation and look for **Layout Shift** entries in the **Layout Shifts** track.
* Use the **Rendering** tab, available in the **More tools** menu, to enable **Layout Shift Regions** for visual feedback.
* Use the **Animations** tab in the drawer to debug and slow down animations and visualize their impact.
* Visually observe during an animation.
* Compare CLS scores before and after.

***

## References

* [How to optimize Cumulative Layout Shift (CLS) on Shopify sites](https://performance.shopify.com/blogs/blog/how-to-optimize-cumulative-layout-shift-cls-on-shopify-sites)
* [Prevent dialogs from hijacking LCP](https://shopify.dev/docs/storefronts/themes/best-practices/performance/prevent-popups-hijacking-lcp)

***
