Hover✨ Premium

Bookmark Toggle

Un bouton marque-page dont le ruban tombe en place au clic avec un léger rebond, le fond se remplit et l'icône passe du contour au plein — animation de sauvegarde en CSS pur avec retour haptique visuel.

CSSToggleAnimation

Mis à jour le

Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Hover comprend 48 effets, dont 5 gratuits. Découvrir la catégorie →

3 exemples d'usage

Enregistrement d'une offre d'emploi — tableau de bord de recherche d'emploi d'une agence de recrutement pour ingénieurs — Bookmark Toggle exemple 1

① Enregistrement d'une offre d'emploi — tableau de bord de recherche d'emploi d'une agence de recrutement pour ingénieurs

QuandChaque offre de la liste a un bouton marque-page dans son coin ; au clic, le ruban tombe et signale que l'offre est sauvegardée. Bouton 40×48 px, intégré dans la fiche sans déborder.
PourquoiL'animation de chute imite physiquement l'action de glisser un marque-page dans un dossier, immédiatement lisible sans explication.
RéglagesBouton 40×48 px en coin de chaque fiche offre, fond de liste dense sur fond sombre.
Sauvegarder un article de presse — en-tête d'une page de détail article (Quorvande) — Bookmark Toggle exemple 2

② Sauvegarder un article de presse — en-tête d'une page de détail article (Quorvande)

QuandEn pied d'en-tête d'une page d'article (Quorvande) : un grand bouton 48×48 px avec libellé « Sauvegarder l'article » permet d'enregistrer l'article d'un clic. Le ruban tombe et le label passe en violet.
PourquoiUn grand bouton nommé rend l'action explicite là où l'espace le permet ; l'animation de chute confirme visuellement l'enregistrement sans pop-up.
RéglagesBouton 48×48 px avec libellé texte, placé en bas de l'en-tête article sur fond sombre.
Marque-page sur vignettes d'un tableau d'inspiration — grille 3×2 — Bookmark Toggle exemple 3

③ Marque-page sur vignettes d'un tableau d'inspiration — grille 3×2

QuandDans un tableau d'inspiration en grille, chaque vignette colorée porte un petit bouton marque-page 30×30 px en superposition (coin supérieur droit) ; au clic, le ruban s'active et signale que l'image est enregistrée.
PourquoiL'icône posée directement sur la vignette lie visuellement le bouton à l'image et préserve la densité de la grille ; l'animation de chute confirme l'action sans interrompre la navigation.
RéglagesBouton 30×30 px en superposition sur chaque vignette, fond semi-transparent noir, grille 3 colonnes × 2 rangées.

Comment ça marche

La racine .fx-0362-root (250 px de haut, fond rgb(26, 26, 36)) centre deux boutons marque-page côte à côte dans .mi-bookmark-scene. Chaque bouton .mi-bookmark-btn (40×48 px) contient un SVG de ruban dont les bords sont tracés en stroke et l'intérieur coloré par fill. Un pseudo-élément ::before forme le fond de remplissage, initialement hors du bouton (translateY(-100%)).

Au clic, la classe .saved s'ajoute au bouton. Elle déclenche trois transitions simultanées. Côté fond : le ::before descend de translateY(-100%) à translateY(0) en 0,4 s avec une cubic-bezier(0.34, 1.56, 0.64, 1) qui donne un léger dépassement vers le bas avant de remonter en place. Côté SVG : stroke et fill passent respectivement de couleur de contour à blanc opaque, via une transition de 0,25 s. Côté label : la couleur du texte adjacent passe aussi en couleur active. L'animation de la coche (@keyframes savedCheck) dessine un trait de confirmation visible 0,2 s après le début de la transition de fond, pour que les trois changements ne semblent pas simultanés.

Le script trouve chaque .fx-0362-root, câble les boutons de la racine et met à jour aria-pressed à chaque clic. L'état initial est lu depuis la présence de la classe .saved dans le HTML : un bouton préchargé en état sauvegardé a déjà aria-pressed="true". Les deux boutons de la démo sont indépendants et leurs états ne se propagent pas d'une copie du composant à l'autre.

