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

色適応型でレスポンシブでアクセスしやすい <button> コンポーネントを構築する方法の基本的な概要。

この投稿では、色調整機能があり、レスポンシブで、アクセスしやすく <button> 要素を作成する方法について、私の考えをご紹介します。デモをお試しください。また、ソースを確認してください。

ライトモードとダークモードでは、ボタンがキーボードとマウスで操作されます。

動画をご覧になる場合は、この投稿の YouTube バージョンをご覧ください。

概要

対応ブラウザ

  • 1
  • 12
  • 1
  • 4 以下

ソース

<button> 要素は、ユーザー操作のために作成されています。click イベントは、タイミングに関するスマートルールを使用して、キーボード、マウス、タップ、音声などからトリガーされます。また、各ブラウザにデフォルトのスタイルがいくつか用意されているため、カスタマイズせずに直接使用できます。color-scheme を使用して、ブラウザが提供するライトボタンとダークボタンも有効にします。

前述の Codepen の埋め込みには、さまざまな種類のボタンもあります。タイプが指定されていない <button> は、<form> 内にあるように適応され、送信タイプに変更されます。

<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>

<!-- button state -->
<button disabled></button>

<!-- input buttons -->
<input type="button" />
<input type="file">

今月の GUI チャレンジでは、各ボタンにスタイルを付与し、インテントを視覚的に区別できるようにします。リセットボタンは破壊的であるため、警告の色が付きます。送信ボタンは青色のアクセント テキストになるため、通常のボタンよりもやや目立つように見えます。

すべてのボタンタイプの最終セットのプレビュー。フォームではなくフォームで表示される。また、アイコンボタンやカスタマイズされたボタンも追加されている。
フォームではなくフォームに表示される、すべてのボタンタイプの最終セットのプレビュー。アイコンボタンとカスタマイズされたボタンの優れた機能が追加されています。

ボタンには、CSS がスタイル設定に使用する疑似クラスもあります。これらのクラスは、ボタンの外観をカスタマイズするための CSS フックを提供します。たとえば、マウスがボタンに重なったときは :hover、マウスまたはキーボードが押されたときは :active、支援技術のスタイル設定を支援する :focus または :focus-visible です。

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
ダークモードのすべてのボタンタイプの最終セットのプレビュー。
ダークモードの全ボタンタイプの最終セットのプレビュー

マークアップ

HTML 仕様で提供されるボタンタイプに加えて、アイコンとボタンを含むボタンとカスタムクラス btn-custom を追加しました。

<button>Default</button>
<input type="button" value="<input>"/>
<button>
  <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
    <path d="..." />
  </svg>
  Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">

次に、テスト用の各ボタンをフォーム内に配置します。これにより、送信ボタンとして機能するデフォルト ボタンのスタイルが適切に更新されるようになります。また、アイコンの戦略をインライン SVG からマスクされた SVG に切り替えて、どちらも同じように適切に機能するようにします。

<form>
  <button>Default</button>
  <input type="button" value="<input>"/>
  <button>Icon <span data-icon="cloud"></span></button>
  <button type="submit">Submit</button>
  <button type="button">Type Button</button>
  <button type="reset">Reset</button>
  <button disabled>Disabled</button>
  <button class="btn-custom btn-large" type="button">Large Custom</button>
  <input type="file">
</form>

この時点では、さまざまな組み合わせが見つかりやすくなります。ボタンタイプ、疑似クラス、フォーム内外の間で、20 を超える組み合わせのボタンがあります。CSS を利用すると、それぞれの要素を明確に表現できるという利点があります。

ユーザー補助

ボタン要素には自然にアクセスできますが、一般的な機能強化もいくつかあります。

カーソルを合わせてフォーカスを合わせる

:hover:focus:is() 機能疑似セレクタと一緒にグループ化します。これにより、インターフェースは常にキーボードと支援技術のスタイルを考慮できます。

button:is(:hover, :focus) {
  …
}
デモを試す

インタラクティブなフォーカス リング

キーボードや支援技術のユーザー向けにフォーカス リングをアニメーション化したいのですが、そのためには、枠線がボタンから 5 ピクセル離れるようにアニメーション化しますが、これはボタンがアクティブでないときに限られます。これにより、押したときにフォーカス リングがボタンのサイズに縮小する効果が生まれます。

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

パスの色のコントラストを確保する

ライトとダークで色のコントラストを考慮する必要がある色の組み合わせは、少なくとも 4 つ(ボタン、送信ボタン、リセットボタン、無効ボタン)あります。ここでは VisBug を使用して、すべてのスコアを一度に検査して表示します。

