Đến nội dung chính

Carousel trượt ngang

Dùng khi muốn mời xem vài thứ đặt cạnh nhau mà không thứ nào gấp đến mức chiếm cả màn hình.

Phương tiện

Xem trước trực tiếp

Nguồn

<section class="dc-car" aria-roledescription="캐러셀" aria-label="이번 주 추천">
  <div class="dc-car__track" tabindex="0" role="group" aria-label="추천 3개, 좌우로 넘겨 보기">
    <article class="dc-car__slide" id="dc-car-s1">
      <div class="dc-car__media" role="img" aria-label="비계 위에서 본 현장 전경"></div>
      <h3 class="dc-car__title">가을 자재 할인전</h3>
      <p class="dc-car__desc">9월 30일까지 · 최대 18%</p>
    </article>
    <article class="dc-car__slide" id="dc-car-s2">
      <div class="dc-car__media" role="img" aria-label="안전 교육장 사진"></div>
      <h3 class="dc-car__title">신규 입사자 안전 교육</h3>
      <p class="dc-car__desc">9월 15일 오전 9시 · 2공구 회의실</p>
    </article>
    <article class="dc-car__slide" id="dc-car-s3">
      <div class="dc-car__media" role="img" aria-label="타설 장비 사진"></div>
      <h3 class="dc-car__title">장비 대여 신청 열림</h3>
      <p class="dc-car__desc">다음 주 배차까지 신청 가능</p>
    </article>
  </div>
  <nav aria-label="슬라이드 이동">
    <ul class="dc-car__dots">
      <li><a class="dc-car__dot" href="#dc-car-s1" aria-current="true"><span class="dc-sr">1번 슬라이드 보기</span></a></li>
      <li><a class="dc-car__dot" href="#dc-car-s2"><span class="dc-sr">2번 슬라이드 보기</span></a></li>
      <li><a class="dc-car__dot" href="#dc-car-s3"><span class="dc-sr">3번 슬라이드 보기</span></a></li>
    </ul>
  </nav>
</section>
.dc-car {
  /* 사진 위에 올라가는 글자와 배지는 두 테마에서 같은 쪽이어야 한다. 스크림이
     밝은 모드에서도 어두우므로 글자는 늘 밝은 쪽, 배지 바탕은 늘 어두운 쪽이다.
     고정색을 적는 대신 토큰을 양쪽에서 뒤집어 그 두 값을 만든다. */
  --dc-on-media: var(--dc-text-on);
  --dc-media-ink: var(--dc-text);
  font-family: var(--dc-font);
}
@media (prefers-color-scheme: dark) {
  .dc-car {
    --dc-on-media: var(--dc-text);
    --dc-media-ink: var(--dc-text-on);
  }
}
.dc-car__track {
  display: flex;
  gap: var(--dc-3);
  padding: var(--dc-1) var(--dc-4) var(--dc-2);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-left: var(--dc-4);
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.dc-car__track::-webkit-scrollbar { display: none; }
.dc-car__slide {
  position: relative;
  flex: 0 0 82%;
  display: flex;
  flex-direction: column;
  gap: var(--dc-2);
  padding: var(--dc-3);
  scroll-snap-align: start;
  background: var(--dc-surface);
  border: 1px solid var(--dc-line);
  border-radius: var(--dc-r-md);
  box-shadow: var(--dc-sh-1);
}
.dc-car__media {
  aspect-ratio: 16 / 10;
  border-radius: var(--dc-r-sm);
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--dc-brand) 32%, var(--dc-sunken)),
    var(--dc-sunken));
}
.dc-car__slide:nth-child(2) .dc-car__media {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--dc-info) 32%, var(--dc-sunken)),
    var(--dc-sunken));
}
.dc-car__slide:nth-child(3) .dc-car__media {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--dc-ok) 30%, var(--dc-sunken)),
    var(--dc-sunken));
}
.dc-car__title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--dc-text);
}
.dc-car__desc {
  font-size: 13px;
  line-height: 1.45;
  color: var(--dc-text-sub);
}
.dc-car__dots {
  display: flex;
  justify-content: center;
  align-items: center;
}
.dc-car__dot {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--dc-r-full);
  text-decoration: none;
}
.dc-car__dot::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: var(--dc-r-full);
  background: var(--dc-line-bold);
  transition: width var(--dc-slow), background var(--dc-slow);
}
.dc-car__dot[aria-current="true"]::before {
  width: 22px;
  background: var(--dc-brand);
}
.dc-car--full .dc-car__track { gap: 0; padding: 0; scroll-padding-left: 0; }
.dc-car--full .dc-car__slide {
  flex: 0 0 100%;
  gap: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.dc-car--full .dc-car__media { aspect-ratio: 3 / 2; border-radius: 0; }
.dc-car--full .dc-car__dots { margin-top: calc(-1 * var(--dc-7)); position: relative; }
.dc-car--full .dc-car__dot::before {
  background: color-mix(in srgb, var(--dc-on-media) 55%, transparent);
}
.dc-car--full .dc-car__dot[aria-current="true"]::before {
  background: var(--dc-on-media);
}
.dc-car__cap {
  position: absolute;
  inset: auto 0 0;
  display: grid;
  gap: var(--dc-1);
  padding: var(--dc-6) var(--dc-4) var(--dc-7);
  background: linear-gradient(to top,
    var(--dc-overlay),
    color-mix(in srgb, var(--dc-overlay) 45%, transparent) 45%,
    transparent);
}
.dc-car__cap .dc-car__title,
.dc-car__cap .dc-car__desc { color: var(--dc-on-media); }
.dc-car__count {
  position: absolute;
  top: var(--dc-4);
  right: var(--dc-4);
  padding: 2px var(--dc-2);
  border-radius: var(--dc-r-full);
  background: color-mix(in srgb, var(--dc-media-ink) 55%, transparent);
  color: var(--dc-on-media);
  font-size: 12px;
  font-weight: 700;
}

Cách dùng

  • Để thẻ kế tiếp hé ra, bề rộng khoảng 82% — thẻ tràn hết sẽ khiến người dùng không biết có thể trượt
  • Chỉ 3–5 thẻ. Nhiều hơn thì không ai xem tới cuối, hãy chuyển sang danh sách
  • Dấu chấm cho biết đang ở đâu; quá sáu thẻ thì đổi thành "2/5"
  • Đừng tự động chuyển — nội dung nhảy trong lúc đang đọc buộc người ta phải tìm lại

Điểm cần lưu ý

  • Nếu chấm bấm được thì vùng bấm phải 44×44px, dù chấm nhìn thấy vẫn nhỏ
  • Thiếu tabindex="0" trên khung trượt, người dùng bàn phím không bao giờ tới được thẻ thứ hai
  • Có chấm mà slide không có tên thì trình đọc chỉ đọc ra mấy tấm ảnh vô danh

Tiếp theo