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

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

この記事では、色適応型でレスポンシブな、アクセシビリティに配慮した <button> 要素を構築する方法について説明します。デモを試すソースを表示する

ライトモードとダークモードで、キーボードとマウスを使用してボタンを操作します。

動画で確認したい場合は、こちらの YouTube 版の投稿をご覧ください。

概要

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

<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 を使用すると、それぞれの要素を明確に表現できます。

ユーザー補助

ボタン要素は本来アクセス可能ですが、一般的な拡張機能がいくつかあります。

ホバーとフォーカスを同時に行う

:is() 関数型疑似セレクタを使用して、:hover:focus をグループ化します。これにより、インターフェースで常にキーボードと支援技術のスタイルが考慮されるようになります。

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 チャレンジで使用されているカスタム プロパティ戦略は、配色を構築するで使用されているものと非常によく似ています。アダプティブ ライトカラー システムとダークカラー システムでは、各テーマのカスタム プロパティが定義され、それに応じて名前が付けられます。次に、単一のカスタム プロパティを使用してテーマの現在の値を保持し、CSS プロパティに割り当てます。その後、単一のカスタム プロパティを別の値に更新して、ボタンのスタイルを更新できます。

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 を含む各ボタンタイプが選択されています。::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);

ボタンのテキストの色

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

--_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%));

さらに、ボタンを少し立体的に見せるために、1px box-shadow で錯覚を生み出します。

--_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 つのシャドウが割り当てられます。最初の --_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);
}

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

レイアウト

ボタンに flexbox レイアウト(具体的には、コンテンツに収まる 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

次のセクションは、主にモバイル デバイスのタッチ操作ユーザーを対象としています。最初のプロパティ 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);
}

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

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

ファイル入力ボタンは、span とボタンのコンテナです。CSS では、入力コンテナとネストされたボタンのスタイルを少し変更できますが、span は変更できません。コンテナには 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 に余白を追加して、span テキストをボタンから離し、スペースを作成します。

: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 つのバリエーションは、プライマリ ボタンによく見られるような、非常に鮮やかな色です。別のバリエーションは large です。最後のバリエーションには、グラデーションで塗りつぶされたアイコンがあります。

鮮やかなボタン

このボタンのスタイルを実現するために、ベースのプロパティを青色で直接オーバーライドしました。この方法は手軽ですが、アダプティブ プロパティが削除され、ライトモードとダークモードの両方で同じように表示されます。

.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));
}

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

まとめ

私がどのように行ったかをご理解いただけたかと思います。では、あなたならどのようにしますか?🙂

アプローチを多様化し、ウェブで構築するすべての方法を学びましょう。

デモを作成して、ツイートでリンクを送信してください。下のコミュニティ リミックス セクションに追加します。

コミュニティ リミックス

表示する項目はありません。

リソース