見えないユーザーに対してアイコンを非表示にする

アイコンボタンを作成する際は、アイコンでボタンテキストを視覚的にサポートする必要があります。これは、視力喪失のあるユーザーにとってアイコンが重要でないことも意味します。幸いなことに、ブラウザにはスクリーン リーダー技術でアイテムを非表示にする方法があるため、視力を失っている人が装飾的なボタンの画像に煩わされることはありません。

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
ボタンのユーザー補助ツリーが表示されている Chrome DevTools。aria-hidden が true に設定されているため、ツリーはボタン画像を無視します。
ボタンのユーザー補助ツリーが表示されている Chrome DevTools。 aria-hidden が true に設定されているため、ツリーはボタン画像を無視します。

スタイル

次のセクションでは、まず、ボタンのアダプティブ スタイルを管理するためのカスタム プロパティ システムを作成します。カスタムプロパティで要素を選択し 外観をカスタマイズできます

適応型のカスタム プロパティ戦略

この GUI チャレンジで使用するカスタム プロパティ戦略は、カラーパターンの作成で使用するものと非常によく似ています。アダプティブ ライト / ダーク カラーシステムの場合、各テーマのカスタム プロパティがそれに応じて定義され、名前が付けられます。1 つのカスタム プロパティがテーマの現在の値を保持し、CSS プロパティに割り当てられます。後で 1 つのカスタム プロパティを別の値に更新して、ボタンのスタイルを更新できます。

button {
  --_bg-light: white;
  --_bg-dark: black;
  --_bg: var(--_bg-light);

  background-color: var(--_bg);
}

@media (prefers-color-scheme: dark) {
  button {
    --_bg: var(--_bg-dark);
  }
}

ライトモードとダークモードが宣言型でわかりやすい点が気に入っています。間接と抽象化は、--_bg カスタム プロパティにオフロードされます。現在は、これが唯一の「リアクティブ」プロパティです。--_bg-light--_bg-dark は静的です。また、ライトモードがデフォルトのテーマであり、ダークは条件付きでのみ適用されることもわかりました。

設計の整合性に向けた準備

共有セレクタ

次のセレクタは、さまざまな種類のボタンをすべてターゲットにするために使用されますが、最初は少し戸惑ってしまいます。:where() が使用されるため、ボタンのカスタマイズに特異性は必要ありません。多くの場合、ボタンは別のシナリオに合わせて調整されています。:where() セレクタにより、タスクが簡単になります。:where() 内では、::file-selector-button を含む各ボタンタイプが選択されます。これは :is() または :where() 内では使用できません

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  …
}

すべてのカスタム プロパティは、このセレクタ内でスコープ設定されます。では すべてのカスタムプロパティを 確認しましょうこのボタンでは多数のカスタム プロパティが使用されています。各グループを説明しながら、セクションの最後に、暗いモーションのコンテキストと軽減されたモーションのコンテキストを共有します。

ボタンのアクセント カラー

送信ボタンとアイコンは、明るめの色を表現するのに最適な場所です。

--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);

ボタンのテキストの色

ボタンのテキストの色は、白や黒ではなく、hsl() を使用して色相 210 を維持したまま、--_accent の暗めまたは明るくしたバージョンです。

--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);

ボタンの背景色

ボタンの背景は、ライトモードのボタンを除き、同じ hsl() パターンに従います。ライトモードのボタンは白に設定されているため、サーフェスはユーザーの近くまたは他のサーフェスの前に表示されます。

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

ボタンの背景を適切に配置

この背景色は、サーフェスを他のサーフェスの背後に表示するためのもので、ファイル入力の背景に役立ちます。

--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);

ボタンのパディング

ボタン内のテキストの周囲のスペースは、ch 単位(フォントサイズに対する相対的な長さ)を使用して設定されます。これは、大きなボタンで font-size をバンプアップするだけで、ボタンが比例して拡大縮小する場合に重要です。

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

ボタンの枠線

ファイル入力が他のボタンと一致するように、ボタンの枠線の半径はカスタム プロパティに隠されています。枠線の色は、確立されているアダプティブ カラーシステムに従います。

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

ボタンのカーソルを合わせた際のハイライト効果

これらのプロパティは、インタラクション時に遷移するためのサイズ プロパティを設定します。ハイライトの色は、アダプティブ カラーシステムに従います。これらの機能については後ほど説明しますが、最終的には box-shadow 効果に使用されます。

