Créer un composant de bouton

Présentation de base de la création de composants <button> adaptatifs, réactifs et accessibles aux couleurs.

Dans ce post, je veux partager mes réflexions sur la façon de créer une un élément <button> responsif et accessible. Essayez la version de démonstration et visionnez la source

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> Les utilisateurs peuvent interagir avec les boutons via le clavier et la souris dans les thèmes clair et sombre.

Si vous préférez la vidéo, voici une version YouTube de cet article:

Présentation

Navigateurs pris en charge

  • Chrome: 1. <ph type="x-smartling-placeholder">
  • Edge: 12 <ph type="x-smartling-placeholder">
  • Firefox: 1. <ph type="x-smartling-placeholder">
  • Safari: 1. <ph type="x-smartling-placeholder">

Source

La <button> est conçu pour permettre l'interaction de l'utilisateur. Ses événements click se déclenchent depuis le clavier, la souris, l'écran tactile, les commandes vocales, etc. grâce à des règles intelligentes codes temporels. Il s'accompagne également avec des styles par défaut dans chaque navigateur, ce qui vous permet de les utiliser directement sans n'importe quelle personnalisation. Utilisez color-scheme pour l'activer aux boutons clair et sombre fournis par le navigateur.

Il existe également différents types de boutons, comme indiqué dans l'intégration de Codepen précédente. Un élément <button> sans type s'adaptent à la présence d'un <form>, en passant au type d'envoi.

<!-- 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">

Lors du défi GUI du mois, chaque bouton aura des styles qui l’aideront à différencier visuellement son intention. Réinitialiser boutons s'accompagnent d'avertissements de couleur, car ils sont destructeurs, puis envoyez-les boutons seront accompagnées d'un texte d'accentuation en bleu, qui seront donc un peu plus mises en avant que les autres .

<ph type="x-smartling-placeholder">
</ph> Aperçu de l&#39;ensemble final de tous les types de boutons, affiché dans un formulaire et non dans un formulaire, avec de jolis ajouts pour les boutons d&#39;icône et les boutons personnalisés. <ph type="x-smartling-placeholder">
</ph> Aperçu de l'ensemble final de tous les types de boutons, affiché dans un formulaire et non dans un formulaire avec de jolis ajouts pour les boutons d'icône et les boutons personnalisés
.

Les boutons ont également des pseudo-classes. à utiliser pour les styles. Ces classes fournissent des hooks CSS pour personnaliser sensation du bouton: :hover lorsqu'une souris passe sur le bouton, :active lorsqu'une souris ou sur le clavier, et :focus ou :focus-visible pour vous aider à styliser les technologies d'assistance.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
<ph type="x-smartling-placeholder">
</ph> Aperçu de l&#39;ensemble final de tous les types de boutons dans le thème sombre.
Aperçu de l'ensemble final de tous les types de boutons dans le thème sombre

Majoration

En plus des types de boutons fournis par la spécification HTML, j'ai ajouté un élément avec une icône et un bouton avec une classe personnalisée 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">

Ensuite, à des fins de test, chaque bouton est placé dans un formulaire. De cette façon, je peux m’assurer les styles sont mis à jour de manière appropriée pour le bouton par défaut, qui se comporte Envoyer. Je change aussi la stratégie d'icône : SVG intégré à SVG masqué, pour s'assurer que les deux fonctionnent de la même manière.

<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>

La matrice de combinaisons est assez écrasante à ce stade. Bouton "Entre" les types de données, les pseudo-classes et le fait d'être dans ou hors d'une forme, il existe plus de 20 combinaisons de boutons. C'est une bonne chose que le CSS nous aide à expliquer chacune clairement !

Accessibilité

Les éléments de bouton sont naturellement accessibles, mais il existe quelques améliorations.

Pointer et placer le curseur en même temps

J'aime regrouper :hover et :focus avec la fonction :is(). pseudo-sélecteur. Cela permet de s'assurer que mes interfaces tiennent toujours compte du clavier et technologies d'assistance.

button:is(:hover, :focus) {
  
}
<ph type="x-smartling-placeholder">
</ph>
. Essayez une démonstration !

