Créer un composant de bouton d'action flottant (FAB)

Présentation de base sur la création de composants de bouton d'action flottant adaptatifs aux couleurs, responsifs et accessibles.

Dans cet article, je vais vous expliquer comment créer des composants de bouton d'action flottant adaptatifs aux couleurs, responsifs et accessibles. Essayez la démonstration et consultez la source.

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

Présentation

Les boutons d'action flottants sont plus courants sur mobile que sur ordinateur, mais ils sont présents dans les deux cas. Ils gardent les actions principales à l'écran, ce qui les rend pratiques et omniprésents. Ce style d'expérience utilisateur a été popularisé par Material UI. Vous trouverez les suggestions d'utilisation et de placement sur cette page.

Éléments et styles

Le code HTML de ces commandes comprend un élément de conteneur et un ensemble d'un ou plusieurs boutons. Le conteneur positionne les boutons d'action flottants dans la fenêtre d'affichage et gère un espace entre les boutons. Les boutons peuvent être mini ou par défaut, ce qui offre une belle variété entre les actions principales et secondaires.

Conteneur du bouton d'action flottant

Cet élément peut être un <div> standard, mais faisons un geste pour nos utilisateurs non voyants et ajoutons-lui des attributs utiles pour expliquer l'objectif et le contenu de ce conteneur.

Balisage des boutons d'action flottants

Commencez par une classe .fabs pour que CSS se connecte au style, puis ajoutez role="group" et aria-label pour qu'il ne s'agisse pas d'un simple conteneur générique, mais d'un nom et d'un objectif précis.

<div class="fabs" role="group" aria-label="Floating action buttons">
  <!-- buttons will go here -->
</div>

Style des boutons d'action flottants

Pour que les boutons d'action flottants soient pratiques, ils restent toujours dans la fenêtre d'affichage. Il s'agit d'un excellent cas d'utilisation pour la position fixed. Dans cette position de vue, j'ai choisi d'utiliser inset-block et inset-inline afin que la position complète le mode de document de l'utilisateur, comme de droite à gauche ou de gauche à droite. Les propriétés personnalisées permettent également d'éviter les répétitions et de garantir une distance égale par rapport aux bords inférieur et latéral du viewport :

.fabs {
  --_viewport-margin: 2.5vmin;

  position: fixed;
  z-index: var(--layer-1);

  inset-block: auto var(--_viewport-margin);
  inset-inline: auto var(--_viewport-margin);
}

Je donne ensuite à l'affichage du conteneur flex et je modifie son orientation de mise en page en column-reverse. Les enfants sont alors empilés les uns sur les autres (colonne) et leur ordre visuel est inversé. Cela a pour effet de faire du premier élément sélectionnable l'élément du bas au lieu du haut, qui est l'endroit où le focus se trouve normalement dans le document HTML. Inverser l'ordre visuel unit l'expérience des personnes voyantes et des utilisateurs de claviers, car le style de l'action principale plus grand que les mini-boutons indique aux utilisateurs voyants qu'il s'agit d'une action principale, et les utilisateurs du clavier la sélectionnent comme premier élément de la source.

Deux boutons d&#39;action flottant sont affichés, avec les outils de développement en superposition sur la mise en page sous forme de grille. Indique l&#39;espace entre eux à l&#39;aide d&#39;un motif rayé, ainsi que leur hauteur et leur largeur calculées.

.fabs {
  

  display: flex;
  flex-direction: column-reverse;
  place-items: center;
  gap: var(--_viewport-margin);
}

Le centrage est géré avec place-items, et gap ajoute de l'espace entre les boutons FAB placés dans le conteneur.

Boutons d'action flottants

Il est temps de styliser certains boutons pour qu'ils semblent flotter au-dessus de tout.

Bouton d'action flottant par défaut

Le premier bouton pour appliquer un style est le bouton par défaut. Il servira de base à tous les boutons de bouton d'action flottant. Nous créerons plus tard une variante qui offre une apparence alternative tout en modifiant le moins possible ces styles de base.

Balisage du bouton d'action flottant