--_highlight-size: 0;

--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);

ボタンのテキストの影

各ボタンには、テキストに薄い影のスタイルが設定されています。これにより、テキストがボタンの上に配置され、読みやすくなり、洗練されたプレゼンテーションのレイヤーが追加されます。

--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);

ボタンアイコン

今回も、相対的な長さの ch 単位により、アイコンは 2 文字のサイズになります。これにより、ボタンのテキストに比例してアイコンを拡大縮小できます。アイコンの色は、アダプティブ カラーとテーマ内の色に --_accent-color に依存します。

--_icon-size: 2ch;
--_icon-color: var(--_accent);

ボタンの影

シャドウを明と暗に適切に適応させるには、色と不透明度の両方を変更する必要があります。ライトモードのシャドウは、繊細で、オーバーレイするサーフェスの色に合わせて着色されている場合に最適です。ダークモードのシャドウは、より暗いサーフェス色をオーバーレイできるように、より暗く、彩度を上げる必要があります。

--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);

--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);

色と強さの自動調整により、2 つの深度のシャドウを組み合わせることができます。

--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));

--_shadow-2: 
  0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
  0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));

さらに、ボタンの外観をわずかに 3D にするために、1px のボックス シャドウによって錯覚を作り出します。

--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);

ボタンの遷移

アダプティブ カラーのパターンに従い、デザイン システムのオプションを保持する 2 つの静的プロパティを作成します。

--_transition-motion-reduce: ;
--_transition-motion-ok:
  box-shadow 145ms ease,
  outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);

すべてのプロパティがセレクタに表示される

セレクタ内のすべてのカスタム プロパティ

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  --_accent-light: hsl(210 100% 40%);
  --_accent-dark: hsl(210 50% 70%);
  --_accent: var(--_accent-light);

--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);

--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);

--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);

--_padding-inline: 1.75ch; --_padding-block: .75ch;

--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);

--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);

--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);

--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));

--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;

--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);

--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }

デフォルト ボタンは、ライトモードとダークモードで並べて表示されます。

ダークモード適応

-light-dark の静的プロパティ パターンの値は、ダークモードのプロパティが設定されている場合に明確になります。

@media (prefers-color-scheme: dark) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_bg: var(--_bg-dark);
    --_text: var(--_text-dark);
    --_border: var(--_border-dark);
    --_accent: var(--_accent-dark);
    --_highlight: var(--_highlight-dark);
    --_input-well: var(--_input-well-dark);
    --_ink-shadow: var(--_ink-shadow-dark);
    --_shadow-depth: var(--_shadow-depth-dark);
    --_shadow-color: var(--_shadow-color-dark);
    --_shadow-strength: var(--_shadow-strength-dark);
  }
}

これらのカスタムボタンの利用者は、読みやすいだけでなく、基本的な小道具をユーザーの好みに適切に適応できる自信を持って使用できます。

モーション適応の軽減

この訪問ユーザーのモーションに問題がない場合は、--_transitionvar(--_transition-motion-ok) に割り当てます。

@media (prefers-reduced-motion: no-preference) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_transition: var(--_transition-motion-ok);
  }
}

共通のスタイル

ボタンと入力のフォントは、ページの他のフォントと一致するように inherit に設定する必要があります。設定されていない場合、ブラウザによってスタイルが設定されます。これは letter-spacing にも適用されます。line-height1.5 に設定すると、レター ボックスのサイズが設定され、テキストの上下に余白が確保されます。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  /* …CSS variables */

  font: inherit;
  letter-spacing: inherit;
  line-height: 1.5;
  border-radius: var(--_border-radius);
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

ボタンのスタイル設定

セレクタ調整

セレクタ input[type="file"] は入力のボタン部分ではありませんが、疑似要素 ::file-selector-button はそうであるため、リストから input[type="file"] を削除しました。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

カーソルとタップの調整

まず、カーソルを pointer スタイルに設定します。これにより、ボタンがマウスユーザーにインタラクティブであることを示せます。次に、touch-action: manipulation を追加して、クリックを待つ必要がなく、ダブルクリックの可能性をモニタリングできるようにして、ボタンが速く感じられるようにします。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  cursor: pointer;
  touch-action: manipulation;
}

色と枠線

次に、先ほど設定したアダプティブ カスタム プロパティの一部を使用して、フォントサイズ、背景、テキスト、枠線の色をカスタマイズします。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  font-size: var(--_size, 1rem);
  font-weight: 700;
  background: var(--_bg);
  color: var(--_text);
  border: 2px solid var(--_border);
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