Anneau de focus interactif

J'aime animer l'anneau de focus pour les utilisateurs de claviers et de technologies d'assistance. Je pour ce faire, animant le contour du bouton de 5 pixels, mais lorsque le bouton n'est pas actif. Cela crée un effet qui fait sonner l'anneau de mise au point pour revenir à la taille du bouton lorsque l'utilisateur appuie dessus.

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

Assurer un contraste des couleurs satisfaisant

Il existe au moins quatre combinaisons de couleurs différentes, claires et sombres, qui vous devez tenir compte du contraste des couleurs: bouton, bouton d'envoi, bouton de réinitialisation et . VisBug permet ici inspectent et affichent tous leurs scores en même temps:

Masquer les icônes des personnes qui ne peuvent pas voir

Lors de la création d'un bouton d'icône, celle-ci doit apporter un support visuel à l'icône texte du bouton. Cela signifie également que l'icône n'a aucune valeur pour une personne voyante. de perte de données. Heureusement, le navigateur permet de masquer des éléments pour le lecteur d'écran. pour que les personnes malvoyantes n'aient pas à se soucier des boutons décoratifs. images:

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
<ph type="x-smartling-placeholder">
</ph> Outils pour les développeurs Chrome affichant l&#39;arborescence d&#39;accessibilité du bouton L&#39;arborescence ignore l&#39;image du bouton, car la valeur aria-hidden est définie sur &quot;true&quot;.
Outils pour les développeurs Chrome affichant l'arborescence d'accessibilité du bouton L'arborescence ignore l'image du bouton, car aria-hidden est défini sur "true"

Styles

Dans cette section, je vais d'abord définir un système de propriétés personnalisées pour gérer les styles adaptatifs du bouton. Avec ces propriétés personnalisées, je peux commencer à sélectionner des éléments et personnaliser leur apparence.

Stratégie de propriétés personnalisée adaptative

La stratégie de propriété personnalisée utilisée dans ce défi de l'IUG est très semblable à celle-ci : utilisées pour créer un jeu de couleurs. Pour système de couleurs clair et sombre adaptatif, une propriété personnalisée pour chaque thème est défini et nommé en conséquence. Ensuite, une seule propriété personnalisée est utilisée pour contenir la valeur actuelle du thème et qui est attribuée à une propriété CSS. Plus tard, le single propriété personnalisée peut être remplacée par une valeur différente, puis mettre à jour le bouton du style.

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

Ce que j'aime, c'est que les thèmes clair et sombre soient déclaratifs et clairs. La l'indirection et l'abstraction sont déchargées dans la propriété personnalisée --_bg, qui est maintenant le seul outil « réactif » propriété ; --_bg-light et --_bg-dark sont statique. Il est également clair de lire que le thème clair est le thème par défaut et le mode sombre n'est appliqué que de manière conditionnelle.

Se préparer à la cohérence de conception

Sélecteur partagé

Le sélecteur suivant est utilisé pour cibler tous les différents types de boutons et est un peu écrasante au début. :where() correspond à la personnalisation du bouton ne nécessite donc aucune spécificité. Les boutons sont souvent adapté à d'autres scénarios, et le sélecteur :where() garantit que la tâche est très simple. Dans :where(), chaque type de bouton est sélectionné, y compris les boutons ::file-selector-button, qui ne peut pas être utilisés dans :is() ou :where().

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

Toutes les propriétés personnalisées seront définies dans ce sélecteur. Délai d'examen toutes les propriétés personnalisées. Dans ce cas, un certain nombre de propriétés personnalisées . Je vais décrire chaque groupe au fur et à mesure, puis partager les notions sombres et réduites les contextes de mouvement à la fin de cette section.

Couleur d'accentuation du bouton

Les boutons et les icônes d’envoi sont un excellent endroit pour ajouter une touche de couleur:

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

Couleur du texte du bouton

Le texte des boutons n'est pas blanc ou noir, mais dans une version plus sombre ou plus éclaircie. sur --_accent utilisant hsl() et en respectant la teinte 210:

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

