跳至主要內容

CSS-only Tailwind CSS carousel using scroll-snap. Horizontal slide layout with navigation controls and no JavaScript required. WCAG AA accessible, works with Django, HTMX, Laravel, React, and any stack.

輪播元件在旋轉或可捲動容器中顯示多個項目,非常適合展示圖像、推薦、產品圖庫或特色內容。輪播採用語義 HTML 和平滑的滾動行為構建,支援具有對齊對齊的水平和垂直佈局。 Frutjam 輪播系統非常適合英雄部分、產品畫廊、推薦展示和內容滑桿。

僅 CSS,無需 JavaScript。 WCAG AA 可存取且與框架無關 - 可與 Django、HTMX、Laravel、React 和任何堆疊配合使用。

班級 類型 描述
carousel根據具有捕捉行為的水平可滾動容器
carousel-item修飾符旋轉木馬內的單獨幻燈片
carousel-vertical修飾符垂直滾動方向
carousel-center修飾符對齊到每個項目的中心
carousel-end修飾符對齊到每個項目的末尾

基本用法

創建一個帶有可滾動項目的簡單水平輪播。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<div class="carousel w-full gap-4 p-4 bg-base-100">
  <div class="carousel-item w-96">
    <div class="badge badge-primary">Featured</div>
  </div>
  <div class="carousel-item w-96">
    <div class="badge badge-secondary">Popular</div>
  </div>
  <div class="carousel-item w-96">
    <div class="badge badge-accent">Trending</div>
  </div>
  <div class="carousel-item w-96">
    <div class="badge badge-info">New</div>
  </div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<div className="carousel w-full gap-4 p-4 bg-base-100">
  <div className="carousel-item w-96">
    <div className="badge badge-primary">Featured</div>
  </div>
  <div className="carousel-item w-96">
    <div className="badge badge-secondary">Popular</div>
  </div>
  <div className="carousel-item w-96">
    <div className="badge badge-accent">Trending</div>
  </div>
  <div className="carousel-item w-96">
    <div className="badge badge-info">New</div>
  </div>
</div>

帶有圖像的輪播

顯示具有平滑捲動和響應式大小調整的影像庫。

html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<div class="carousel w-full gap-2">
  <div class="carousel-item w-full">
    <picture>
      <source media="(max-width: 640px)" srcset="https://cdn.frutjam.com/images/photo-2.jpg?format=webp&width=640&height=360">
      <img src="https://cdn.frutjam.com/images/photo-2.jpg?format=webp&width=800&height=450" alt="Image 1" class="w-full" loading="lazy" />
    </picture>
  </div>
  <div class="carousel-item w-full">
    <picture>
      <source media="(max-width: 640px)" srcset="https://cdn.frutjam.com/images/photo-3.jpg?format=webp&width=640&height=360">
      <img src="https://cdn.frutjam.com/images/photo-3.jpg?format=webp&width=800&height=450" alt="Image 2" class="w-full" loading="lazy" />
    </picture>
  </div>
  <div class="carousel-item w-full">
    <picture>
      <source media="(max-width: 640px)" srcset="https://cdn.frutjam.com/images/photo-4.jpg?format=webp&width=640&height=360">
      <img src="https://cdn.frutjam.com/images/photo-4.jpg?format=webp&width=800&height=450" alt="Image 3" class="w-full" loading="lazy" />
    </picture>
  </div>
</div>

輪播中心對齊

以中心對齊方式顯示輪播項目並在卡片之間留出間距。

html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div class="carousel carousel-center gap-4 p-4 bg-base-200 rounded-lg">
  <div class="carousel-item">
    <div class="card card-primary w-80">
      <div class="card-content">
        <h2 class="card-title">Card 1</h2>
        <p>Featured product or content</p>
      </div>
    </div>
  </div>
  <div class="carousel-item">
    <div class="card card-secondary w-80">
      <div class="card-content">
        <h2 class="card-title">Card 2</h2>
        <p>Popular selection</p>
      </div>
    </div>
  </div>
  <div class="carousel-item">
    <div class="card card-accent w-80">
      <div class="card-content">
        <h2 class="card-title">Card 3</h2>
        <p>Trending now</p>
      </div>
    </div>
  </div>
</div>

垂直轉盤

建立一個垂直輪播,用於從上到下滾動項目。

html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<div class="carousel carousel-vertical h-96 gap-2 p-2 bg-base-100">
  <div class="carousel-item h-32">
    <div class="badge badge-lg badge-primary">Item 1</div>
  </div>
  <div class="carousel-item h-32">
    <div class="badge badge-lg badge-secondary">Item 2</div>
  </div>
  <div class="carousel-item h-32">
    <div class="badge badge-lg badge-accent">Item 3</div>
  </div>
  <div class="carousel-item h-32">
    <div class="badge badge-lg badge-info">Item 4</div>
  </div>
</div>