ボタンにはいくつかの優れた手法が適用されています。text-shadow はライトとダークに合わせて調整し、背景の上にぴったり収まるボタンテキストの外観を作成します。box-shadow には 3 つのシャドウが割り当てられます。1 つ目の --_shadow-2 は、通常のボックス シャドウです。2 つ目の影は、ボタンが少し上がっているように見せるためのトリックです。最後のシャドウはホバー ハイライト用で、最初はサイズ 0 ですが、後でサイズが指定されて、ボタンから拡大するように移行されます。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  box-shadow: 
    var(--_shadow-2),
    var(--_shadow-depth),
    0 0 0 var(--_highlight-size) var(--_highlight)
  ;
  text-shadow: var(--_ink-shadow);
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

Layout

ボタンにフレックスボックス レイアウト、具体的にはコンテンツに適合する inline-flex レイアウトを設定しました。次に、テキストを中央に配置し、子を垂直方向と水平方向に中央に揃えます。これにより、アイコンやその他のボタン要素を適切に配置できます。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  display: inline-flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

間隔

ボタンの間隔については、gap を使用して兄弟姉妹が触れないようにし、パディングの論理プロパティを使用して、ボタンの間隔がすべてのテキスト レイアウトで機能するようにします。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  gap: 1ch;
  padding-block: var(--_padding-block);
  padding-inline: var(--_padding-inline);
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

タップとマウスの UX

次のセクションは主にモバイル デバイスのタッチユーザーを対象としています。1 つ目のプロパティ user-select はすべてのユーザーを対象としており、ボタンのテキストをハイライト表示するテキストを禁止します。タッチデバイスでは、ボタンをタップして長押しすると、オペレーティング システムによってボタンのテキストがハイライト表示されます。

通常、これは組み込みアプリのボタンに関するユーザー エクスペリエンスではないので、user-select を none に設定して無効にします。タップのハイライトの色(-webkit-tap-highlight-color)とオペレーティング システムのコンテキスト メニュー(-webkit-touch-callout)は、ウェブ中心のその他のボタン機能であり、一般的なボタンユーザーの期待に沿わないため、同様に削除しました。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

切り替え効果

適応型の --_transition 変数は、transition プロパティに割り当てられます。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  transition: var(--_transition);
}

カーソルを合わせたときに、ユーザーが積極的にボタンを押していないときに、シャドウのハイライトのサイズを調整して、ボタンの内側から拡大するように見えるフォーカスの外観を整えます。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
):where(:not(:active):hover) {
  --_highlight-size: .5rem;
}

フォーカス時に、ボタンからのフォーカス アウトライン オフセットを増やして、ボタン内から拡大するように見えるフォーカスの外観を整えます。

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

アイコン

