Interactive Radial Image Carousel
See the Pen Interactive Radial Image Carousel.
Tech & Dependencies
Features
- ✓ CSS Motion Path
- ✓ Sibling Targeting
- ✓ Spring Physics
- ✓ Pure CSS
Browser Support
Core
This is an Interactive Radial CSS Image Carousel. It arranges a deck of image cards into a curved, fan-like layout. Its function is to provide an engaging, space-saving gallery interface where hovering over a card gracefully shifts its neighbors away along a circular path, bringing the focused item into clear view without relying on JavaScript math.
Specs
- Weight: ~2 KB. Zero dependencies. No JavaScript.
- Performance: High. The browser’s native CSS engine handles the complex mathematical positioning via the Motion Path API, allowing smooth GPU-accelerated interpolation during hover states.
- Theming / Customization: Fully parameterized via CSS variables. You can easily adjust the curve radius (
--radius), the spread of the cards (--arc-size), and the physical bounce of the animation (--card-trans-easing). - Responsiveness: Fluid. Elements use viewport relative units (
vmin), ensuring the entire fan structure scales perfectly across desktop and mobile screens. - Graceful Degradation: [!] Highly experimental. Relies heavily on
sibling-count(),sibling-index(), and the:has()pseudo-class. In unsupported browsers, the component includes@supports notblocks as a rudimentary fallback to hardcode indices, but withoutoffset-pathsupport, the cards will simply stack flat on top of each other.
Anatomy
The component relies on absolute positioning tethered to a mathematically defined invisible path.
- HTML (The Skeleton): A single
.wrappercontainer holding a flat list of<div>elements, each wrapping an<img>. - CSS (The Skin): Utilizes
offset-path: circle()to define the invisible track. It uses complexcalc()functions to determine the exact percentage distance (offset-distance) each card should travel along that circle. - JS (The Nervous System): Absent. The logic is strictly state-driven.
Logic
The standout technical achievement is “Radial Sibling Displacement” using the :has() combinator:
/* Card pushes right-side neighbors forward */
&:hover {
& + div { --arc-shift: calc(var(--arc-shift-delta) * 3); }
& + div + div { --arc-shift: calc(var(--arc-shift-delta) * 2); }
}
/* Card pushes left-side neighbors backward */
&:has(+*:hover) {
--arc-shift: calc(var(--arc-shift-delta) * -3);
}
Instead of using JS to recalculate the positions of every card in an array, the CSS engine dynamically updates the --arc-shift variable based on structural relationships. When a card is hovered, the adjacent sibling combinator (+) shifts the next few cards positively along the arc. Simultaneously, the :has() pseudo-class looks backwards up the DOM tree, shifting the preceding cards negatively. The transition property then smoothly animates the resulting change in offset-distance.
Feel
Elastic and deeply organic. The complex linear() easing function mimics physical spring tension. When you hover over a card, it feels like parting physical objects on a curved string; the targeted card pops up slightly (offset-anchor), while its neighbors reluctantly yield space, rippling outward before springing back into place when the cursor leaves.

