Lottie is the file type of Bodymovin, a plugin for AfterEffects that can export an animation into a descriptive JSON format.
Why is it called Lottie files?
Lottie got its name from Charlotte ‘Lotte’ Reiniger, German film director and the foremost pioneer of silhouette animation.
I don't recommend using the Lottie web player. The reason is that it's a heavy library (~250K) and is buggy, for instance it doesn't scale correctly according to its container. The file size can be reduced slightly by choosing one of the "lite" players but it's still a big file size in the end. Improving the file size of this library seems hard since it's not a modern library. It's not even using modules. In order for this web player to be smaller it would have to be rewritten to modern JS (or TS) and also know of the files it is going to play, so it would be able to leave out features that are not needed. (For instance music playback is part of the library, but our animations don't use that.)
There's a NPM package for converting Lottie files into native SVG animations (SMIL). If possible we recommend using that over the Lottie web player.
- Package: https://www.npmjs.com/package/bodymovin-to-smil
- Example usage in this readme: https://github.com/bodymovin/bodymovin-to-smil#readme
- No support of IE up until IE11.
How to:
- Rewrite the example to use the file name of your Lottie file and adjust the exported file name
- Check that the animation plays back in all major browsers
- Simply use this file from within the source code
We've made a custom React solution. Note that if you use another setup then these tips might not apply.
- SVG placeholders for before the animation is loaded
- The animations are imported as modules in React
- The animation modules are loaded asynchronously
- There's two breakpoints, one animation for narrow screens and one for wider screens
SVG placeholders are easy to craft. Just copy the animation file and paste into a placeholder.svg. Remove everything inside the SVG element and replace that with a rect
the same dimensions as the image.
For example, this is a placeholder image:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" width="820" height="461" viewBox="0 0 820 461" style="width:100%;height:100%">
<rect fill="#ffffff" width="820" height="461"/>
</svg>
In order to allow the animation to be a module and part of React, use the following pattern:
import React from 'react';
import { ReactComponent } from './animation.svg';
export default () => <ReactComponent />;
Since I'm using TypeScript to wrap the images I'm using TypeScript to detect the screen resolution and decide what to display too.
import React from 'react';
import useWindowSize from 'hooks/useWindowSize';
type Breakpoint = {
width: number;
component: React.FC;
};
type Props = {
breakpoints: Breakpoint[];
};
const ResponsivePicker: React.FC<Props> = ({ breakpoints }) => {
const size = useWindowSize();
// Ensure that breakpoints are sorted before iterating
breakpoints.sort((a, b) => a.width - b.width);
for (const breakpoint of breakpoints) {
const { width, component: Component } = breakpoint;
if (size.width < width) {
return <Component />;
}
}
// Fall back to widest breakpoint
const { component: Component } = breakpoints[breakpoints.length - 1];
return <Component />;
};
export default ResponsivePicker;
I copied the useWindowSize hook from here: https://usehooks.com/useWindowSize/
The SVG files are rendered incorrectly in IE11 so we wanna hide them. This is how we detect IE:
import React from 'react';
type Props = {
ie: React.FC;
other: React.FC;
};
const isIE = () =>
window.navigator.userAgent.match(/(MSIE|Trident)/);
const BrowserPicker: React.FC<Props> = ({ ie, other }) => {
const Component = isIE() ? ie : other;
return <Component />;
};
export default BrowserPicker;
This is how I'm using placeholders, dynamically loaded modules, responsive images and a check for IE up to 11:
import React, { Suspense } from 'react';
const Medium = React.lazy(() => import('./Medium/animation'));
const Large = React.lazy(() => import('./Large/animation'));
import LargePlaceholder from './Large/placeholder';
import MediumPlaceholder from './Medium/placeholder';
import ResponsivePicker from '../ResponsivePicker';
import BrowserPicker from './BrowserPicker';
export default () => (
<BrowserPicker
ie={() => null}
other={()=>
<Suspense fallback={
<ResponsivePicker breakpoints={[
{ width: 820, component: MediumPlaceholder },
{ width: 2000, component: LargePlaceholder },
]} />
}>
<ResponsivePicker breakpoints={[
{ width: 820, component: Medium },
{ width: 2000, component: Large },
]} />
</Suspense>
}
/>
);