Couleur de l'arrière-plan du bouton

L'arrière-plan des boutons suit le même schéma hsl(), sauf pour le thème clair des boutons : ceux-ci sont réglés en blanc, de sorte que leur surface les fait apparaître près du ou devant d'autres surfaces:

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

L'arrière-plan du bouton est correct

Cette couleur d'arrière-plan permet de faire apparaître une surface derrière d'autres surfaces, utile pour l'arrière-plan de l'entrée du fichier:

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

Marge intérieure du bouton

L'espacement autour du texte du bouton est effectué à l'aide des ch unité, une longueur relative par rapport à la taille de la police. Cela devient essentiel lorsqu'un grand nombre les boutons peuvent simplement faire monter la font-size et les échelles de boutons proportionnellement:

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

Bordure du bouton

L'arrondi de bordure du bouton est placé dans une propriété personnalisée afin que l'entrée du fichier puisse correspondent aux autres boutons. Les couleurs de bordure suivent la couleur adaptative établie système:

--_border-radius: .5ch;

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

Effet de mise en surbrillance du bouton au passage de la souris

Ces propriétés établissent une propriété de taille pour les transitions lors des interactions. la couleur de surlignage suit le système de couleurs adaptatives. Nous verrons comment ces plus loin dans cet article, mais elles seront utilisées pour box-shadow effet:

--_highlight-size: 0;

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

Ombre du texte du bouton

Chaque bouton a un style d'ombre de texte subtil. Cela permet au texte de se tenir au-dessus de le bouton, ce qui améliore la lisibilité et ajoute une jolie couche de présentation.

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

Icône de bouton

Les icônes ont la taille de deux caractères grâce à l'unité de longueur relative ch ce qui permettra à l'icône de s'adapter proportionnellement au texte du bouton. La La couleur de l'icône s'appuie sur --_accent-color pour s'adapter et se fondre dans le thème. couleur.

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

Ombre du bouton

Pour que les ombres s’adaptent correctement à la lumière et à l’obscurité, elles doivent toutes les deux décaler leur la couleur et l'opacité. Les ombres du thème clair sont plus belles lorsqu'elles sont subtiles et teintées vers la couleur de surface qu'elles superposent. Les ombres du thème sombre doivent être plus sombres et plus saturées afin qu’elles puissent superposer des couleurs de surface plus sombres.

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

Grâce aux couleurs et aux points forts qui s'adaptent, je peux assembler deux profondeurs d'ombre:

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

De plus, pour donner aux boutons un aspect légèrement 3D, une ombre de case 1px crée l'illusion:

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

Transitions de boutons

En suivant le modèle des couleurs adaptatives, je crée deux propriétés statiques contiennent les options du système de conception:

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

Toutes les propriétés réunies dans le sélecteur

Toutes les propriétés personnalisées d'un sélecteur

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

Les boutons par défaut s&#39;affichent avec les thèmes clair et sombre côte à côte.

Adaptations au thème sombre

La valeur du modèle de propriété statique -light et -dark devient claire lorsque les accessoires du thème sombre sont définis:

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

Non seulement cela est bien, mais les utilisateurs de ces boutons personnalisés peuvent utiliser le des accessoires nus en toute confiance qu'ils s'adapteront de manière appropriée aux préférences de l'utilisateur.

Adaptations en mouvement réduites

Si le mouvement est autorisé pour cet utilisateur visiteur, attribuez --_transition à var(--_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);
  }
}

Quelques styles en commun

La police des boutons et des entrées doit être définie sur inherit afin qu'elles correspondent à le reste des polices de la page. sinon le navigateur les applique. De plus, s'applique à letter-spacing. Si line-height est défini sur 1.5, la boîte aux lettres est appliquée. pour laisser de l'espace au texte au-dessus et en dessous:

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Appliquer un style aux boutons

Ajustement du sélecteur

Le sélecteur input[type="file"] n'est pas la partie bouton de l'entrée, le pseudo-élément ::file-selector-button, j'ai donc supprimé input[type="file"] dans la liste:

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

