カードを作成する

概要

カードは、関連するコンテンツまたは選択肢を 1 つにまとめたものです。これは視覚的なパターンであり、固定されたセマンティック モデルやインタラクション モデルではないため、コンテンツの意味を維持し、目的に合ったネイティブ インタラクションを使用してください。

ガイドライン

コンテンツとそのインタラクションのセマンティクスを個別に選択します。

  • リンク先へのリンクの有無にかかわらず、<article> をカードのルートとして使用します。
  • ナビゲーションにネイティブ リンクを使用します。カード全体が 1 つのリンク先である場合、カードに他のインタラクティブ要素(a、button、input、select、textarea)が含まれていない場合にのみ、1 つのリンクで <article> をラップできます。
  • 独立したアクションのリンクとボタンは、別々のネイティブ コントロールとして保持します。
  • カードが選択肢の場合は、関連付けられた <label> を含むラジオボタンまたはチェックボックス、またはネイティブ <select> の option を使用します。

メディア、タイトル、サポート コンテンツ、アクションを意味のあるソース順序で配置します。CSS order を使用して、これに反する配置にしないでください(CSS レイアウトとレスポンシブ デザインを参照)。

実装

マークアップを最小限に抑え、CSS セレクタで各リージョンを認識できるようにすることで、シンプルなカードはシンプルなまま、よりリッチカードも可能になります。カードには、このソース順に最大 4 つのリージョンがあり、いずれも省略できます。リージョンはカードの直接の子であり、.card__body などのラッパー要素にグループ化されていないため、セレクタによるリージョンの配置やスタイル設定はできません。要素が 1 つだけの領域は、その要素自体であり、ラップされません。1 つの段落は <p> です。ラッパーは、リージョンに複数の要素が含まれている場合にのみ使用します。

  • Media: <img>、<picture>、<video>、<svg> のいずれかを最初の子として指定します。.media クラスは、これらの要素以外の任意のヒーロー コンテンツにのみ追加します。プレーンな <img> を .media 要素でラップしないでください。
  • ヘッダー: 単独の見出し。<hgroup> は、見出しにサブタイトルまたはタグラインがある場合にのみ使用します。<header> は、領域にタイトルだけでなく、署名やバッジなども含まれる場合に使用します。カードにメインのリンク先がある場合、リンクは見出し内に配置されます。
  • コンテンツ: 1 つの <p>、<ul>、<dl> が単独で存在します。コンテンツが複数の要素(複数の段落、段落とリストなど)で構成されている場合は、1 つの <div> にグループ化して、リージョンが 1 つのグリッド項目になるようにします。
  • フッター: 独立したアクションをネイティブ リンクとボタンとして保持する <footer>。「続きを読む」リンクは、見出しリンクの URL を共有できますが、視覚的に非表示のテキスト(例: Read more<span> about poached eggs</span>)を使用して、表示されるテキストで始まるわかりやすいユーザー補助機能用の名前を付けます。これは、同一の「続きを読む」リンクがスクリーン リーダーのリンク一覧で曖昧になるためです。見出しの URL を繰り返す他のフッターリンクを追加しないでください。

最もシンプルなカードは、見出しと段落を含む <article> です。カードの動作に一致するリンクとアクションのパターンを選択します。インタラクション モデルをご覧ください。

固定比率の領域を埋めるカード画像または動画の場合は、<img> または <video> 自体に aspect-ratio と object-fit: cover を設定して、歪みなく領域を埋めるようにします(トリミングが発生する場合があります)。.media コンテナの aspect-ratio は、他のヒーロー コンテンツにのみ使用します。それ以外の場合は、メディアの固有の比率を維持します。情報を提供する画像には適切な代替テキストを付け、装飾用の画像には alt="" を使用します。

利用可能なスペースに合わせる

レイアウトは、ビューポートではなく、カードの使用可能なスペースに基づいて設定します。カードの子孫(メディア、テキスト、アクション)を適応させるには、カードをサイズ コンテナ(container-type: inline-size)にして、その子に対して @container ルールを記述します。グリッドまたはリストの親からサイズを決定しないようにします。カードの実際の幅は、列数やギャップなどによって異なるため、親ベースのブレークポイントはノイズが多くなります。

幅の狭いコンテナでは、リージョンをソース順に積み重ねます。幅の広いコンテナでは、メディアを他の領域の横のサイド列に配置します。ただし、メディアを含むカードのみを対象とします。メディアの子(.card:has(> img) など)に :has() を指定して、これらのルールをスコープ設定します。これにより、列の定義と grid-column の配置がメディアのないカードに適用されることはありません。メディアのないカードは、どの幅でも 1 列のままです。空のメディア列を予約しないでください。