Accessibilité

  • Clavier : chaque bouton marque-page est un vrai <button> ; Tab l'atteint, Espace ou Entrée le bascule. Le contour de focus (:focus-visible) apparaît à la navigation au clavier.
  • État annoncé : aria-pressed passe de false à true au clic. L'aria-label (Sauvegarder / Favoris selon le bouton) décrit l'action ; le lecteur d'écran annonce l'état activé ou non activé.
  • Mouvement réduit : sous prefers-reduced-motion: reduce, la transition translateY du fond est supprimée et l'animation @keyframes savedCheck est désactivée. L'état sauvegardé reste lisible par le changement de couleur du fond et de l'icône.
  • Toucher : les boutons répondent normalement aux événements tactiles. Leur cible de 40×48 px est dans les minimums recommandés (44×44 px).

Compatibilité navigateur

CSS pur (transitions, pseudo-éléments, cubic-bezier avec dépassement) + 0,4 Ko de JavaScript (classList, aria-pressed), aucune dépendance. Vérifié dans Chromium 151 : animation de chute, remplissage, deux boutons indépendants, deux copies de la racine indépendantes, aria-pressed mis à jour, 0 erreur. Les captures d'aperçu montrent l'animation rejouée en boucle automatique par le code de scène : ce comportement n'est pas inclus dans le code vendu.

Chrome 49+✓ Complet (mesuré)
Firefox 55+✓ Complet
Safari 9.1+✓ Complet
Edge 79+✓ Complet (moteur Chromium)
Mobile iOS 9.3+✓ Complet
Android Chrome 49+✓ Complet (moteur Chromium)

Sans JavaScript, le bouton reste fonctionnel en lecture seule (l'état ne bascule plus). Sans CSS transitions, le fond et l'icône changent instantanément de couleur sans animation de chute.

Le code

Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :

index.html — structure
<div class="fx-0362-root">
  <div class="mi-bookmark-scene">
    <button class="mi-bookmark-btn" aria-pressed="false" aria-label="Sauvegarder">
      <svg viewBox="0 0 24 24">
        <path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path>
      </svg>
    </button>
    <span class="mi-bookmark-text">Sauvegarder</span>
  </div>
</div>

Paiement unique, sans abonnement — le code est à toi pour toujours

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
Couleur de fond actif (CSS — background de .mi-bookmark-btn::before et .mi-bookmark-btn.saved::before) Bleu indigo #6366f1 Passez à #f59e0b (ambre) ou #10b981 (vert émeraude). La couleur de l'icône SVG en état actif (.mi-bookmark-btn.saved svg) et du label (.mi-bookmark-btn.saved ~ .mi-bookmark-text) doivent être mis à jour en cohérence.
Rebond de la chute (CSS — cubic-bezier de la transition transform sur ::before) cubic-bezier(0.34, 1.56, 0.64, 1) (léger dépassement) ease-out donne une chute sans rebond ; augmentez le deuxième paramètre au-delà de 1 (ex. 1,8) pour un rebond plus marqué.
Taille du bouton (CSS — width / height de .mi-bookmark-btn) 40×48 px Réduisez à 32×40 px pour une liste très dense ; agrandissez à 48×56 px pour un usage isolé. Le SVG à l'intérieur suit si sa taille est exprimée en pourcentage.
Nombre de boutons dans la démo (HTML — nombre de .mi-bookmark-btn dans la scène) 2 boutons Ajoutez ou supprimez des boutons dans le .mi-bookmark-scene. Chaque bouton doit avoir son propre aria-label décrivant l'élément à sauvegarder.
État initial sauvegardé (HTML — classe .saved sur le bouton) Aucun bouton sauvegardé au départ Ajoutez la classe .saved directement dans le HTML pour afficher un bouton déjà enregistré au chargement ; le JS lit cet état et initialise aria-pressed en conséquence.

FAQ

Oui pour le passage à l'état non sauvegardé → sauvegardé : la classe .saved s'ajoute et l'animation de chute rejoue. Mais le passage inverse (sauvegardé → non sauvegardé) n'a pas d'animation propre : le fond disparaît sans animation de sortie. Pour ajouter une animation de retrait, déclarez @keyframes sur la suppression de la classe ou utilisez une animation animation-direction: reverse.
Oui, en ajoutant la classe .saved directement dans le HTML. Le script lit l'état initial des classes et fixe aria-pressed en conséquence : aria-pressed="true" sur un bouton déjà .saved.
Non. Chaque bouton a son propre état de classe .saved et son propre aria-pressed. L'un peut être sauvegardé et l'autre non, indépendamment. De même, deux copies du composant sur la même page ont des états totalement séparés.