タブ コンポーネントの作成

iOS アプリや Android アプリのものと同様のタブ コンポーネントを作成する方法について、基本的な概要を示します。

この投稿では、ウェブ用のタブ コンポーネントの構築に関する考え方を共有します。 応答性に優れ、複数のデバイス入力をサポートし、ブラウザで動作します。 デモをお試しください。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> デモ

動画で視聴したい場合は、この投稿の YouTube バージョンをご利用ください。

概要

タブはデザイン システムの一般的なコンポーネントですが、さまざまな形状や フォームです。最初は、<frame> 要素に基づくデスクトップ タブがありましたが、 物理特性に基づいてコンテンツをアニメーション化する、バターのようなモバイル コンポーネント。 どれも同じこと、「スペースの節約」を目指しています。

現在、タブのユーザー エクスペリエンスに不可欠なのはボタン ナビゲーション領域です 表示フレーム内のコンテンツの表示 / 非表示を切り替えます。多岐にわたる コンテンツ領域は同じスペースを共有しますが、各コンテンツ領域は、指定した基準に従って 移動することもできます。

<ph type="x-smartling-placeholder">
</ph> ウェブがコンポーネントのコンセプトに適用しているスタイルの非常に多様性により、コラージュはかなり混乱しています。 <ph type="x-smartling-placeholder">
</ph> 過去 10 年間に登場したタブ コンポーネントのウェブデザイン スタイルのコラージュ
をご覧ください。

ウェブ戦術

まとめると、このコンポーネントはとても簡単にビルドでき ウェブ プラットフォームの重要な機能:

  • scroll-snap-points: スマートなスワイプ操作とキーボード操作 適切なスクロール停止位置
  • ディープリンク - URL ハッシュを使用: ブラウザ処理、ページ内スクロールのアンカーと共有のサポート
  • <a> 要素と id="#hash" 要素のマークアップでのスクリーン リーダーのサポート
  • prefers-reduced-motion: クロスフェード遷移とインスタント検索を有効にします ページ内スクロール
  • 下書きの @scroll-timeline ウェブ機能。動的に下線を引いて、 選択したタブの色を変更する

HTML

ここでの UX は基本的に、リンクをクリックすること、ネストされた URL を URL で表すことです。 コンテンツ領域が更新されます。ブラウザが あります。

そこには構造的コンテンツ メンバー(リンクと :target)があります。水 リンクのリストが必要です。リンクのリストは <nav> が適しています。また、<article> のリストが必要です。 これには <section> が適しています。各リンクハッシュはセクションと一致し アンカー機能によって ブラウザがスクロールできるようにします

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> リンクボタンがクリックされ、フォーカスのあるコンテンツ内でスライドする

たとえば、リンクをクリックすると、:target の記事が自動的に Chrome 89、JS は不要。ユーザーは、 変更することはできません。これは無料のコンテンツであり、 マークアップを追加します。

次のマークアップを使用してタブを整理しました。

<snap-tabs>
  <header>
    <nav>
      <a></a>
      <a></a>
      <a></a>
      <a></a>
    </nav>
  </header>
  <section>
    <article></article>
    <article></article>
    <article></article>
    <article></article>
  </section>
</snap-tabs>

次のようにして、<a> 要素と <article> 要素間の接続を確立できます。 href プロパティと id プロパティは次のようになります。

<snap-tabs>
  <header>
    <nav>
      <a href="#responsive"></a>
      <a href="#accessible"></a>
      <a href="#overscroll"></a>
      <a href="#more"></a>
    </nav>
  </header>
  <section>
    <article id="responsive"></article>
    <article id="accessible"></article>
    <article id="overscroll"></article>
    <article id="more"></article>
  </section>
</snap-tabs>

次に、記事にさまざまなロレムを混ぜて、リンクに さまざまな長さと画像を組み合わせたタイトルのセットです。扱うコンテンツがあれば できます。

スクロール レイアウト

このコンポーネントには、次の 3 種類のスクロール領域があります。

  • ナビゲーション(ピンク)は水平方向 スクロール可能
  • コンテンツ領域(青)は水平方向 スクロール可能
  • 各記事項目(緑色)は縦方向です。 スクロール可能にします。
3 つのカラフルなボックスと、その色の方向を示す矢印(スクロール領域の枠線とスクロール方向を示す矢印)が表示されている。

スクロールに関連する要素には、次の 2 種類があります。

  1. ウィンドウ
    overflow が定義された、寸法が定義されたボックス プロパティ スタイル。
  2. 特大サーフェス
    このレイアウトでは、リストコンテナ: nav リンク、セクション記事、記事の内容です。

レイアウト: <snap-tabs>

私が選んだ最上位のレイアウトは Flex(Flexbox)でした。方向を column の場合は、ヘッダーとセクションが縦方向に並べられます。Google の スクロール ウィンドウが表示され、オーバーフローが非表示になります。ヘッダーと セクションでは、個別のゾーンとしてまもなくオーバースクロールが使用されます。

HTML
<snap-tabs>
  <header></header>
  <section></section>
</snap-tabs>
CSS
  snap-tabs {
  display: flex;
  flex-direction: column;

  /* establish primary containing box */
  overflow: hidden;
  position: relative;

  & > section {
    /* be pushy about consuming all space */
    block-size: 100%;
  }

  & > header {
    /* defend against 
needing 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }

カラフルな 3 スクロールの図に戻ると、

  • これで <header>(ピンク)になる準備が整いました。 スクロール コンテナ。
  • <section>(青)スクロールとして準備されています。 されます。

下でハイライトしたフレームは VisBug は、Google がウィンドウを確認し、 作成できます。

ヘッダーとセクションの要素にはホットピンクのオーバーレイがあり、コンポーネント内で占めるスペースを囲んでいます。

タブの <header> レイアウト

次のレイアウトもほぼ同じです。Flex を使用して縦方向の順序付けを作成します。

HTML
<snap-tabs>
  <header>
    <nav></nav>
    <span class="snap-indicator"></span>
  </header>
  <section></section>
</snap-tabs>
CSS
header {
  display: flex;
  flex-direction: column;
}

.snap-indicator は、リンクのグループに沿って水平に移動する。 このヘッダーレイアウトは その舞台を整えるのに役立ちますここに絶対位置の要素はありません。

nav 要素と span.indicator 要素には、コンポーネント内で占めるスペースを囲む、ホットピンクのオーバーレイがあります。

次はスクロールのスタイルですスクロール スタイルを共有できることがわかりました。 2 つの横スクロール領域(ヘッダーとセクション)の間に クラス、.scroll-snap-x

.scroll-snap-x {
  /* browser decide if x is ok to scroll and show bars on, y hidden */
  overflow: auto hidden;
  /* prevent scroll chaining on x scroll */
  overscroll-behavior-x: contain;
  /* scrolling should snap children on x */
  scroll-snap-type: x mandatory;

  @media (hover: none) {
    scrollbar-width: none;

    &::-webkit-scrollbar {
      width: 0;
      height: 0;
    }
  }
}

それぞれが X 軸でオーバーフロー、オーバースクロールをトラップするためのスクロール封じ込め、非表示が必要 タッチデバイスではスクロールバー、コンテンツのロックではスクロール スナップを使用します。 説明します。キーボードのタブの順序がアクセス可能で、操作ガイド 自然に焦点を絞ることができますスクロール スナップ コンテナも適切なカルーセル スタイルで表示されます 簡単に操作できます。

タブのヘッダー <nav> レイアウト

ナビゲーション リンクは、縦方向に、改行を入れずに一直線に配置する必要があります。 各リンク項目をスクロール スナップ コンテナにスナップする必要があります。Swift 2021 年の CSS です。

HTML
<nav>
  <a></a>
  <a></a>
  <a></a>
  <a></a>
</nav>
CSS
  nav {
  display: flex;

  & a {
    scroll-snap-align: start;

    display: inline-flex;
    align-items: center;
    white-space: nowrap;
  }
}

各リンクはそれ自体のスタイルとサイズを設定するため、ナビゲーション レイアウトは 方向と流れです。ナビゲーション アイテムの幅を一意にすることでタブ間の遷移を実現 インジケーターが新しいターゲットに合わせて幅を調整します。いくつもの 要素がある場合、ブラウザはスクロールバーを表示するかどうかを決定します。

ナビゲーションの a 要素にはホットピンク オーバーレイがあり、コンポーネント内で占めるスペースとオーバーフローする領域が概説されている

タブの <section> レイアウト

このセクションはフレキシブル アイテムであり、スペースを最も多く使用する必要があります。これは、 記事を配置する列も作成する必要がありますここでも CSS 2021 でぜひご利用ください。block-size: 100% は、この要素を引き伸ばして、 それ自体のレイアウトで、一連の親要素が作成される 親の幅が 100% である列。ここではパーセンテージが効果的 親に厳密な制約を記述したからです

HTML
<section>
  <article></article>
  <article></article>
  <article></article>
  <article></article>
</section>
CSS
  section {
  block-size: 100%;

  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
}

これはまるで、押し付けがましい方法で、垂直方向に可能な限り拡大するようなものです。 (flex-shrink: 0 に設定したヘッダーを思い出してください。この問題に対する防御策です。 展開プッシュなど)を使用して、行の高さを設定します。「 auto-flow スタイルは、子を常に水平方向にレイアウトするようグリッドに指示します 行を折り返しません親ウィンドウにオーバーフローします

記事の要素がホットピンクのオーバーレイで表示され、コンポーネント内で占める領域とあふれている領域が概説されている

頭を巻き込むのが難しいから!このセクション要素は 同時に一連の箱を作りましたビジュアルと 説明が役に立ちます。

タブの <article> レイアウト

ユーザーが記事コンテンツをスクロールでき、スクロールバーが オーバーフローがある場合にのみ表示されます。これらの記事の要素が見やすく整理されています なります。同時に親はスクロールの親で、スクロールの子でもあります。「 ブラウザは複雑なタップ操作、マウス操作、キーボード操作に実際に対応しています。 説明します。

HTML
<article>
  <h2></h2>
  <p></p>
  <p></p>
  <h2></h2>
  <p></p>
  <p></p>
  ...
</article>
CSS
article {
  scroll-snap-align: start;

  overflow-y: auto;
  overscroll-behavior-y: contain;
}

親スクローラー内に記事をスナップするようにしました。非常に好きな ナビゲーション リンク項目と記事要素がインライン開始にスナップする方法 表示することもできます。見た目も使用感も あります。

記事要素とその子要素には、コンポーネント内で占めるスペースとオーバーフロー方向が輪郭線で囲まれているホットピンクのオーバーレイがあります

記事がグリッドの子であり、サイズがビューポートとして事前に定義されている スクロールの UX を提供したい領域ですつまり高さと幅は必要ないので ここにはスタイルがありますが、あとはオーバーフロー方法を定義するだけです。「overflow-y」を「auto」に設定し さらに、便利なオーバースクロール動作でスクロール操作をトラップします。 プロパティです。

3 つのスクロール エリアのまとめ

システム設定で [スクロールバーを常に表示する] を選択しました。たぶん レイアウトが機能することの重要性が 2 倍に高まっています。 レイアウトとスクロールの連携を確認しましょう。

3 つのスクロールバーが表示されるよう設定されており、レイアウト スペースを消費するようになり、コンポーネントも見栄えが良くなりました。

スクロールバーのガターを見れば スクロール領域の方向、スクロール領域と 相互作用する方法 相互に通信します。これらの各スクロール ウィンドウ フレームも グリッドの親をレイアウトに追加します。

DevTools を使用してこれを可視化します。

<ph type="x-smartling-placeholder">
</ph> スクロール領域にはグリッドと Flexbox ツールのオーバーレイがあり、コンポーネント内で占めるスペースとオーバーフローする方向が概説されています。 <ph type="x-smartling-placeholder">
</ph> Flexbox のナビゲーション要素のレイアウトがアンカー要素でいっぱいの Chromium Devtools 記事の要素でいっぱいのグリッド セクション レイアウトと、 段落や見出し要素でいっぱいの要素です。

スクロール レイアウトの完成(スナップ、ディープリンク可能、キーボード) アクセスできるようにします。UX の強化、スタイル、楽しさの強力な基盤。

注目の機能

スナップされた子をスクロールすると、サイズ変更時にロック位置が維持されます。つまり デバイスの回転時やブラウザでの表示時に、JavaScript で何も表示する必要がない クリックします。Chromium DevTools で試すデバイス モード [レスポンシブ] 以外のモードを選択してから、デバイス フレームのサイズを変更する 要素がビューに表示され、コンテンツによってロックされたままになります。このたびは 使用できるようになりました。こちらが 関連するブログ投稿をご覧ください。

アニメーション

ここでのアニメーションの目的は、UI の操作を明確にリンクすることです。 できます。これは、ユーザーを(うまくいけば) コンテンツを発見しやすくします目的と行動を意識して できます。ユーザーはモーションを 環境の設定、 インターフェースで視聴者の好みに応えるのが大好きです。

記事のスクロール位置にタブの下線をリンクします。スナップは アニメーションの開始と終了を固定します これにより、<nav> が保持され、 コンテンツに接続されるミニマップ。 CSS と JS の両方からユーザーのモーション設定を確認します。また、 思いやりのある場所はほとんどない!

スクロール動作

:targetelement.scrollIntoView()。デフォルトは Instant です。ブラウザは スクロール位置を指定しますでは、スクロール位置に遷移させるにはどうすればよいでしょうか。 どうすればよいでしょうか。

@media (prefers-reduced-motion: no-preference) {
  .scroll-snap-x {
    scroll-behavior: smooth;
  }
}

ここではモーションを導入します (スクロールなど)スタイルを適用できるのは、ユーザーが選択を オペレーティングシステムの 動作を縮小できるからですこれにより 同意を示す必要があります

タブのインジケーター

このアニメーションの目的は、インジケーターと状態を関連付けることを できます。ユーザー向けにクロスフェード border-bottom スタイルに色を付けることにしました 動きの少ない、スクロール リンクのスライド + カラーフェード アニメーションを好むユーザー モーションに抵抗のない ユーザーを優先して配信されます

Chromium DevTools で設定を切り替えて、2 つの さまざまな遷移スタイルを使用できます。構築はとても楽しかったです。

@media (prefers-reduced-motion: reduce) {
  snap-tabs > header a {
    border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
    transition: color .7s ease, border-color .5s ease;

    &:is(:target,:active,[active]) {
      color: var(--text-active-color);
      border-block-end-color: hsl(var(--accent));
    }
  }

  snap-tabs .snap-indicator {
    visibility: hidden;
  }
}

ユーザーが動きの抑制を好む場合は .snap-indicator を非表示にします。 必要なくなります。次に、それを border-block-end スタイルと transition。また、タブ操作では、アクティブなナビゲーション アイテムが ブランドの下線のハイライトだけなのに テキストの色も暗くなっています「 アクティブ要素では、テキストの色のコントラストが高くなり、暗い色調のアクセントになります。

CSS を数行追加するだけで、見られているとユーザーに感じてもらえます ユーザーのモーションの好みを尊重しています)。気に入ったわ

