Catégories
Astuces et Design

Comment recréer l'effet d'entraînement des boutons de conception de matériaux

Lorsque j'ai découvert Material Design pour la première fois, j'ai été particulièrement inspiré par son composant bouton. Il utilise un effet d'entraînement pour donner aux utilisateurs des commentaires d'une manière simple et élégante.

Comment fonctionne cet effet? Les boutons de Material Design ne présentent pas seulement une animation ondulée soignée, mais l'animation change également de position en fonction de l'endroit où chaque bouton est cliqué.

Nous pouvons obtenir le même résultat. Nous allons commencer par une solution concise utilisant ES6 + JavaScript, avant d'examiner quelques approches alternatives.

HTML

Notre objectif est d'éviter tout balisage HTML superflu. Nous allons donc utiliser le strict minimum:

Styliser le bouton

Nous devrons styliser dynamiquement quelques éléments de notre ondulation, à l'aide de JavaScript. Mais tout le reste peut être fait en CSS. Pour nos boutons, il suffit d’inclure deux propriétés.

button {
  position: relative;
  overflow: hidden;
}

En utilisant position: relative nous permet d'utiliser position: absolute sur notre élément d'entraînement, dont nous avons besoin pour contrôler sa position. Pendant ce temps, overflow: hidden empêche l'ondulation de dépasser les bords du bouton. Tout le reste est facultatif. Mais pour le moment, notre bouton a l'air un peu old school. Voici un point de départ plus moderne:

/* Roboto is Material's default font */
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');


button {
  position: relative;
  overflow: hidden;
  transition: background 400ms;
  color: #fff;
  background-color: #6200ee;
  padding: 1rem 2rem;
  font-family: 'Roboto', sans-serif;
  font-size: 1.5rem;
  outline: 0;
  border: 0;
  border-radius: 0.25rem;
  box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.3);
  cursor: pointer;
}

Styliser les ondulations

Plus tard, nous utiliserons JavaScript pour injecter des ondulations dans notre HTML sous forme d'étendues avec un .ripple classe. Mais avant de passer à JavaScript, définissons un style pour ces ondulations dans CSS afin de les avoir à portée de main:

span.ripple {
  position: absolute; /* The absolute position we mentioned earlier */
  border-radius: 50%;
  transform: scale(0);
  animation: ripple 600ms linear;
  background-color: rgba(255, 255, 255, 0.7);
}

Pour rendre nos ondulations circulaires, nous avons défini la border-radius à 50%. Et pour nous assurer que chaque ondulation émerge de rien, nous avons défini l'échelle par défaut sur 0. Pour le moment, nous ne pouvons rien voir car nous n'avons pas encore de valeur pour le top, left, width, ou height Propriétés; nous allons bientôt injecter ces propriétés avec JavaScript.

Quant à notre CSS, la dernière chose que nous devons ajouter est un état final pour l'animation:

@keyframes ripple {
  to {
    transform: scale(4);
    opacity: 0;
  }
}

Notez que nous ne définissons pas un état de départ avec le from mot-clé dans les images clés? Nous pouvons omettre from et CSS construira les valeurs manquantes en fonction de celles qui s'appliquent à l'élément animé. Cela se produit si les valeurs pertinentes sont énoncées explicitement – comme dans transform: scale(0) – ou s'il s'agit de la valeur par défaut, comme opacity: 1.

Maintenant pour le JavaScript

Enfin, nous avons besoin de JavaScript pour définir dynamiquement la position et la taille de nos ondulations. La taille doit être basée sur la taille du bouton, tandis que la position doit être basée à la fois sur la position du bouton et du curseur.

Nous allons commencer par une fonction vide qui prend un événement de clic comme argument:

function createRipple(event) {
  //
}

Nous accéderons à notre bouton en trouvant le currentTarget de l'événement.

const button = event.currentTarget;

Ensuite, nous allons instancier notre élément span et calculer son diamètre et son rayon en fonction de la largeur et de la hauteur du bouton.

const circle = document.createElement("span");
const diameter = Math.max(button.clientWidth, button.clientHeight);
const radius = diameter / 2;

Nous pouvons maintenant définir les propriétés restantes dont nous avons besoin pour nos ondulations: le left, top, width et height.

circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${event.clientX - (button.offsetLeft + radius)}px`;
circle.style.top = `${event.clientY - (button.offsetTop + radius)}px`;
circle.classList.add("ripple"); 

Avant d'ajouter notre élément span au DOM, il est recommandé de vérifier les ondulations existantes qui pourraient être restées des clics précédents, et de les supprimer avant d'exécuter la suivante.

const ripple = button.getElementsByClassName("ripple")(0);


if (ripple) {
  ripple.remove();
}

Pour terminer, nous ajoutons le span en tant qu'enfant à l'élément button afin qu'il soit injecté à l'intérieur du bouton.

button.appendChild(circle);

Une fois notre fonction terminée, il ne reste plus qu'à l'appeler. Cela pourrait se faire de plusieurs manières. Si nous voulons ajouter l'ondulation à chaque bouton de notre page, nous pouvons utiliser quelque chose comme ceci:

const buttons = document.getElementsByTagName("button");
for (const button of buttons) {
  button.addEventListener("click", createRipple);
}

Nous avons maintenant un effet d'entraînement fonctionnel!

Aller plus loin

Et si nous voulons aller plus loin et combiner cet effet avec d’autres modifications de la position ou de la taille de notre bouton? La possibilité de personnaliser est, après tout, l'un des principaux avantages que nous avons en choisissant de recréer l'effet nous-mêmes. Pour tester à quel point il est facile d'étendre notre fonction, j'ai décidé d'ajouter un effet «aimant», ce qui amène notre bouton à se déplacer vers notre curseur lorsque le curseur se trouve dans une certaine zone.

Nous devons nous fier à certaines des mêmes variables définies dans la fonction d'entraînement. Plutôt que de répéter le code inutilement, nous devrions les stocker dans un endroit accessible aux deux méthodes. Mais nous devons également garder les variables partagées étendues à chaque bouton individuel. Une façon d'y parvenir consiste à utiliser des classes, comme dans l'exemple ci-dessous:

Étant donné que l'effet d'aimant doit suivre le curseur à chaque fois qu'il se déplace, nous n'avons plus besoin de calculer la position du curseur pour créer une ondulation. Au lieu de cela, nous pouvons compter sur cursorX et cursorY.

Deux nouvelles variables importantes sont magneticPullX et magneticPullY. Ils contrôlent la force avec laquelle notre méthode magnétique tire le bouton après le curseur. Ainsi, lorsque nous définissons le centre de notre ondulation, nous devons ajuster à la fois la position du nouveau bouton (x et y) et la traction magnétique.

const offsetLeft = this.left + this.x * this.magneticPullX;
const offsetTop = this.top + this.y * this.magneticPullY;

Pour appliquer ces effets combinés à tous nos boutons, nous devons instancier une nouvelle instance de la classe pour chacun:

const buttons = document.getElementsByTagName("button");
for (const button of buttons) {
  new Button(button);
}

Autres techniques

Bien sûr, ce n'est qu'une manière d'obtenir un effet d'entraînement. Sur CodePen, il existe de nombreux exemples qui montrent différentes implémentations. Voici quelques-uns de mes favoris.

CSS uniquement

Si un utilisateur a désactivé JavaScript, notre effet d'entraînement n'a pas de solution de rechange. Mais il est possible de se rapprocher de l'effet d'origine avec seulement CSS, en utilisant la pseudo-classe: active pour répondre aux clics. La principale limitation est que l'ondulation ne peut émerger que d'un seul endroit – généralement le centre du bouton – plutôt que de répondre à la position de nos clics. Cet exemple de Ben Szabo est particulièrement concis:

JavaScript pré-ES6

La démo de Leandro Parice est similaire à notre implémentation, mais elle est compatible avec les versions antérieures de JavaScript:

jQuery

Cet exemple utilise jQuery pour obtenir l'effet d'entraînement. Si vous avez déjà jQuery en tant que dépendance, cela pourrait vous aider à économiser quelques lignes de code.

Réagir

Enfin, un dernier exemple de ma part. Bien qu'il soit possible d'utiliser des fonctionnalités React telles que l'état et les références pour aider à créer l'effet d'entraînement, celles-ci ne sont pas strictement nécessaires. La position et la taille de l'ondulation doivent toutes deux être calculées pour chaque clic. Il n'y a donc aucun avantage à conserver ces informations dans l'état. De plus, nous pouvons accéder à notre élément bouton à partir de l'événement de clic, nous n'avons donc pas non plus besoin de références.

Cet exemple React utilise un createRipple fonction identique à celle de la première implémentation de cet article. La principale différence est que – en tant que méthode de Button composant – notre fonction est étendue à ce composant. Également onClick event listener fait maintenant partie de notre JSX:

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *