Introduction
Les composants UI interactifs sont le socle de toute interface web moderne. Accordions, tabs, modals et toast notifications se retrouvent sur la majorite des sites, mais leur qualite d'animation fait toute la difference entre une experience banale et une interface premium.
Dans ce tutoriel, nous allons construire 5 composants essentiels avec des animations CSS fluides et du JavaScript accessible. Chaque composant est accompagne d'un demo interactif et du code complet a copier.
Tous les composants de ce tutoriel utilisent des transitions CSS pour la fluidite et du JavaScript vanille pour la logique. Aucune dependance externe n'est requise.
1. Accordion anime
L'accordion est le composant ideal pour afficher du contenu pliable. Notre version utilise la technique max-height pour une transition fluide a l'ouverture et a la fermeture.
Demo interactive
.accordion-item {
border: 1px solid #2a2a35;
border-radius: 12px;
margin-bottom: 8px;
overflow: hidden;
}
.accordion-header {
padding: 16px 20px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
}
.accordion-icon {
transition: transform 0.3s ease;
}
.accordion-item.active .accordion-icon {
transform: rotate(45deg);
}
/* Transition fluide avec max-height */
.accordion-body {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease;
}
.accordion-item.active .accordion-body {
max-height: 200px;
}
function toggleAccordion(item) {
// Fermer les autres items (mode exclusif)
const siblings = item.parentElement
.querySelectorAll('.accordion-item');
siblings.forEach(sibling => {
if (sibling !== item) {
sibling.classList.remove('active');
}
});
// Basculer l'item clique
item.classList.toggle('active');
}
Comment ca fonctionne
La technique repose sur la propriete max-height :
- Etat ferme :
max-height: 0avecoverflow: hiddenmasque le contenu - Etat ouvert :
max-height: 200pxrevele le contenu avec une transition fluide - L'icone + tourne de 45 degres pour former un x grace a
transform: rotate(45deg)
Choisissez une valeur max-height legerement superieure au contenu reel. Une valeur trop grande ralentit visuellement la transition car le navigateur anime jusqu'a cette valeur meme si le contenu est plus petit.
2. Tabs animes
Les tabs (onglets) permettent d'organiser du contenu en sections accessibles sans changement de page. Notre version integre un indicateur glissant qui suit l'onglet actif avec une transition fluide.
Demo interactive
.tabs-nav {
display: flex;
border-bottom: 2px solid #2a2a35;
position: relative;
}
.tab-btn {
padding: 12px 24px;
background: none;
border: none;
color: #a1a1aa;
font-weight: 600;
cursor: pointer;
transition: color 0.3s;
}
.tab-btn.active {
color: #6366f1;
}
/* Indicateur glissant */
.tabs-indicator {
position: absolute;
bottom: -2px;
height: 2px;
background: #6366f1;
transition: left 0.3s ease,
width 0.3s ease;
}
/* Animation d'apparition du panneau */
.tab-panel {
display: none;
animation: tabFadeIn 0.3s ease;
}
.tab-panel.active {
display: block;
}
@keyframes tabFadeIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
function switchTab(btn, panelId) {
const container = btn.closest('.tabs-container');
// Desactiver tous les onglets et panneaux
container.querySelectorAll('.tab-btn')
.forEach(b => b.classList.remove('active'));
container.querySelectorAll('.tab-panel')
.forEach(p => p.classList.remove('active'));
// Activer l'onglet et panneau selectionnes
btn.classList.add('active');
document.getElementById(panelId)
.classList.add('active');
// Deplacer l'indicateur
updateIndicator(btn);
}
function updateIndicator(activeBtn) {
const indicator = document
.getElementById('tabIndicator');
indicator.style.left =
activeBtn.offsetLeft + 'px';
indicator.style.width =
activeBtn.offsetWidth + 'px';
}
3. Modal avec animation
Les modals (fenetres modales) sont essentiels pour les confirmations, formulaires et messages importants. Notre version combine une animation d'entree avec rebond (cubic-bezier) et un overlay avec backdrop-filter.
Demo interactive
.modal-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
backdrop-filter: blur(4px);
z-index: 2000;
align-items: center;
justify-content: center;
}
.modal-overlay.show {
display: flex;
animation: overlayIn 0.3s ease;
}
@keyframes overlayIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Animation d'entree avec rebond */
.modal-box {
background: #12121a;
border-radius: 20px;
padding: 40px;
max-width: 480px;
width: 90%;
animation: modalIn 0.4s
cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes modalIn {
from {
opacity: 0;
transform: scale(0.9) translateY(20px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
function openModal() {
const overlay = document
.getElementById('modalOverlay');
overlay.classList.add('show');
document.body.style.overflow = 'hidden';
}
function closeModal() {
const overlay = document
.getElementById('modalOverlay');
overlay.classList.remove('show');
document.body.style.overflow = '';
}
// Fermer en cliquant sur l'overlay
overlay.addEventListener('click', (e) => {
if (e.target === overlay) closeModal();
});
Pensez a ajouter overflow: hidden sur le body a l'ouverture de la modal pour empecher le scroll en arriere-plan, et a le retirer a la fermeture.
4. Toast Notification
Les toast notifications sont des messages temporaires non-intrusifs. Notre version utilise un slide-in depuis la droite avec un timing cubic-bezier pour un effet de rebond subtil.
Demo interactive
.toast {
position: fixed;
bottom: 24px;
right: 24px;
padding: 16px 24px;
background: #12121a;
border: 1px solid #10b981;
border-radius: 14px;
display: flex;
align-items: center;
gap: 12px;
z-index: 3000;
box-shadow: 0 8px 30px rgba(0,0,0,0.3);
/* Etat initial : hors ecran a droite */
transform: translateX(calc(100% + 40px));
opacity: 0;
transition: transform 0.4s
cubic-bezier(0.34, 1.56, 0.64, 1),
opacity 0.4s ease;
}
.toast.show {
transform: translateX(0);
opacity: 1;
}
function showToast() {
const toast = document
.getElementById('toastDemo');
toast.classList.add('show');
// Masquer apres 3 secondes
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
5. Tooltip anime
Les tooltips fournissent des informations contextuelles au survol. Notre version utilise un fade + translate avec une fleche CSS en pseudo-element pour un resultat elegant et leger.
.tooltip-wrapper {
position: relative;
display: inline-block;
}
.tooltip {
position: absolute;
bottom: calc(100% + 10px);
left: 50%;
transform: translateX(-50%)
translateY(8px);
padding: 8px 16px;
background: #1a1a25;
border: 1px solid #2a2a35;
border-radius: 8px;
font-size: 0.85rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease,
transform 0.2s ease;
}
/* Fleche du tooltip */
.tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: #1a1a25;
}
/* Afficher au survol */
.tooltip-wrapper:hover .tooltip {
opacity: 1;
transform: translateX(-50%)
translateY(0);
}
Le tooltip se positionne au-dessus de l'element parent grace a bottom: calc(100% + 10px). La fleche est creee avec un pseudo-element ::after utilisant la technique des bordures CSS.
Pour un tooltip qui s'adapte automatiquement a la position dans le viewport (en haut, en bas, a gauche ou a droite), il faudra ajouter du JavaScript pour detecter l'espace disponible et ajuster la classe de positionnement.
Bonnes pratiques
Voici les recommandations essentielles pour des composants UI de qualite professionnelle :
Performance
- Preferez
transformetopacitypour les animations : ces proprietes sont optimisees par le GPU et ne declenchent pas de reflow - Evitez d'animer
heightdirectement : utilisezmax-heightoutransform: scaleY()a la place - Utilisez
will-changeavec parcimonie sur les elements frequemment animes
Accessibilite
Les attributs ARIA sont essentiels pour rendre vos composants utilisables par tous :
<!-- Accordion accessible -->
<button
role="button"
aria-expanded="false"
aria-controls="panel-1"
>Titre de la section</button>
<div
id="panel-1"
role="region"
aria-hidden="true"
>Contenu</div>
<!-- Modal accessible -->
<div
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<h2 id="modal-title">Titre</h2>
</div>
<!-- Tabs accessibles -->
<div role="tablist">
<button
role="tab"
aria-selected="true"
aria-controls="tab-panel-1"
>Onglet 1</button>
</div>
UX
- Duree des animations : 200-400ms est la plage ideale. En dessous, c'est trop rapide pour etre percu ; au-dessus, ca ralentit l'utilisateur
- Easing naturel : utilisez
easeoucubic-bezierplutot quelinearpour un mouvement organique - Feedback immediat : le composant doit reagir au clic en moins de 100ms, meme si l'animation complete prend plus de temps
- Respectez
prefers-reduced-motionpour les utilisateurs sensibles aux mouvements
@media (prefers-reduced-motion: reduce) {
.accordion-body,
.tabs-indicator,
.modal-box,
.toast,
.tooltip {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}
Conclusion
Les composants UI animes sont la cle d'une interface web agreable et professionnelle. En combinant CSS transitions pour la fluidite, @keyframes pour les animations complexes et JavaScript vanille pour la logique, vous obtenez des composants performants et accessibles.
Les techniques presentees dans ce tutoriel -- max-height pour les accordions, indicateur glissant pour les tabs, cubic-bezier pour les modals et translateX pour les toasts -- couvrent la majorite des besoins en composants interactifs. Adaptez les durees, les easing et les couleurs a votre design system pour un resultat coherent.
Decouvrez notre collection de composants prets a l'emploi dans la bibliotheque d'effets, avec code copiable en un clic et demos interactives.