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

色に適応し、レスポンシブで、ユーザー補助に対応した <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() 内で、各ボタンタイプが選択されます。その中の ::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 {
  
}

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

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

[Submit] ボタンと [Submit] ボタンとアイコンは、ポップな色をするのに最適な場所です。

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

さらに、ボタンに少し 3D の外観を与えるために、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));
}

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

まとめ

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

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

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

コミュニティ リミックス

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

リソース