@scroll-timeline

前のセクションでは、モーションを低減したクロスフェードを処理する方法を説明しました。 できます。このセクションでは、インジケータと まとめて確認できます次はおもしろい実験的な機能についてです。皆さんが とても楽しみです。

const { matches:motionOK } = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
);

まず、JavaScript でユーザーのモーション設定を確認します。結果に false であり、ユーザーがモーションの軽減を好むことを意味し、何も実行しません。 モーション効果のリンクです

if (motionOK) {
  // motion based animation code
}

このドキュメントの作成時点では、 @scroll-timeline はありません。Google ドラフト仕様に 実装しています。ただし、ここではポリフィルを使用します。 説明します。

ScrollTimeline

CSS と JavaScript のどちらでもスクロールのタイムラインを作成できますが、ここでは、 アニメーションでライブ要素の測定を使用できるようにします。

const sectionScrollTimeline = new ScrollTimeline({
  scrollSource: tabsection,  // snap-tabs > section
  orientation: 'inline',     // scroll in the direction letters flow
  fill: 'both',              // bi-directional linking
});

あるものを別のスクロール位置に合わせて表示させ、 ScrollTimeline スクロール リンクのドライバ scrollSource を定義します。 通常、ウェブ上のアニメーションはグローバルな時間枠で実行されますが、 カスタム sectionScrollTimeline をメモリに保持したい場合は、すべて変更できます。