Ajustements du curseur et des commandes tactiles

J'applique d'abord le style pointer au curseur, ce qui permet au bouton d'indiquer aux utilisateurs de souris qu'il est interactif. J'ajoute ensuite touch-action: manipulation à faire en sorte que les clics n'aient pas besoin d'attendre et d'observer un double-clic potentiel. les boutons sont plus rapides:

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

Couleurs et bordures

Ensuite, je personnalise la taille de la police, l'arrière-plan, le texte et les couleurs de bordure, en utilisant des propriétés personnalisées adaptatives établies précédemment:

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Ombres

D'excellentes techniques sont appliquées aux boutons. La text-shadow correspond à s'adapte au clair et à l'obscurité, ce qui crée une apparence subtile et agréable du bouton sur l'arrière-plan. Pour le box-shadow, trois ombres sont attribuées. La première, --_shadow-2, est une ombre de boîte standard. La deuxième ombre est une technique qui donne l'impression que le bouton est un peu bizarre. La dernière ombre concerne la mise en surbrillance à une taille de 0, mais une taille lui sera attribuée ultérieurement et transformée pour qu'elle apparaisse se développer grâce au bouton.

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Mise en page

J'ai choisi une mise en page flexbox pour le bouton, en particulier une mise en page inline-flex adaptée à son contenu. puis je centre le texte, et alignez verticalement et horizontalement les enfants sur la centre de contrôle. Cela aidera les icônes et autres de boutons pour s'aligner correctement.

: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;
}

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Espacement

Pour l'espacement des boutons, j'ai utilisé gap pour garder les frères et sœurs de toucher et de logiquement pour la marge intérieure. l'espacement fonctionne pour toutes les mises en page de texte.

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Expérience utilisateur tactile et avec la souris

La section suivante s'adresse principalement aux utilisateurs tactiles sur des appareils mobiles. Le premier , user-select, s'adresse à tous les utilisateurs. cela empêche le texte de mettre en surbrillance le texte du bouton. Il s'agit principalement visible sur les appareils tactiles lorsque l'utilisateur appuie sur un bouton et le maintient enfoncé, et que le système d'exploitation met en surbrillance le texte du bouton.

J'ai trouvé que ce n'était généralement pas l'expérience utilisateur avec les boutons des applications. Je désactive donc cette option en définissant user-select sur "aucune". Appuyez sur les couleurs de surlignage (-webkit-tap-highlight-color) et les menus contextuels du système d'exploitation (-webkit-touch-callout) Il existe d'autres fonctionnalités de boutons très axées sur le Web qui ne correspondent pas aux des attentes des utilisateurs, je les supprime donc également.

: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;
}

Transitions

La variable adaptative --_transition est attribuée au transition:

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

  transition: var(--_transition);
}

Ajuster la mise en surbrillance de l'ombre lorsque l'utilisateur n'appuie pas activement sur ce point pour lui donner une belle apparence d'attention qui semble s'agrandir au sein bouton:

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

Au moment de la mise au point, augmentez le décalage du contour de la mise au point par rapport au bouton une belle apparence de mise au point qui semble s'agrandir à l'intérieur du bouton:

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

Icônes

Pour gérer les icônes, le sélecteur dispose d'un sélecteur :where() supplémentaire pour les images SVG directes. enfants ou éléments comportant l'attribut personnalisé data-icon. La taille de l'icône est définie avec la propriété personnalisée à l'aide de propriétés logiques intégrées et de bloc. Couleur du trait est définie, ainsi qu'une drop-shadow pour correspondre à text-shadow. flex-shrink étant défini sur 0, l'icône n'est jamais écrasé. Enfin, je sélectionne des icônes lignées et j'attribue ces styles ici avec Extrémités de ligne et jointures de fill: none et round:

: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;
}

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Personnalisation des boutons "Envoyer"

Je voulais que les boutons Envoyer aient une apparence légèrement mise en avant et j’ai atteint en faisant de la couleur du texte des boutons la couleur d'accentuation:

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Personnaliser les boutons de réinitialisation