カードをグリッドに沿って配置する

行内のカードが領域の高さを共有する必要がある場合は、subgrid を使用します。各カードが 4 つの共有行トラック(メディア、ヘッダー、コンテンツ、フッター)にまたがるようにし、要素セレクタで領域を配置します。メディア、見出し、<footer> 以外のものはすべてコンテンツとして扱います。リージョンを省略したカードでは、そのトラックが空のままになるため、残りのリージョンは隣接するカードと揃ったままになります。各トラックには 1 つのグリッド アイテムが保持されるため、コンテンツ領域に複数の要素があり、カードがトラックを共有している場合にのみ、コンテンツ領域を <div> でラップします。兄弟要素と揃っていないカードには、ラッパーもサブグリッドも必要ありません。

インタラクション モデル

コンテンツ カード

カードのルートとして <article> を使用します。リンクとボタンは、別々のネイティブ コントロールとして保持します。

単一目的地のカード

カード全体が 1 つのリンク先であり、独立したアクションがない場合は、1 つのネイティブ リンクを使用します。リンクは <article> をラップできます。リンク内に他のリンク、ボタン、フォーム コントロールをネストしないでください。「続きを読む」などのテキストは、プレーンな <p> または <span> にしてください。リンクのユーザー補助機能用の名前はカードのテキスト全体であるため、コンテンツは短くしてください。カードに大量のテキストや他のアクションがある場合は、以下の stretched-link パターンを使用して、見出しのみをリンクにします。

<a href="/recipes/poached-eggs">
  <article class="card">
    <h3>Poached eggs</h3>
    <p>Two poached eggs served on toasted sourdough.</p>
  </article>
</a>

独立したアクションを含むクリック可能なカード

カードをクリックしたときに、ナビゲーションではなくアクションがトリガーされる場合は、リンクではなく <button> を使用します。

コンテンツ カードがメインのリンク先にリンクし、他のインタラクティブ要素も含まれていて、全体をクリック可能にする必要がある場合:

  • メインリンク自体に 1 つのオプトインを使用します。カードごとに 1 つのリンク(見出しリンク)に .card-link を配置します。フッターやその他のリンクは、独自のオーバーレイを拡張し、最後のリンクがカード全体をキャプチャするため、この属性を取得することはありません。
  • タイトルをリンクし、::after を使用してポインタのヒット領域をカード全体に広げます。
.card:has(a.card-link) {
    position: relative;
}

.card a.card-link::after {
    content: "";
    position: absolute;
    inset: 0;
}
  • インタラクティブ要素を position: relative; z-index: 1 で引き上げて、操作可能な状態を維持します。クラスを介したオプトインを要求するのではなく、要素のターゲット タイプ(a, button など)を指定します。
  • z-index をコンテナ全体に適用しないでください。適用すると、アクションを生成しないポインタイベントがキャプチャされます。
.card:has(a.card-link) {
    /* Keep other interactive elements above the overlay */
    a:not(.card-link), button, input, x-button {
        position: relative;
        z-index: 1;
    }
}
  • 引き伸ばされたリンクではなく、ホバー / フォーカス時にカード自体のスタイルを設定します。
.card {
    a.card-link {
        &:focus-visible {
            outline: none; /* Draw it on the card instead */
        }
    }
    
    &:has(a.card-link:focus-visible) {
        /* Focus ring */
    }

    &:has(a.card-link:hover) {
        /* Hover styles */
    }
}

選択カード

事前定義された選択肢を表すカードの場合は、<label class="card"> を使用し、チェックボックスまたはラジオボタンを直接の子として配置します。

選択したカードのスタイルを :has(:checked) で設定します。選択時に border-width、padding、font-weight などのレイアウトに影響するプロパティを変更しないでください。カードとその隣のカードがジャンプするためです。outline、box-shadow、または色のみが変化する透明な枠線を使用して強調表示します。

.card {
  border: 2px solid transparent;

  &:has(> :checked) {
    border-color: var(--accent);
  }
}

表示されているチェックボックスやラジオボタン自体が、選択を示す色以外のインジケーターであるため、色の変更だけで十分です。コントロールが視覚的に非表示になっている場合(フォーカス可能で、ユーザー補助ツリーに表示されるようにします。display: none は使用しないでください)、レイアウトに影響しない色以外のインジケーター(チェックアイコンや太い outline など)を追加します。

選択肢が、オプションがカードとして配置されているプルダウン ピッカーに属している場合は、選択肢を <div> カードに置き換えるのではなく、appearance: base-select を含むネイティブの <select> を使用し、::picker(select) 要素と <option> 要素のスタイルを設定します。詳細と代替手段については、カスタム選択ピッカーのレイアウトをご覧ください。