Version selector

This demo has several versions:

  1. CSS Version
  2. JavaScript Version
🏠

About this demo

This demo is a recreation of the infamous Cover Flow UI, once featured by Apple Inc. in iTunes for visually flipping through album artwork.

Each album cover has a View Timeline attached, driving an animation to rotate the cover sideways when offscreen and have it facing forwards when at the center of the scroller.

The album covers are from albums all released on the wonderful Loci Records record label.

The Code / Explanation

Base layout

The list of covers is presented in an unordered list, with each list item containing an image of the cover.

<ul class="cards">
	<li>
		<img src="https://example.org/cover1.jpg"
				width="600" height="600" alt="…" />
	</li>
	<li>
		<img src="https://example.org/cover2.jpg"
				width="600" height="600" alt="…" />
	</li>
	…
	<li>
		<img src="https://example.org/cover3.jpg"
				width="600" height="600" alt="…" />
	</li>
</ul>

Using CSS, the albums are on one line and the container is made scrollable

.cards {
	list-style: none;
	white-space: nowrap;
	…
	max-width: calc(var(--cover-size) * 6);
	overflow: scroll;
}

.cards li {
	display: inline-block;
	width: var(--cover-size);
	aspect-ratio: 1;
}

To always have one album cover centered, CSS Scroll Snapping is used.

.cards {
	scroll-snap-type: x mandatory;
}

.cards li {
	scroll-snap-align: center;
}

The album reflections are also done using CSS.

.cards li img {
	width: 100%;
	height: auto;

	-webkit-box-reflect: below 0.5em linear-gradient(rgb(0 0 0 / 0), rgb(0 0 0 / 0.25));
}

Scroll-driven animations

There are two scroll-driven animations on each list item, to power the effect

  1. An animation on the li elements, changing the z-index
  2. An animation on the img elements, rotating them in 3D.

The main driver for both animations is a ViewTimeline on each list item, tracking it for the entirety of the cover range. That way, elements are tracked from entry (0%) to exit (100%). The 50% mark indicates when the element is at the center of its scroller.

.…

The keyframes for the li elements make it so that at halfway in the scroller, that cover is topmost.

The keyframes for the img work in similar fashion. At the 50% mark, the cover faces forwards. On the other sides, it is rotated sideways.

There is also some CSS to make the 3D perspective work:

.cards li {
	/* Make the 3D stuff work… */
	perspective: 40em;
}

Because no rangeStart or rangeEnd is set, the cover range is used.

⚠️ Note that key here is that the transforms happen on the imgs, not the lis. If the li elements were transformed, the total scroll distance of the scroller would be affected, causing a flickering effect. By rotating the imgs inside the lis, the size of the li elements – and thus the total scroll distance – remain unchanged.

⚠️ Your browser does not support Scroll-Linked Animations. To cater for this, a polyfill has been loaded.