Je voulais que les boutons de réinitialisation aient des signes d'avertissement intégrés pour alerter les utilisateurs de leur comportement potentiellement destructeur. J'ai aussi choisi de styliser le thème clair avec plus d'accentuation de rouge que le thème sombre. La personnalisation se fait par change la couleur sous-jacente claire ou sombre appropriée, et le bouton modifiez le style:

: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%);
}

J'ai aussi pensé qu'il serait bon que la couleur du contour d'une mise au point corresponde à l'accent rouge. La couleur du texte adapte le rouge foncé au rouge clair. je définis la couleur du contour faites correspondre ce mot clé currentColor:

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Personnaliser les boutons désactivés

Il est trop courant que les boutons désactivés aient un faible contraste de couleurs pendant le essayer de supprimer le bouton désactivé pour qu'il soit moins actif. J'ai testé chacun jeu de couleurs et s'assurer qu'elles étaient validées, en encourageant la valeur de luminosité HSL jusqu'à ce que transmis dans DevTools ou VisBug.

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Personnalisation des boutons d'entrée de fichier

Le bouton d'entrée de fichier est un conteneur pour un segment et un bouton. Le CSS peut effectuer les actions suivantes : Appliquez un peu de style au conteneur d'entrée et au bouton imbriqué, mais pas le segment. Le conteneur reçoit la valeur max-inline-size. Il ne dépassera donc pas nécessaire, tandis que inline-size: 100% se rétrécit et s'adapte conteneurs plus petits qu'elles ne l'est. La couleur d'arrière-plan est définie sur une couleur adaptative. plus sombre que les autres surfaces, il regarde donc derrière le bouton de sélection de fichier.

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

Le bouton de sélection de fichier et les boutons de type de saisie appearance: none pour supprimer tous les styles fournis par le navigateur qui n'étaient pas remplacé par les autres styles de bouton.

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

Enfin, une marge est ajoutée à l'élément inline-end du bouton pour pousser le texte du segment. à l'écart du bouton, ce qui crée de l'espace.

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Exceptions liées au thème sombre

J'ai donné aux principaux boutons d'action un arrière-plan plus sombre pour un contraste plus élevé du texte, ce qui leur donne une apparence légèrement plus mise en avant.

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

Capture d&#39;écran montrant les boutons après l&#39;application des styles précédents.

Créer des variantes

Pour m'amuser et parce que c'est pratique, j'ai choisi de montrer comment créer . Une variante est très colorée, similaire à la façon dont les boutons principaux un style. Une autre variante est de grande taille. La dernière variante présente une icône avec un dégradé.

Bouton coloré

Pour obtenir ce style de bouton, j'ai remplacé les accessoires de la base par du bleu couleurs. Même si l'opération a été simple et rapide, les accessoires et l'apparence adaptatifs ont été supprimés. de la même manière dans les thèmes clair et sombre.

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

Le bouton personnalisé s&#39;affiche en clair et en mode sombre. Il est d&#39;un bleu éclatant, comme les principaux boutons d&#39;action.

Bouton de grande taille

Ce style de bouton est obtenu en modifiant la propriété personnalisée --_size. Les marges intérieures et les autres éléments d'espace sont définis par rapport à cette taille, la mise à l'échelle le long proportionnellement à la nouvelle taille.

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

Le grand bouton est affiché à côté du bouton personnalisé. Il est environ 150 fois plus grand.

Bouton en forme d'icône

Cet effet d'icône n'a rien à voir avec nos styles de boutons, mais il en a vous montrer comment y parvenir avec quelques propriétés CSS gère les icônes qui ne sont pas des SVG intégrés.

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

Un bouton avec une icône est affiché dans les thèmes clair et sombre.

Conclusion

Maintenant que vous savez comment j'ai fait, comment feriez-vous ? 😃

Diversifiez nos approches et découvrons toutes les manières de créer des applications sur le Web.

Créer une démonstration, me envoyer des tweets et je l'ajouterai à la section des remix de la communauté ci-dessous.

Remix de la communauté

Rien à afficher pour le moment.

Ressources