Add Polished Animations in Svelte Without Inflating Your Bundle
Learn how to use Svelte’s built‑in transition system to add, customize, and optimize animations while keeping bundle size low. Includes examples, custom transitions, and accessibility tips.
14 Jul 2025, 00:58 UTC

Why Animations Matter—and Why You Shouldn’t Bloat Your Build
When you first learn Svelte, the built‑in transition directives (e.g., in:fade, out:slide) look like a quick way to make a UI feel alive. Yet many developers hesitate: “Will this add a hefty runtime library?” or “What about users who prefer reduced motion?” The short answer is that Svelte’s transition system is compiled away, so you can sprinkle animations throughout your app without a noticeable cost—if you use it correctly.
1. Declarative Transitions & Bundle Size
Transitions are simple directives that you attach to an element. The compiler turns them into lightweight JavaScript that drives CSS changes on the fly. Because the runtime is zero‑cost, the only thing that ends up in your bundle is the code for the specific transitions you import.
{#if show}
Hello, world!
{/if}
Notice how we cherry‑pick only fade and slide. If you were to import * as transitions instead, the entire svelte/transition module would be bundled, adding a few kilobytes. In practice, the compiled code for each transition is under 200 bytes, so importing only what you need keeps the bundle lean.
2. Custom Transitions: Reusable, Zero‑Cost Functions
When the built‑ins don’t match your design, write a custom transition. A custom transition is a function that receives the node and an optional params object, and returns an object with css (or tick and duration) properties. The compiler inlines this code, so no extra library is shipped.
export function slideFadeScale(node, { delay = 0, duration = 400, easing = cubicOut } = {}) {
const style = getComputedStyle(node);
const opacity = +style.opacity;
const transform = style.transform === 'none' ? '' : style.transform;
return {
delay,
duration,
easing,
css: t => `opacity: ${t * opacity}; transform: translateX(${(1 - t) * 100}%) ${transform};`
};
}
Use it like any built‑in transition:
import { slideFadeScale } from './slideFadeScale.js';
{#if show}
Content that slides, fades, and scales.
{/if}
Because the function is inlined, the final bundle contains only the generated CSS string logic, not a separate runtime.
3. Layout Transitions with animate:flip
When list items reorder, animate:flip from svelte/animate calculates the before/after positions and interpolates the transform. No manual keyframes are required.
import { flip } from 'svelte/animate';
let items = [1, 2, 3, 4];
function shuffle() {
items = items.sort(() => Math.random() - 0.5);
}
<button on:click={shuffle}>Shuffle</button>
{#each items as item (item)}
<li animate:flip>Item {item}</li>
{/each}
</ul>
The flip directive automatically animates the list items as they move, giving a natural “fluid” effect without manual calculations.
4. Respecting prefers-reduced-motion
Accessibility matters. Svelte automatically disables transitions when the user has set the system preference for reduced motion. If you want to override this behavior for specific elements, wrap the transition in a reactive check.
<script>
import { fade } from 'svelte/transition';
let show = true;
let reduceMotion = false; // toggle this to simulate the media query
</script>
{#if show}
<div
in:fade={{ duration: 400 }}
out:fade={{ duration: 400 }}
data-reduce-motion={reduceMotion}
>
Conditionally animated content.
</div>
{/if}
In a production app, you would derive reduceMotion from window.matchMedia('(prefers-reduced-motion: reduce)') or a CSS media query. The compiler will still include the transition code, but the browser will skip it when the media query matches.
5. Trade‑offs & Limitations
- Overuse can clutter UI. Keep transitions purposeful—use them to signal state changes, not to decorate every element.
- Main‑thread execution. Complex or long animations can drop frames on low‑end devices. Test on target browsers and consider simplifying or using CSS animations for heavy work.
- Browser support. Most modern browsers support the CSS properties used by Svelte’s transitions. For older browsers, test
transformandopacitycompatibility.
6. Quick Checklist for Production
- Import only the transitions you need:
import { fade } from 'svelte/transition'; - Use custom transitions sparingly and inline them to keep bundle size minimal.
- Apply
animate:flipto reorderable lists for smooth layout changes. - Respect
prefers-reduced-motionby conditionally disabling animations. - Measure bundle size with your build tool (e.g.,
rollup -corvite build) to confirm only the used transitions are included. - Test on target devices and browsers; monitor frame rates with browser dev tools.
By following these practices, you can add delightful, accessible animations to your Svelte app without compromising bundle size or performance.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.