Basic Carousel
A slide carousel with prev/next arrows, dots and a polite live region.
6 个框架中级
A carousel whose backdrops lag behind the text to read as depth.
<!-- Parallax: each panel translates a full 100% per step, but its gradient
backdrop is counter-shifted 30% and over-scaled so it lags behind the text,
reading as depth. Everything is transform-only and honours reduced motion. -->
<section class="relative h-64 overflow-hidden rounded-2xl" aria-roledescription="carousel" aria-label="Highlights" data-px>
<div aria-live="polite">
<div class="absolute inset-0 transition-transform duration-700 ease-out motion-reduce:transition-none" style="transform: translateX(0%);" data-px-panel role="group" aria-roledescription="slide" aria-label="1 of 3">
<div class="absolute inset-0 scale-125 bg-gradient-to-br from-blue-600 to-indigo-700 transition-transform duration-700 ease-out motion-reduce:transition-none" style="transform: translateX(0%);" data-px-bg></div>
<div class="relative flex h-full flex-col justify-end p-6 text-white sm:p-8"><h3 class="text-2xl font-bold">Analytics</h3><p class="mt-1 max-w-sm text-sm text-white/90">Every metric that matters, updated the moment it changes.</p></div>
</div>
<div class="absolute inset-0 transition-transform duration-700 ease-out motion-reduce:transition-none" style="transform: translateX(100%);" data-px-panel role="group" aria-roledescription="slide" aria-label="2 of 3" aria-hidden="true">
<div class="absolute inset-0 scale-125 bg-gradient-to-br from-teal-700 to-emerald-700 transition-transform duration-700 ease-out motion-reduce:transition-none" style="transform: translateX(30%);" data-px-bg></div>
<div class="relative flex h-full flex-col justify-end p-6 text-white sm:p-8"><h3 class="text-2xl font-bold">Automations</h3><p class="mt-1 max-w-sm text-sm text-white/90">Turn a repeated click into a rule that runs itself.</p></div>
</div>
<div class="absolute inset-0 transition-transform duration-700 ease-out motion-reduce:transition-none" style="transform: translateX(200%);" data-px-panel role="group" aria-roledescription="slide" aria-label="3 of 3" aria-hidden="true">
<div class="absolute inset-0 scale-125 bg-gradient-to-br from-violet-700 to-fuchsia-700 transition-transform duration-700 ease-out motion-reduce:transition-none" style="transform: translateX(60%);" data-px-bg></div>
<div class="relative flex h-full flex-col justify-end p-6 text-white sm:p-8"><h3 class="text-2xl font-bold">Integrations</h3><p class="mt-1 max-w-sm text-sm text-white/90">Forty connectors, and a webhook for everything else.</p></div>
</div>
</div>
<button class="absolute left-3 top-1/2 z-10 grid h-10 w-10 -translate-y-1/2 place-items-center rounded-full bg-black/30 text-white backdrop-blur hover:bg-black/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white" type="button" aria-label="Previous slide" data-px-prev>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m12.5 5-5 5 5 5" stroke-linecap="round" stroke-linejoin="round" /></svg>
</button>
<button class="absolute right-3 top-1/2 z-10 grid h-10 w-10 -translate-y-1/2 place-items-center rounded-full bg-black/30 text-white backdrop-blur hover:bg-black/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white" type="button" aria-label="Next slide" data-px-next>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m7.5 5 5 5-5 5" stroke-linecap="round" stroke-linejoin="round" /></svg>
</button>
</section>
<script>
(function () {
document.querySelectorAll('[data-px]').forEach(function (root) {
var panels = Array.prototype.slice.call(root.querySelectorAll('[data-px-panel]'));
var index = 0;
function go(next) {
index = (next + panels.length) % panels.length;
panels.forEach(function (panel, i) {
var offset = i - index;
panel.style.transform = 'translateX(' + offset * 100 + '%)';
var bg = panel.querySelector('[data-px-bg]');
if (bg) bg.style.transform = 'translateX(' + offset * 30 + '%)';
if (i === index) panel.removeAttribute('aria-hidden');
else panel.setAttribute('aria-hidden', 'true');
});
}
root.querySelector('[data-px-prev]').addEventListener('click', function () { go(index - 1); });
root.querySelector('[data-px-next]').addEventListener('click', function () { go(index + 1); });
});
})();
</script>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
items必填 | Slide[] | - | 要渲染的项目数组。 |
className | string | - | 合并到根元素上的额外类名。 |
ariaLabel | string | 'Carousel' | 按钮的无障碍名称。仅有图标的按钮必须设置。 |
Every panel translates a full 100% per step while its gradient backdrop is counter-shifted 30% and over-scaled, so the background trails the foreground. Everything is transform-only and honours reduced motion, where the parallax becomes an instant cut.