Présentation de base sur la création de composants <button>
adaptatifs, responsifs et accessibles aux couleurs.
Dans cet article, je souhaite partager mes réflexions sur la création d'un élément <button>
adaptatif, adaptatif et accessible aux couleurs.
Essayez la démonstration et consultez la source.
Si vous préférez la vidéo, voici une version YouTube de ce post:
Présentation
L'élément <button>
est conçu pour les interactions utilisateur. Son événement click
se déclenche au clavier, à la souris, au toucher, à la voix, etc., avec des règles intelligentes sur la durée. Il est également fourni avec des styles par défaut dans chaque navigateur, afin que vous puissiez les utiliser directement sans aucune personnalisation. Utilisez color-scheme
pour activer également les boutons clair et sombre fournis par le navigateur.
Il existe également différents types de boutons, chacun illustré dans le codepen précédent. Une <button>
sans type s'adapte pour se trouver dans un <form>
, en changeant 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">
Dans le défi de l'interface graphique de ce mois-ci, chaque bouton sera associé à des styles pour aider à différencier visuellement son intention. Les boutons de réinitialisation auront des couleurs d'avertissement car ils sont destructeurs, et les boutons d'envoi auront un texte d'accentuation bleu, de sorte qu'ils apparaissent un peu plus mis en avant que les boutons standards.
Les boutons possèdent également des pseudo-classes que le CSS peut utiliser pour définir les styles. Ces classes fournissent des hooks CSS pour personnaliser l'aspect du bouton: :hover
pour les cas où une souris passe au-dessus du bouton, :active
lorsque l'utilisateur appuie sur une souris ou un clavier, et :focus
ou :focus-visible
pour faciliter l'application d'un style de technologie d'assistance.
button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Markup
En plus des types de boutons fournis par la spécification HTML, j'ai ajouté un bouton 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é à l'intérieur d'un formulaire. De cette façon, je peux m'assurer que les styles sont correctement mis à jour pour le bouton par défaut, qui se comporte comme un bouton d'envoi. Je change également la stratégie d'icônes, du SVG intégré au SVG masqué, pour m'assurer que les deux fonctionnent aussi bien.
<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. Il existe plus de 20 combinaisons de boutons entre les types de boutons, les pseudo-classes et l'intégration ou la déconnexion d'un formulaire. C'est une bonne chose que le CSS peut nous aider à formuler chacun d'eux clairement.
Accessibilité
Les éléments de bouton sont accessibles naturellement, mais il existe quelques améliorations courantes.
Pointer et effectuer la mise au point ensemble
J'aime regrouper :hover
et :focus
avec le pseudo-sélecteur fonctionnel :is()
. Cela permet de s'assurer que mes interfaces tiennent toujours compte
des styles de clavier et de technologie d'assistance.
button:is(:hover, :focus) {
…
}
Anneau de mise au point interactif
J'aime animer l'anneau de mise au point pour les utilisateurs de clavier et de technologies d'assistance. Pour ce faire, j'anime le contour de 5 pixels, mais seulement lorsque le bouton n'est pas actif. Cela crée un effet qui fait que l'anneau de sélection se réduit à la taille du bouton lorsqu'il est enfoncé.
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
Garantir un contraste des couleurs correct
Au moins quatre combinaisons de couleurs différentes pour clair et sombre doivent tenir compte du contraste des couleurs: bouton, bouton d'envoi, bouton de réinitialisation et bouton désactivé. VisBug permet d'inspecter et d'afficher tous leurs scores en même temps:
Masquage des icônes pour les personnes qui ne peuvent pas voir
Lors de la création d'un bouton d'icône, l'icône doit fournir un support visuel au texte du bouton. Cela signifie également que l'icône n'est pas utile aux personnes souffrant d'une perte de vue. Heureusement, le navigateur permet de masquer des éléments pour la technologie de lecture d'écran afin que les personnes malvoyantes ne soient pas dérangées par des images de boutons décoratifs:
<button>
<svg … aria-hidden="true">...</svg>
Icon Button
</button>
Styles
Dans la section suivante, nous commençons par établir un système de propriétés personnalisé pour gérer les styles adaptatifs du bouton. Je peux commencer à sélectionner des éléments et à personnaliser leur apparence.
Stratégie de propriétés personnalisées adaptatives
La stratégie de propriété personnalisée utilisée dans ce défi de l'IUG est très semblable à celle utilisée pour créer un jeu de couleurs. Pour un système de couleurs clair et sombre adaptatif, une propriété personnalisée est définie et nommée en conséquence pour chaque thème. Une seule propriété personnalisée est ensuite utilisée pour contenir la valeur actuelle du thème et est attribuée à une propriété CSS. Par la suite, la propriété personnalisée unique pourra être mise à jour avec une valeur différente, puis le style du bouton sera mis à jour.
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 sont déclaratifs et clairs. L'indirection et l'abstraction sont déchargées dans la propriété personnalisée --_bg
, qui est désormais la seule propriété "réactive". --_bg-light
et --_bg-dark
sont statiques. Il est également clair que le thème clair est le thème par défaut et que l'option sombre n'est appliquée que de manière conditionnelle.
Préparer la cohérence de la conception
Sélecteur partagé
Le sélecteur suivant permet de cibler tous les différents types de boutons. Au premier abord, il est un peu trop compliqué. :where()
est utilisé. La personnalisation du bouton ne nécessite donc aucune spécificité. Les boutons sont souvent adaptés à d'autres scénarios, et le sélecteur :where()
garantit la simplicité de la tâche. Dans :where()
, chaque type de bouton est sélectionné, y compris ::file-selector-button
, qui ne peut pas être utilisé 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 limitées dans ce sélecteur. Passons en revue toutes les propriétés personnalisées. De nombreuses propriétés personnalisées sont utilisées pour ce bouton. Je vais décrire chaque groupe au fur et à mesure, puis partager les contextes de mouvement sombre et réduit à la fin de la section.
Couleur d'accentuation du bouton
Les boutons et les icônes Envoyer sont parfaits 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
Les couleurs du texte des boutons ne sont pas le blanc ni le noir. Ce sont des versions sombres ou éclaircies de --_accent
qui utilisent hsl()
et qui s'appliquent à 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
Les arrière-plans de bouton suivent le même schéma hsl()
, à l'exception des boutons du thème clair. Ils sont définis en blanc afin que leur surface les fasse apparaître à proximité de l'utilisateur ou devant d'autres surfaces:
--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);
Arrière-plan du bouton réussi
Cette couleur d'arrière-plan permet de faire apparaître une surface derrière d'autres surfaces, ce qui est 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);
Rembourrage des boutons
L'espacement autour du texte du bouton est effectué à l'aide de l'unité ch
, une longueur relative par rapport à la taille de la police. Cela devient essentiel lorsque les gros boutons peuvent simplement augmenter la font-size
et que le bouton s'ajuste proportionnellement:
--_padding-inline: 1.75ch;
--_padding-block: .75ch;
Bordure du bouton
L'arrondi de la bordure du bouton est placé dans une propriété personnalisée afin que l'entrée du fichier puisse correspondre aux autres boutons. Les couleurs de bordure suivent le système de couleurs adaptatif établi:
--_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 lors du survol
Ces propriétés définissent une propriété de taille pour la transition en cas d'interaction. La couleur de surlignage suit le système de couleurs adaptatif. Nous verrons comment ces éléments interagissent plus loin dans cet article, mais ils sont au final utilisés pour un effet box-shadow
:
--_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 présente un style d'ombre de texte subtil. Cela permet au texte de se poser sur le bouton, ce qui améliore la lisibilité et ajoute une belle 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
encore une fois, ce qui aidera l'icône à s'ajuster proportionnellement au texte du bouton. La couleur de l'icône s'appuie sur la --_accent-color
pour une couleur adaptative et intégrée au thème.
--_icon-size: 2ch;
--_icon-color: var(--_accent);
Ombre du bouton
Pour que les ombres s'adaptent correctement à la lumière et au noir, elles doivent à la fois modifier leur couleur et leur opacité. Les ombres du thème clair sont idéales lorsqu'elles sont subtiles et teintées vers la couleur de la surface qu'elles superposent. Les ombres du thème sombre doivent être plus sombres et plus saturées pour pouvoir 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 intensités adaptatives, je peux obtenir 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 carrée 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 pour contenir 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
: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); }
Adaptations avec thème sombre
La valeur du modèle d'accessoires statiques -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 se lit bien, mais les consommateurs de ces boutons personnalisés peuvent utiliser les accessoires simples en étant sûr qu'ils s'adapteront de manière appropriée aux préférences de l'utilisateur.
Adaptations de mouvement réduites
Si le mouvement convient à 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 partagés
La police des boutons et des entrées doit être définie sur inherit
afin qu'elles correspondent aux autres polices de la page. Sinon, elles seront stylisées par le navigateur. Cela s'applique également à letter-spacing
. Si vous définissez line-height
sur 1.5
, la taille de la zone aux lettres est définie de manière à laisser un espace au-dessus et en dessous du texte:
: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);
}
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, contrairement au pseudo-élément ::file-selector-button
. J'ai donc supprimé input[type="file"]
de la liste:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
}
Réglages du curseur et des commandes tactiles
Tout d'abord, j'applique le style de curseur pointer
au bouton, ce qui permet au bouton d'indiquer aux utilisateurs de souris qu'il est interactif. Ensuite, j'ajoute touch-action: manipulation
pour éviter que les clics n'aient à attendre et pour observer un potentiel double-clic, ce qui rend les boutons 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 à l'aide de certaines 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);
}
Ombres
D'excellentes techniques ont été appliquées aux boutons. Le text-shadow
s'adapte à la lumière et au sombre, ce qui crée une apparence subtile agréable du texte du bouton bien placé au-dessus de l'arrière-plan. Pour box-shadow
, trois ombres sont attribuées. La première, --_shadow-2
, est une ombre de rectangle standard.
La deuxième ombre est une astuce à l'œil qui fait que le bouton semble légèrement plié. La dernière ombre correspond à la mise en surbrillance du passage de la souris, initialement avec une taille de 0, mais une taille lui sera attribuée par la suite et une transition sera effectuée de sorte qu'elle semble grandir à partir du 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);
}
Mise en page
J'ai défini une mise en page flexbox pour le bouton, en particulier une mise en page inline-flex
adaptée à son contenu. Centrez ensuite le texte, et alignez les enfants verticalement et horizontalement au centre. Cela aidera les icônes et les autres
éléments de bouton à 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;
}
Espacement
Pour l'espacement des boutons, j'ai utilisé gap
pour empêcher les frères d'appuyer sur l'écran et des propriétés logiques pour la marge intérieure afin que l'espacement des boutons 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);
}
Expérience utilisateur tactile et de la souris
La section suivante s'adresse principalement aux utilisateurs de l'écran tactile sur les appareils mobiles. La première propriété, user-select
, s'adresse à tous les utilisateurs. Elle empêche la mise en surbrillance du texte du bouton. Cela est principalement visible sur les appareils tactiles lorsqu'un utilisateur appuie de manière prolongée sur un bouton et que le système d'exploitation met en surbrillance le texte du bouton.
Je trouve que ce n'est généralement pas l'expérience utilisateur avec les boutons dans les applications intégrées. Je la désactive donc en définissant user-select
sur "Aucun". Les couleurs de mise en surbrillance (-webkit-tap-highlight-color
) et les menus contextuels du système d'exploitation (-webkit-touch-callout
) sont d'autres fonctionnalités très axées sur le Web qui ne correspondent pas aux attentes générales 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 à la propriété de transition:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
transition: var(--_transition);
}
Lors du survol, alors que l'utilisateur n'appuie pas activement, ajustez la taille de la mise en surbrillance des ombres pour lui donner une belle apparence qui semble grandir à partir du bouton:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
):where(:not(:active):hover) {
--_highlight-size: .5rem;
}
Lors de la mise au point, augmentez le décalage des contours de la mise au point à partir du bouton, en lui donnant également une belle apparence qui semble se développer à partir 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()
ajouté pour les enfants SVG directs ou les éléments avec l'attribut personnalisé data-icon
. La taille de l'icône est définie avec la propriété personnalisée à l'aide des propriétés logiques intégrées et de bloc. La couleur du trait est définie, ainsi qu'un élément drop-shadow
correspondant à l'élément text-shadow
. flex-shrink
étant défini sur 0
, l'icône n'est jamais écrasée. Enfin, je sélectionne des icônes lignées et j'attribue ces styles ici avec des limites de ligne et des jointures de ligne 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;
}
Personnalisation des boutons d'envoi
Je voulais que les boutons d'envoi aient une apparence légèrement promue. J'ai obtenu ce résultat en faisant de la couleur du texte des boutons la couleur d'accentuation:
:where(
[type="submit"],
form button:not([type],[disabled])
) {
--_text: var(--_accent);
}
Personnaliser les boutons de réinitialisation
Je voulais que les boutons de réinitialisation intègrent des panneaux d'avertissement pour alerter les utilisateurs de leur comportement potentiellement destructeur. J'ai également choisi de styliser le bouton du thème clair avec plus de touches de rouge que le thème sombre. La personnalisation se fait en modifiant la couleur claire ou sombre appropriée, et le bouton met à jour 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 également pensé qu'il serait intéressant que la couleur du contour de la mise au point corresponde à l'accentuation du rouge. La couleur du texte adapte un rouge foncé à un rouge clair. La couleur du contour correspond à celle du mot clé currentColor
:
:where([type="reset"]):focus-visible {
outline-color: currentColor;
}
Personnaliser les boutons désactivés
Il est trop courant que les boutons désactivés présentent un faible contraste des couleurs lorsque l'utilisateur essaie de le supprimer, ce qui le rend moins actif. J'ai testé chaque jeu de couleurs et je me suis assuré qu'ils réussissaient, en encourageant la valeur de luminosité HSL jusqu'à ce que le score soit transmis dans les outils de développement ou dans 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);
}
Personnalisation des boutons de saisie de fichier
Le bouton d'entrée de fichier est un conteneur pour un segment et un bouton. CSS est capable de styliser un peu le conteneur d'entrée ainsi que le bouton imbriqué, mais pas l'intervalle. Le conteneur reçoit max-inline-size
afin qu'il ne devienne pas plus grand que nécessaire, tandis que inline-size: 100%
s'autorise à réduire et à ajuster des conteneurs plus petits qu'il ne l'est. La couleur d'arrière-plan est définie sur une couleur adaptative plus sombre que les autres surfaces. Elle se trouve 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 du sélecteur de fichier et les boutons du type d'entrée disposent de appearance: none
pour supprimer tous les styles fournis par le navigateur qui n'ont pas été écrasés 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 éloigner le texte du segment du bouton, ce qui crée de l'espace.
:where(input[type="file"])::file-selector-button {
margin-inline-end: var(--_padding-inline);
}
Exceptions spéciales liées au thème sombre
J'ai choisi un arrière-plan plus sombre pour les principaux boutons d'action afin d'accentuer le contraste du texte, afin de leur donner 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);
}
}
Créer des variantes
Pour le plaisir et pour des raisons pratiques, j'ai choisi de montrer comment créer quelques variantes. Une variante est très colorée, semblable à l'apparence souvent des boutons principaux. Une autre variante est "grande". 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 base directement par des couleurs bleues. Bien que cette méthode soit rapide et facile, elle supprime les accessoires adaptatifs et a le même aspect 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%);
}
Grand bouton
Ce style de bouton est obtenu en modifiant la propriété personnalisée --_size
.
La marge intérieure et les autres éléments d'espace sont relatifs à cette taille et sont ajustés proportionnellement à la nouvelle taille.
.btn-large {
--_size: 1.5rem;
}
Bouton d'icône
Cet effet d'icône n'a rien à voir avec nos styles de boutons, mais il montre comment y parvenir avec seulement quelques propriétés CSS, et comment le bouton gère les icônes qui ne sont pas au format SVG intégré.
[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));
}
Conclusion
Maintenant que vous savez comment je l'ai fait, comment le feriez-vous‽ 😃 ?
Diversissons nos approches et apprenons toutes les façons de créer sur le Web.
Créez une démo, cliquez sur les liens tweet me, et je l'ajouterai à la section "Remix" de la communauté ci-dessous.
Remix de la communauté
Rien à afficher pour le moment.
Ressources
- Code source sur GitHub