tabindicator.animate({
    transform: ...,
    width: ...,
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

アニメーションのキーフレームに入る前に、 スクロールのフォロワー(tabindicator)を指し、アニメーション ベースで表示します カスタムタイムライン上に表示されますこれでリンクは完了しますが、 最後の要素(アニメーション化するステートフルなポイント)が不足しています。 できます。

動的キーフレーム

非常に強力な純粋な宣言型 CSS を使用して、 @scroll-timelineだが、選択したアニメーションが動的すぎる現在、 auto の幅の間で切り替える手段が用意されており、 子の長さに基づくキーフレームの数。

ただし、JavaScript がその情報を取得する方法を認識しているため、 実行時に計算された値を取得するようにします。

tabindicator.animate({
    transform: [...tabnavitems].map(({offsetLeft}) =>
      `translateX(${offsetLeft}px)`),
    width: [...tabnavitems].map(({offsetWidth}) =>
      `${offsetWidth}px`)
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

tabnavitem ごとに、offsetLeft の位置を分離して文字列を返します。 それを translateX 値として使用するものです。これにより、4 つの変換キーフレームが 作成します。幅についても同様に、ダイナミック幅について質問します。 キーフレーム値として使用されます

フォントとブラウザの設定に基づく出力例は次のとおりです。

TranslateX キーフレーム:

[...tabnavitems].map(({offsetLeft}) =>
  `translateX(${offsetLeft}px)`)

// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]

キーフレームの幅:

[...tabnavitems].map(({offsetWidth}) =>
  `${offsetWidth}px`)

// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]

まとめると、タブ インジケーターが 4 つのキーフレームにわたってアニメーション表示されるようになりました。 セクション スクローラーのスクロール スナップ位置に応じて異なります。スナップ ポイント キーフレーム間の境界を明確にして アニメーションの感触が同期します。

アクティブ タブとアクティブでないタブが VisBug オーバーレイで表示され、両方のコントラスト スコアが合格していることを示す

ユーザーは、動画の幅と高さ、 あるセクションから次のセクションへのインジケーターの変化の位置、追跡 スクロールできます

お気づきでないかもしれませんが ハイライト表示されたナビゲーション項目が選択されます。

選択されていない薄いグレーは、ハイライト表示された部分が コントラストが大きくなります。カーソルを合わせたときなど、テキストの色が遷移するのは スクロール時に色が変わって表示されます 下線インジケーターと同期されます。

方法は次のとおりです。

tabnavitems.forEach(navitem => {
  navitem.animate({
      color: [...tabnavitems].map(item =>
        item === navitem
          ? `var(--text-active-color)`
          : `var(--text-color)`)
    }, {
      duration: 1000,
      fill: 'both',
      timeline: sectionScrollTimeline,
    }
  );
});

各タブ ナビゲーション リンクにはこの新しいカラー アニメーションが必要で、同じスクロールがトラッキングされます 下線インジケーターとして使用できます。以前と同じタイムラインを使用します。 目盛りをスクロールしたときに 目盛りを出力できます 追加します。先ほどと同じようにループ内に 4 つのキーフレームを作成し、 できます。

[...tabnavitems].map(item =>
  item === navitem
    ? `var(--text-active-color)`
    : `var(--text-color)`)

// results in 4 array items, which represent 4 keyframe states
// [
  "var(--text-active-color)",
  "var(--text-color)",
  "var(--text-color)",
  "var(--text-color)",
]

var(--text-active-color) 色のキーフレームでリンクがハイライト表示されます。 それ以外は標準のテキスト色です。ネストされたループにより、 外側のループが各ナビゲーション項目で、内側のループが navitem の個人用キーフレームです外側のループの要素が 選択されたときにそれを知ることができます。

これを書くのはとても楽しかったです。大好きさ

その他の JavaScript の機能強化

ここで紹介するコア機能は 使用できます。では次に、JavaScript がコードベースに できます。

ディープリンクの意図はモバイル上の用語だと思いますが、 タブを使用して、タブのコンテンツへの URL を直接共有できます。「 ブラウザは、URL ハッシュで一致した ID にページ内を移動します。見つかった この onload ハンドラにより、プラットフォーム間で影響が及びました。

window.onload = () => {
  if (location.hash) {
    tabsection.scrollLeft = document
      .querySelector(location.hash)
      .offsetLeft;
  }
}

スクロール終了の同期

ユーザーは必ずしもキーボードをクリックしたり 操作したりしているわけではなく スクロールせずに見える範囲に 配置してくださいセクション スクローラーが停止したとき スクロール(スクロールする場所)を上部のナビゲーション バーに配置する必要があります。

スクロールの終了を待つ方法: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });

セクションをスクロールするときは常に、セクション タイムアウトがあればクリアします。 新しいものを作成できますセクションのスクロールを停止するときは、タイムアウトをクリアしないでください。 休息後 100 ミリ秒後に起動します。イベントが発生したら、関数を呼び出して、 ユーザーが停止したところから 再開されます

const determineActiveTabSection = () => {
  const i = tabsection.scrollLeft / tabsection.clientWidth;
  const matchingNavItem = tabnavitems[i];

  matchingNavItem && setActiveTab(matchingNavItem);
};

スクロールがスナップされたと仮定し、現在のスクロール位置を幅で割った値 は、スクロール領域の小数ではなく整数値にする必要があります。次に、 この計算されたインデックスを介してキャッシュから navitem を取得し、 一致するものを送信します。

const setActiveTab = tabbtn => {
  tabnav
    .querySelector(':scope a[active]')
    .removeAttribute('active');

  tabbtn.setAttribute('active', '');
  tabbtn.scrollIntoView();
};

アクティブなタブを設定するには、まず現在アクティブなタブをすべて消去してから、 ナビゲーション アイテムのアクティブ状態属性。scrollIntoView() への呼び出し CSS とのインタラクションが楽しいものであることは注目に値します。

.scroll-snap-x {
  overflow: auto hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;

  @media (prefers-reduced-motion: no-preference) {
    scroll-behavior: smooth;
  }
}

水平スクロールのスナップ ユーティリティ CSS には、 ネストしたメディアクエリ smooth のスクロール(ユーザーがモーション トレラントな場合)。JavaScript は JavaScript により、 を呼び出してスクロール要素を表示でき、CSS では宣言的に UX を管理できます。 ときどき小さいマッチングができて、とても嬉しい。

まとめ

私のやり方わかったな、どうやって?!楽しい時間をお過ごしください 説明します。誰が最初のバージョンを フレームワーク🙂

アプローチを多様化して、ウェブで構築するすべての方法を学びましょう。 グリッチを作成してツイート コミュニティ リミックスに追加します。 セクションをご覧ください。

コミュニティ リミックス