A carousel with no JavaScript

The carousel here uses CSS scroll snap: a horizontally scrolling flex container with scroll-snap-type: x mandatory, and each slide set to scroll-snap-align: center. Swiping or scrolling docks each slide into place with native momentum and no script at all.

This approach is better than most JavaScript carousels for a reason beyond bundle size: it works with the platform. Keyboard scrolling, touch momentum, and screen reader navigation all behave normally, because it's genuinely just a scrolling container. Add anchor links for dot navigation, or a few lines of JavaScript only if you need autoplay.

Clip the frame, animate the image

Every hover effect here scales the image inside a container with overflow: hidden, rather than scaling the container itself. That keeps the frame's footprint fixed, so nothing around it reflows — the difference between a smooth zoom and a page that shifts when you mouse over a thumbnail.

The Ken Burns effect applies the same principle over a long duration: a slow scale and drift that makes a still photograph feel alive in a hero section. Keep it slow — 12 seconds or more — and subtle, or it becomes seasick rather than cinematic.

Images, layout shift and loading

Animated or not, images are the main cause of Cumulative Layout Shift. Always give them width and height attributes so the browser reserves space before the file arrives — our aspect ratio calculator produces the correct pair. Add loading="lazy" to anything below the fold, but never to your hero image, since lazy-loading your largest visible element delays the LCP metric that Google measures.

The blur-up reveal is the loading pattern popularised by Medium: the image sharpens into place instead of popping in. Trigger it by adding the class on the image's load event.

Filters cost more than transforms

The greyscale-to-colour effect uses filter, which is GPU-accelerated but heavier than a plain transform — especially on large images. It's fine for a logo wall or a team grid; be more careful applying it to full-bleed hero imagery on lower-powered devices.

Frequently asked questions

Can I build a carousel with only CSS?

Yes. A flex container with scroll-snap-type: x mandatory and slides set to scroll-snap-align gives you a working, swipeable carousel with native momentum and keyboard support, with no JavaScript at all.

Why does my image zoom effect shift the page layout?

You are likely scaling the container rather than the image inside it. Put overflow: hidden on the frame and scale the image within, so the frame keeps its footprint and nothing around it reflows.

Should I lazy-load all my images?

No. Use loading="lazy" for images below the fold, but never on your hero or largest visible image — lazy-loading it delays the Largest Contentful Paint metric that Google uses to measure your page speed.

Related categories

← Back to all 72 CSS animations