CSS scroll snap と ::scroll-button()

縦スクロールSample


概要

- `::scroll-button()` `::scroll-marker` `::scroll-marker-group` `scroll-state()` は CSS の新しい機能 - 2026年05月27日現在、対応しているのはChrome 135以降とEdgeだけ - 現在表示中のアイテムに対応するマーカーが赤く塗りつぶされ、マーカーをクリックすると該当位置までスナップスクロールするサンプル - Container Scroll-State Queries により、左方向にスクロール可能なときだけ◀ボタン、右方向にスクロール可能なときだけ▶ボタンが表示されるサンプル

デモ

CSS Modern Features no.1

CSS Modern Features no.2

CSS Modern Features no.3

CSS Modern Features no.4

CSS Modern Features no.5

CSS Modern Features no.6


コード

HTML

<section class="container">
  <article class="content" data-index="0">
    <h4>CSS Modern Features no.1</h4>
  </article>
  <article class="content" data-index="1">
    <h4>CSS Modern Features no.2</h4>
  </article>
  <article class="content" data-index="2">
    <h4>CSS Modern Features no.3</h4>
  </article>
  <article class="content" data-index="3">
    <h4>CSS Modern Features no.4</h4>
  </article>
  <article class="content" data-index="4">
    <h4>CSS Modern Features no.5</h4>
  </article>
  <article class="content" data-index="5">
    <h4>CSS Modern Features no.6</h4>
  </article>
</section>

        

CSS

body {
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans", "Yu Gothic UI", sans-serif;
  padding: 24px;
  line-height: 1.6;
  color: #222;
}

h1 {
  font-size: 18px;
  margin-bottom: 8px;
}

.note {
  background: #fff8e1;
  border-left: 4px solid #ffb300;
  padding: 8px 12px;
  margin-bottom: 24px;
  font-size: 13px;
}

/* ===== 記事のサンプルコード ===== */
.container {
  overflow-y: scroll;
  height: 360px;
  width: 280px;
  border: 1px solid black;

  /* Scroll Snap Events */
  scroll-snap-type: y mandatory;

  /* Container Scroll-State Queries */
  container-type: scroll-state;

  /* スクロールボタン本体(初期は非表示) */
  &::scroll-button(up) {
    content: "▲";
    opacity: 0;
    transition: opacity 0.2s;
  }
  &::scroll-button(down) {
    content: "▼";
    opacity: 0;
    transition: opacity 0.2s;
  }

  /* 上方向にスクロール可能なときだけ上ボタンを表示 */
  @container scroll-state(scrollable: top) {
    &::scroll-button(up) {
      opacity: 1;
    }
  }
  /* 下方向にスクロール可能なときだけ下ボタンを表示 */
  @container scroll-state(scrollable: bottom) {
    &::scroll-button(down) {
      opacity: 1;
    }
  }

  /* スクロールボタン共通スタイル */
  &::scroll-button(*) {
    background-color: #000;
    color: #fff;
    border-radius: 100%;
    display: inline-flex;
    justify-content: center;
    align-items: center;
    width: 24px;
    height: 24px;
    margin: 4px;
  }
}

.content {
  scroll-snap-align: center;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #e3f2fd;
  border-bottom: 1px solid #90caf9;
  box-sizing: border-box;
}

.content h4 {
  margin: 0;
  font-size: 16px;
}

.subtitle {
  margin-top: 16px;
  padding: 8px 12px;
  background: #f5f5f5;
  border-radius: 4px;
  font-size: 14px;
  min-height: 1.6em;
}

        

JavaScript

const SUB_TITLES = [
  "新しい擬似クラス:has()、:is()、:where()を使いこなそう",
  "Container Queries/祖先要素に応じたCSSの切り替え",
  "Cascade Layers/レイヤーによる優先順位の制御",
  "CSS Nesting Module/CSSの入れ子指定",
  "Scoped Styles/スコープ付きスタイルルール",
  "Cascade Sorting Order/CSSの適用順序を学び直す",
];

document.addEventListener("DOMContentLoaded", () => {
  const container = document.querySelector(".container");
  const subtitle = document.querySelector(".subtitle");

  subtitle.innerHTML = SUB_TITLES[0];

  container.addEventListener("scrollsnapchange", (event) => {
    const index = Number(event.snapTargetBlock.dataset.index);
    subtitle.innerHTML = SUB_TITLES[index];
  });
});


      

参照