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

色に適応し、レスポンシブで、ユーザー補助に対応した <button> コンポーネントを作成する方法の基本的な概要。

この投稿では、色に適応し、レスポンシブで、ユーザー補助に対応した <button> 要素を作成する方法について説明します。デモを試すソースを表示する

ボタンは、明るいテーマと暗いテーマの両方でキーボードとマウスで操作できます。

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

概要

対応ブラウザ

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

ソース

<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 チャレンジで使用されるカスタム プロパティ戦略は、カラーパターンの作成で使用される戦略と非常によく似ています。明るい色と暗い色の適応型システムの場合、テーマごとにカスタム プロパティが定義され、それに応じて名前が付けられます。次に、単一のカスタム プロパティを使用してテーマの現在の値を保持し、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() 内では、:is() または :where() 内で使用できない ::file-selector-button など、各ボタンタイプが選択されます。

: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() を使用して --_accent を暗くまたは明るくした色で、色相 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 変数は、遷移プロパティに割り当てられます。

: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 では、入力コンテナとネストされたボタンに少しだけスタイルを設定できますが、スパンは設定できません。コンテナには 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));
}

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

まとめ

私の方法をご覧になったところで、あなたならどうしますか?

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

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

コミュニティ リミックス

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

リソース