帶導航的輪播

使用錨連結新增用於在輪播項目之間手動導航的按鈕。

html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<div class="carousel w-full">
  <div id="slide1" class="carousel-item relative w-full">
    <div class="badge badge-primary w-full h-32">Slide 1</div>
    <div class="absolute inset-x-0 top-1/2 flex justify-between px-2">
      <a href="#slide4" class="btn btn-circle btn-sm btn-ghost" aria-label="Previous slide"></a>
      <a href="#slide2" class="btn btn-circle btn-sm btn-ghost" aria-label="Next slide"></a>
    </div>
  </div>
  <div id="slide2" class="carousel-item relative w-full">
    <div class="badge badge-secondary w-full h-32">Slide 2</div>
    <div class="absolute inset-x-0 top-1/2 flex justify-between px-2">
      <a href="#slide1" class="btn btn-circle btn-sm btn-ghost" aria-label="Previous slide"></a>
      <a href="#slide3" class="btn btn-circle btn-sm btn-ghost" aria-label="Next slide"></a>
    </div>
  </div>
  <div id="slide3" class="carousel-item relative w-full">
    <div class="badge badge-accent w-full h-32">Slide 3</div>
    <div class="absolute inset-x-0 top-1/2 flex justify-between px-2">
      <a href="#slide2" class="btn btn-circle btn-sm btn-ghost" aria-label="Previous slide"></a>
      <a href="#slide4" class="btn btn-circle btn-sm btn-ghost" aria-label="Next slide"></a>
    </div>
  </div>
  <div id="slide4" class="carousel-item relative w-full">
    <div class="badge badge-info w-full h-32">Slide 4</div>
    <div class="absolute inset-x-0 top-1/2 flex justify-between px-2">
      <a href="#slide3" class="btn btn-circle btn-sm" aria-label="Previous slide">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg>
      </a>
      <a href="#slide1" class="btn btn-circle btn-sm" aria-label="Next slide">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>
      </a>
    </div>
  </div>
</div>

帶點指示器的輪播

使用小徽章按鈕作為多個輪播項目的導航指示器。

html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<div class="carousel w-full">
  <div id="item1" class="carousel-item w-full">
    <div class="badge badge-primary w-full h-32">1</div>
  </div>
  <div id="item2" class="carousel-item w-full">
    <div class="badge badge-secondary w-full h-32">2</div>
  </div>
  <div id="item3" class="carousel-item w-full">
    <div class="badge badge-accent w-full h-32">3</div>
  </div>
  <div id="item4" class="carousel-item w-full">
    <div class="badge badge-info w-full h-32">4</div>
  </div>
  <div class="flex justify-center gap-2 pt-4">
    <a href="#item1" class="btn btn-xs btn-outline">1</a>
    <a href="#item2" class="btn btn-xs btn-outline">2</a>
    <a href="#item3" class="btn btn-xs btn-outline">3</a>
    <a href="#item4" class="btn btn-xs btn-outline">4</a>
  </div>
</div>

JS 和 React 助手

使用 frutjam/js 中的 createCarouselfrutjam/eact 中的 useCarousel 以程式方式導航投影片 - 自動遵守 prefers-reduced-motion 以程式方式導覽投影片 - 自動遵守 prefers-reduced-motion

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<div class="flex gap-2 mb-3">
  <button class="btn btn-sm" id="carousel-prev">← Prev</button>
  <button class="btn btn-sm" id="carousel-next">Next →</button>
</div>
<div class="carousel w-full" id="js-carousel">
  <div class="carousel-item w-full"><div class="badge badge-primary w-full h-32">Slide 1</div></div>
  <div class="carousel-item w-full"><div class="badge badge-secondary w-full h-32">Slide 2</div></div>
  <div class="carousel-item w-full"><div class="badge badge-accent w-full h-32">Slide 3</div></div>
</div>
<script type="module">
  import { createCarousel } from 'frutjam/js'
  const carousel = createCarousel(document.getElementById('js-carousel'))
  document.getElementById('carousel-prev').onclick = () => carousel.prev()
  document.getElementById('carousel-next').onclick = () => carousel.next()
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import { useCarousel } from 'frutjam/react'

export default function CarouselDemo() {
  const carousel = useCarousel()
  return (
    <>
      <div className="flex gap-2 mb-3">
        <button className="btn btn-sm" onClick={carousel.prev}> Prev</button>
        <button className="btn btn-sm" onClick={carousel.next}>Next </button>
      </div>
      <div ref={carousel.ref} className="carousel w-full">
        <div className="carousel-item w-full"><div className="badge badge-primary w-full h-32">Slide 1</div></div>
        <div className="carousel-item w-full"><div className="badge badge-secondary w-full h-32">Slide 2</div></div>
        <div className="carousel-item w-full"><div className="badge badge-accent w-full h-32">Slide 3</div></div>
      </div>
    </>
  )
}