L'élément <button> est la bonne réponse. Nous allons commencer par cela comme base, car il offre une excellente expérience utilisateur avec la souris, l'écran tactile et le clavier. L'aspect le plus crucial de ce balisage consiste à masquer l'icône aux utilisateurs de lecteurs d'écran avec aria-hidden="true" et à ajouter le texte de libellé nécessaire au balisage <button> lui-même. Dans ces cas, lorsque j'ajoute des étiquettes, j'aime également ajouter un title afin que les utilisateurs de souris puissent obtenir des informations sur ce que l'icône espère communiquer.

<button data-icon="plus" class="fab" title="Add new action" aria-label="Add new action">
  <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>

Style du bouton d'action flottant

Commençons par transformer le bouton en bouton rond avec une bordure et une ombre prononcées, car ce sont les premières caractéristiques qui le définissent :

.fab {
  --_size: 2rem;

  padding: calc(var(--_size) / 2);
  border-radius: var(--radius-round);
  aspect-ratio: 1;
  box-shadow: var(--shadow-4);
}

Ajoutons ensuite de la couleur. Nous allons utiliser une stratégie que nous avons déjà utilisée dans les défis d'interface utilisateur. Créez un ensemble de propriétés personnalisées clairement nommé qui contient statiquement les couleurs claires et sombres, puis une propriété personnalisée adaptative qui sera définie sur les variables claires ou sombres en fonction des préférences système de l'utilisateur pour les couleurs:

.fab {
  

  /* light button and button hover */
  --_light-bg: var(--pink-6);
  --_light-bg-hover: var(--pink-7);

  /* dark button and button hover */
  --_dark-bg: var(--pink-4);
  --_dark-bg-hover: var(--pink-3);

  /* adaptive variables set to light by default */
  --_bg: var(--_light-bg);

  /* static icon colors set to the adaptive foreground variable */
  --_light-fg: white;
  --_dark-fg: black;
  --_fg: var(--_light-fg);

  /* use the adaptive properties on some styles */
  background: var(--_bg);
  color: var(--_fg);

  &:is(:active, :hover, :focus-visible) {
    --_bg: var(--_light-bg-hover);

    @media (prefers-color-scheme: dark) {
      --_bg: var(--_dark-bg-hover);
    }
  }

  /* if users prefers dark, set adaptive props to dark */
  @media (prefers-color-scheme: dark) {
    --_bg: var(--_dark-bg);
    --_fg: var(--_dark-fg);
  }
}

Ajoutez ensuite quelques styles pour que les icônes SVG s'adaptent à l'espace.

.fab {
  

  & > svg {
    inline-size: var(--_size);
    block-size: var(--_size);
    stroke-width: 3px;
  }
}

Enfin, supprimez la mise en surbrillance du bouton, car nous avons ajouté nos propres commentaires visuels pour l'interaction :

.fab {
  -webkit-tap-highlight-color: transparent;
}

Mini bouton d'action flottant

L'objectif de cette section est de créer une variante pour le bouton de type appui long. En réduisant la taille de certains boutons d'action flottants par rapport à l'action par défaut, nous pouvons mettre en avant l'action que l'utilisateur effectue le plus souvent.

Balisage du mini bouton d'action flottant

Le code HTML est identique à un bouton d'action flottant, à la différence que nous ajoutons une classe ".mini" pour donner au CSS une accroche dans la variante.

<button data-icon="heart" class="fab mini" title="Like action" aria-label="Like action">
  <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
Style du bouton d'action flottant mini

Grâce à l'utilisation de propriétés personnalisées, le seul changement nécessaire est un ajustement de la variable --_size.

.fab.mini {
  --_size: 1.25rem;
}

Capture d&#39;écran des deux boutons d&#39;action flottant empilés, et bouton du haut plus petit que celui du bas.

Accessibilité

L'élément le plus important à retenir pour l'accessibilité avec les boutons d'action flottants est leur emplacement dans le flux de clavier de la page. Cette démonstration ne comporte que des boutons d'action flottants. Il n'y a rien à comparer en termes d'ordre et de flux du clavier, ce qui signifie qu'il n'a pas l'occasion de démontrer un flux de clavier pertinent. Dans un scénario où des éléments se disputent l'attention, je vous suggère de réfléchir attentivement à l'endroit où l'utilisateur doit entrer dans le flux du bouton FAB.

Démonstration de l'interaction avec le clavier

Une fois que l'utilisateur a sélectionné le conteneur du bouton d'action flottant, nous avons déjà ajouté role="group" et aria-label="floating action buttons", qui informent les utilisateurs du lecteur d'écran sur le contenu de ce qu'ils ont sélectionné. J'ai placé le bouton d'action flottant par défaut en premier pour que les utilisateurs trouvent d'abord l'action principale. J'utilise ensuite flex-direction: column-reverse; pour organiser visuellement le bouton principal en bas, près des doigts des utilisateurs pour un accès facile. C'est un bon point, car le bouton par défaut est visuellement proéminent et est également le premier pour les utilisateurs de clavier, ce qui leur offre des expériences très similaires.

Enfin, n'oubliez pas de masquer vos icônes aux utilisateurs de lecteurs d'écran et assurez-vous de leur fournir un libellé pour le bouton afin qu'il ne soit pas un mystère. Cela a déjà été fait dans le code HTML avec aria-hidden="true" sur <svg> et aria-label="Some action" sur les <button>.

Animation

Vous pouvez ajouter différents types d'animations pour améliorer l'expérience utilisateur. Comme dans d'autres défis d'interface utilisateur graphique, nous allons configurer quelques propriétés personnalisées pour contenir l'intention d'une expérience de mouvement réduite et d'une expérience de mouvement complète. Par défaut, les styles supposent que l'utilisateur souhaite réduire le mouvement, puis l'utilisation de la requête média prefers-reduced-motion définit la valeur de transition sur l'intégralité du mouvement.

Une stratégie de mouvements réduits avec des propriétés personnalisées

Trois propriétés personnalisées sont créées dans le code CSS suivant : --_motion-reduced, --_motion-ok et --_transition. Les deux premières contiennent les transitions appropriées en fonction des préférences de l'utilisateur, et la dernière variable --_transition sera définie sur --_motion-reduced ou --_motion-ok, respectivement.

.fab {
  /* box-shadow and background-color can safely be transitioned for reduced motion users */
  --_motion-reduced:
    box-shadow .2s var(--ease-3),
    background-color .3s var(--ease-3);

  /* add transform and outline-offset for users ok with motion */
  --_motion-ok:
    var(--_motion-reduced),
    transform .2s var(--ease-3),
    outline-offset 145ms var(--ease-2);

  /* default the transition styles to reduced motion */
  --_transition: var(--_motion-reduced);

  /* set the transition to our adaptive transition custom property*/
  transition: var(--_transition);

  /* if motion is ok, update the adaptive prop to the respective transition prop */
  @media (prefers-reduced-motion: no-preference) {
    --_transition: var(--_motion-ok);
  }
}

Une fois les éléments ci-dessus en place, les modifications apportées à box-shadow, background-color, transform et outline-offset peuvent être effectuées, ce qui permet à l'utilisateur de recevoir un retour sur l'interface utilisateur indiquant que son interaction a été reçue.

Ajoutez ensuite un peu plus de style à l'état :active en ajustant légèrement translateY. Cela donne au bouton un bel effet de pression :

.fab {
  

  &:active {
    @media (prefers-reduced-motion: no-preference) {
      transform: translateY(2%);
    }
  }
}

Enfin, effectuez une transition entre les éventuelles modifications apportées aux icônes SVG dans les boutons:

.fab {
  

  &[data-icon="plus"]:hover > svg {
    transform: rotateZ(.25turn);
  }

  & > svg {
    @media (prefers-reduced-motion: no-preference) {
      will-change: transform;
      transition: transform .5s var(--ease-squish-3);
    }
  }
}

Conclusion

Maintenant que vous savez comment j'ai fait, comment procéderiez-vous ? 🙂

Diversifions nos approches et découvrons toutes les façons de créer sur le Web.

Créez une démo, tweetez-moi des liens et je les ajouterai à la section "Remix de la communauté" ci-dessous.

Remix de la communauté

Rien à afficher pour le moment.

Ressources