Frontend Development 27 min read

How to Turn Lottie Animations into CSS and React Native Code

This article explains the challenges of converting designers' Lottie animation descriptions into reusable front‑end code, compares frame‑by‑frame, keyframe, and CSS variable approaches, and provides practical examples for generating CSS, CSS‑variables, and React Native Animated implementations.

Kuaishou Frontend Engineering
Kuaishou Frontend Engineering
Kuaishou Frontend Engineering
How to Turn Lottie Animations into CSS and React Native Code

1. Project Background

Front‑end developers often receive animation specifications from designers in various formats—natural language, timeline data, or AE‑exported JSON. Manually translating these descriptions into CSS, React Native Animated code is repetitive, time‑consuming, and mentally taxing.

2. Lottie Format Overview

Lottie stores animation data as JSON. The root object contains global settings (width, height, frame rate, etc.) and two crucial arrays:

layers : each entry describes a single AE layer, including its type, transform keyframes ( ks ), timing ( ip , op ), and optional parent relationships.

assets : reusable resources such as images or pre‑compositions referenced by layers.

Keyframe objects inside ks define start values ( s ), end values ( e ), frame index ( t ) and cubic‑bezier control points for timing and path interpolation.

Lottie JSON structure illustration
Lottie JSON structure illustration

3. Exporting Lottie to Code

Three main strategies are discussed:

3.1 Frame‑by‑frame CSS

Record the transform and opacity of every animation frame and emit a dense @keyframes rule. While it reproduces the visual effect accurately, the generated CSS is large and hard to maintain.

<code>// Example of a dense keyframe block
.hash5edafe06{transform-origin:50% 50%;animation:hash5edafe06_kf 0.667s linear;}
@keyframes hash5edafe06_kf{0%{opacity:1;transform:matrix3d(...);}…100%{opacity:0.01;transform:matrix3d(...);}}</code>

3.2 Semantic Keyframe CSS

Sample the animation at 5‑10 frames per second, keep the original easing curves, and generate concise keyframes. This reduces file size and improves readability.

<code>.hash5edafe06_0{animation:hash5edafe06_0_keyframe_0 0.4s 0.267s cubic-bezier(0.333,0,0.667,1) forwards;}
@keyframes hash5edafe06_0_keyframe_0{0%{transform:scale(1,1);}66.667%{opacity:1;}100%{opacity:0.01;transform:scale(0.15,0.15);}}</code>

3.3 CSS Variable Approach

Using the experimental @property rule, custom properties (e.g., --translateX , --scaleX ) are animated separately, then composed in a single transform . This decouples transform components, allowing multiple animations on the same element without DOM nesting.

<code>@property --translateX {syntax:'<number>';inherits:false;initial-value:0;}
@keyframes translateX_anim{0%{--translateX:0;}100%{--translateX:-162.4;}}
.element{transform:translateX(calc(1px*var(--translateX))) scaleX(var(--scaleX));animation:translateX_anim 0.4s forwards;}</code>

Pros: smaller CSS, better readability. Cons: limited browser support because @property is still experimental.

4. React Native Animated Code Generation

React Native’s Animated API maps Lottie’s independent transform channels directly, preserving per‑segment easing curves. The article provides a hook that creates Animated.Value objects for opacity, translation, and scale, then composes them with Animated.timing and Animated.parallel .

<code>function useLayerAnimated(){
  const opacityVal = useRef(new Animated.Value(1)).current;
  const translateXVal = useRef(new Animated.Value(0)).current;
  const translateYVal = useRef(new Animated.Value(0)).current;
  const scaleXVal = useRef(new Animated.Value(1)).current;
  const scaleYVal = useRef(new Animated.Value(1)).current;
  const getCompositeAnimation = useCallback(()=>{
    const opacityAnim = Animated.timing(opacityVal,{toValue:0.01,duration:133.333,delay:533.333,easing:Easing.bezier(0.333,0,0.667,1),useNativeDriver:true});
    const translateXAnim = Animated.timing(translateXVal,{toValue:-162.4,duration:400,delay:266.667,easing:Easing.bezier(0.869,0.774,0.874,0.951),useNativeDriver:true});
    const translateYAnim = Animated.timing(translateYVal,{toValue:303.456,duration:400,delay:266.667,easing:Easing.bezier(0.869,-0.64,0.874,0.445),useNativeDriver:true});
    const scaleXAnim = Animated.timing(scaleXVal,{toValue:0.15,duration:400,delay:266.667,easing:Easing.bezier(0.333,0,0.667,1),useNativeDriver:true});
    const scaleYAnim = Animated.timing(scaleYVal,{toValue:0.15,duration:400,delay:266.667,easing:Easing.bezier(0.333,0,0.667,1),useNativeDriver:true});
    return Animated.parallel([opacityAnim,translateXAnim,translateYAnim,scaleXAnim,scaleYAnim]);
  },[]);
  const style = {transform:[{translateX:translateXVal},{translateY:translateYVal},{scaleX:scaleXVal},{scaleY:scaleYVal}],opacity:opacityVal};
  return {animatedStyle:style,resetAnim:()=>{opacityVal.setValue(1);translateXVal.setValue(0);translateYVal.setValue(0);scaleXVal.setValue(1);scaleYVal.setValue(1);},getAnim:getCompositeAnimation};
}</code>
React Native Animated preview
React Native Animated preview

5. Platform Integration

The conversion pipeline has been integrated into the internal Vision animation platform, providing a one‑click export of CSS, CSS‑variable, and React Native Animated code for any Lottie asset. The article links to a detailed usage guide and teases a forthcoming deep‑dive on sequence‑frame format conversion.

Vision platform overview
Vision platform overview

3.2 Summary

For short, simple animations, the frame‑by‑frame method works as a quick fallback. For most production use cases, the semantic keyframe approach offers a good balance of size and maintainability. The CSS‑variable technique yields the smallest and most flexible output but requires modern browser support. React Native Animated provides a direct mapping with full easing control.

frontendanimationLottieReact NativeCSS animation
Kuaishou Frontend Engineering
Written by

Kuaishou Frontend Engineering

Explore the cutting‑edge tech behind Kuaishou's front‑end ecosystem

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.