アイコンを処理するため、このセレクタには、直接 SVG の子またはカスタム属性 data-icon を持つ要素用の :where() セレクタが追加されています。アイコンのサイズは、インラインとブロックの論理プロパティを使用して、カスタム プロパティで設定されます。ストロークの色が設定され、text-shadow に合わせて drop-shadow が設定されています。flex-shrink0 に設定されているため、アイコンはつぶれません。最後に、枠線付きアイコンを選択し、それらのスタイルを fill: noneround のラインキャップとライン結合で割り当てます。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
) > :where(svg, [data-icon]) {
  block-size: var(--_icon-size);
  inline-size: var(--_icon-size);
  stroke: var(--_icon-color);
  filter: drop-shadow(var(--_ink-shadow));

  flex-shrink: 0;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

送信ボタンのカスタマイズ

そこで、送信ボタンの外観をやや強調して、ボタンのテキスト色をアクセント カラーにすることで実現しました。

:where(
  [type="submit"], 
  form button:not([type],[disabled])
) {
  --_text: var(--_accent);
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

リセットボタンをカスタマイズする

私はリセットボタンに、破壊的動作についてユーザーに警告する警告標識を組み込みたいと考えていました。またライトモードのボタンのスタイルは ダークモードよりも赤のアクセントが多いものでしたカスタマイズは、適切なライトまたはダークの基本色を変更することで行います。ボタンでスタイルが更新されます。

:where([type="reset"]) {
  --_border-light: hsl(0 100% 83%);
  --_highlight-light: hsl(0 100% 89% / 20%);
  --_text-light: hsl(0 80% 50%);
  --_text-dark: hsl(0 100% 89%);
}

また、フォーカスの輪郭の色を赤のアクセントに合わせるのもよいと考えました。テキストの色は、濃い赤から薄い赤に適応します。枠線の色をキーワード currentColor と一致させます。

:where([type="reset"]):focus-visible {
  outline-color: currentColor;
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

無効になっているボタンをカスタマイズ

無効なボタンは、無効にしたボタンを下に収めようとするときに色のコントラストが弱くなり、アクティブに見えなくなることがよくあります。各カラーセットをテストし、合格することを確認し、DevTools または VisBug でスコアが合格するまで HSL の明度の値を調整しました。

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
)[disabled] {
  --_bg: none;
  --_text-light: hsl(210 7% 40%);
  --_text-dark: hsl(210 11% 71%);

  cursor: not-allowed;
  box-shadow: var(--_shadow-1);
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

ファイル入力ボタンのカスタマイズ

ファイル入力ボタンは、スパンとボタンのコンテナです。CSS では、入力コンテナとネストされたボタンのスタイルを微調整できますが、スパンのスタイルは設定できません。コンテナには max-inline-size が提供されるため、必要以上に大きくなりません。一方、inline-size: 100% を使用すると、コンテナをそれよりも小さくして収めることができます。背景色は、他のサーフェスよりも暗いアダプティブ カラーに設定されているため、ファイル選択ボタンの背後に表示されます。

:where(input[type="file"]) {
  inline-size: 100%;
  max-inline-size: max-content;
  background-color: var(--_input-well);
}

ファイル選択ボタンと入力タイプボタンには、他のボタンスタイルによって上書きされなかったブラウザ提供のスタイルを削除するために、appearance: none が指定されています。

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
  appearance: none;
}

最後に、ボタンの inline-end に余白を追加し、スパンテキストをボタンから離して、スペースを確保します。

:where(input[type="file"])::file-selector-button {
  margin-inline-end: var(--_padding-inline);
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

特別なダークモードの例外

メイン アクション ボタンの背景を暗くしてテキストのコントラストを高くし、外観を少し強調しました。

@media (prefers-color-scheme: dark) {
  :where(
    [type="submit"],
    [type="reset"],
    [disabled],
    form button:not([type="button"])
  ) {
    --_bg: var(--_input-well);
  }
}

上記のスタイルを適用した後のボタンを示すスクリーンショット

パターンの作成

今回は楽しさと実用性を考慮して、いくつかのバリアントを作成する方法を紹介します。1 つのバリアントは、プライマリ ボタンの外観と同様に、非常に鮮明です。別のバリアントが大きいです。最後のパターンは、グラデーションが施されたアイコンです。

鮮やかなボタン

このボタンのスタイルを実現するため、ベースとなる小道具を直接青色で上書きしました。これは手早く簡単にできましたが、アダプティブな小道具が削除され、ライトモードとダークモードのどちらでも同じように見えます。

.btn-custom {
  --_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
  --_border: hsl(228 89% 63%);
  --_text: hsl(228 89% 100%);
  --_ink-shadow: 0 1px 0 hsl(228 57% 50%);
  --_highlight: hsl(228 94% 67% / 20%);
}

カスタム ボタンはライトとダークで示されています。一般的なメイン アクション ボタンと同じく、鮮やかな青色です。

大きなボタン

このスタイルのボタンは、--_size カスタム プロパティを変更することで実現されます。パディングなどのスペース要素はこのサイズに比例し、新しいサイズに比例してスケーリングされます。

.btn-large {
  --_size: 1.5rem;
}

大きいボタンは、カスタム ボタンの横に約 150 倍大きく表示されます。

アイコンボタン

このアイコン効果は、ボタンのスタイルとは関係ありませんが、いくつかの CSS プロパティでそれを実現する方法と、インライン SVG 以外のアイコンをボタンがどの程度適切に処理できるかを示しています。

[data-icon="cloud"] {
  --icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;

  -webkit-mask: var(--icon-cloud);
  mask: var(--icon-cloud);
  background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}

アイコン付きのボタンが、ライトモードとダークモードで表示されます。

おわりに

私のやり方がわかったところで、どうしたらいいですか? 🙂?

多様なアプローチを活用し、ウェブでアプリをビルドするためのあらゆる方法を学びましょう。

デモを作成してツイートのリンクをお願いします。下のコミュニティ リミックス セクションに追加します。

コミュニティのリミックス

まだ何も表示されません。

リソース