Chapitre 3 · La matière
Le modèle de l'atome
Carbone : 2 électrons sur la 1re couche, 4 sur la 2e.
- Noyau : 6 protons, 6 neutrons
- Électron
Un noyau violet, deux anneaux en pointillés et trois points qui tournent : un rose sur l'anneau intérieur, et sur l'anneau extérieur un cyan et un ambre qui vont en sens contraires et se croisent — CSS pur avec offset-path: circle(), zéro JavaScript, image fixe si l'utilisateur réduit les animations.
Mis à jour le
Cet effet est gratuit — la catégorie 3D en contient 50 au total, dont 8 gratuits. Effect.Labs regroupe 840 effets vanilla. Découvrir la catégorie →
Chapitre 3 · La matière
Carbone : 2 électrons sur la 1re couche, 4 sur la 2e.
Base de loisirs des Varennes · Plan
Chemin du lac 2,4 km · Vélos au pas près de la plage
Cercle celtique Telenn Glas
Initiation à 20 h
Le bloc .fx-0031-root fait 250 px de haut et toute la largeur disponible, fond rgb(26, 26, 36). Au centre, .mp-orbit-scene (260 × 260 px) empile deux anneaux de 140 et 210 px (bordure de 1 px en pointillés, blanc à 10 %), un noyau de 40 px en dégradé violet #8b5cf6 → #7c3aed avec un halo, et trois points en position: absolute. Le noyau passe devant les points (z-index: 2).
Le mouvement tient en deux déclarations par point. offset-path: circle(70px) trace un cercle de 70 px de rayon centré sur la scène, sur lequel le point se place par son centre, quelle que soit sa taille (sa marge négative n'y change rien, mesuré), et l'animation mpOrbit fait varier offset-distance de 0 à 100 % : le point parcourt le cercle, en commençant à droite (3 heures) et dans le sens des aiguilles d'une montre. Le point rose (16 px) fait le tour intérieur en 4 s. Sur l'anneau extérieur, circle(105px), le point cyan (12 px) tourne en 7 s avec animation-direction: reverse, donc à l'envers, et le point ambre (8 px) en 5 s à l'endroit. Leurs vitesses s'additionnent quand ils vont l'un vers l'autre : ils se croisent toutes les 2,9 s, à un endroit différent à chaque fois.
Tout est linéaire (linear) : vitesse constante, aucun à-coup. Aucun script, aucun identifiant : deux copies du bloc sur une même page tournent chacune de leur côté (mesuré dans Chromium, Firefox et WebKit). Sous prefers-reduced-motion: reduce, un bloc limité à .fx-0031-root retire les animations et pose les trois points à 12, 62 et 30 % de leur anneau : ils restent visibles, répartis, au lieu de s'empiler au point de départ.
prefers-reduced-motion: reduce, les trois points s'arrêtent à des places fixes, répartis sur leurs anneaux. Mesuré dans Chromium, Firefox et WebKit : 0 animation en cours, 0 % des pixels changent en 800 ms.aria-hidden="true" sur la racine et écrivez l'information à côté, comme la légende des exemples ; sinon, donnez à la racine role="img" et un aria-label qui dit ce qu'on voit.rgba(30, 41, 59, .38)), sinon ils disparaissent et les points semblent flotter sans trajectoire.CSS pur : offset-path: circle(), offset-distance animé par @keyframes, prefers-reduced-motion. Aucune dépendance, aucun JavaScript. Mesuré dans Chromium 151, Firefox 153 et WebKit 26.5 : chaque point reste à moins de 0,1 px de son anneau pendant tout le tour, mêmes vitesses, même arrêt sous mouvement réduit, deux copies indépendantes sur la page. circle() comme trajectoire est arrivé plus tard que path() : versions minimales ci-dessous.
Un navigateur qui ne connaît pas offset-path: circle() ignore la trajectoire : les trois points restent au centre, cachés derrière le noyau (mesuré en retirant la propriété). On voit alors un noyau immobile et ses deux anneaux, sans rien de cassé.
Copiez les trois blocs dans votre page. Aucune dépendance.
<div class="fx-0031-root">
<div class="mp-orbit-scene">
<div class="mp-orbit-ring mp-orbit-ring--1"></div>
<div class="mp-orbit-ring mp-orbit-ring--2"></div>
<div class="mp-orbit-center"></div>
<div class="mp-orbit-dot mp-orbit-dot--1"></div>
<div class="mp-orbit-dot mp-orbit-dot--2"></div>
<div class="mp-orbit-dot mp-orbit-dot--3"></div>
</div>
</div>
.fx-0031-root,
.fx-0031-root *,
.fx-0031-root *::before,
.fx-0031-root *::after {
box-sizing: border-box
}
.fx-0031-root {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.mp-orbit-scene {
width: 260px;
height: 260px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.mp-orbit-center {
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
box-shadow: 0 0 20px rgba(139, 92, 246, 0.4);
z-index: 2;
}
.mp-orbit-ring {
position: absolute;
border-radius: 50%;
border: 1px dashed rgba(255, 255, 255, 0.1);
}
.mp-orbit-ring--1 {
width: 140px;
height: 140px;
}
.mp-orbit-ring--2 {
width: 210px;
height: 210px;
}
.mp-orbit-dot {
position: absolute;
border-radius: 50%;
top: 50%;
left: 50%;
}
.mp-orbit-dot--1 {
width: 16px;
height: 16px;
background: #ec4899;
box-shadow: 0 0 10px rgba(236, 72, 153, 0.5);
offset-path: circle(70px);
animation: mpOrbit 4s linear infinite;
margin: -8px 0 0 -8px;
}
.mp-orbit-dot--2 {
width: 12px;
height: 12px;
background: #06b6d4;
box-shadow: 0 0 10px rgba(6, 182, 212, 0.5);
offset-path: circle(105px);
animation: mpOrbit 7s linear infinite reverse;
margin: -6px 0 0 -6px;
}
.mp-orbit-dot--3 {
width: 8px;
height: 8px;
background: #f59e0b;
box-shadow: 0 0 8px rgba(245, 158, 11, 0.5);
offset-path: circle(105px);
animation: mpOrbit 5s linear infinite;
margin: -4px 0 0 -4px;
}
@keyframes mpOrbit {
to {
offset-distance: 100%;
}
}
/* Mouvement réduit : les trois points s'arrêtent, répartis sur leurs anneaux (image fixe). */
@media (prefers-reduced-motion: reduce) {
.fx-0031-root .mp-orbit-dot { animation: none }
.fx-0031-root .mp-orbit-dot--1 { offset-distance: 12% }
.fx-0031-root .mp-orbit-dot--2 { offset-distance: 62% }
.fx-0031-root .mp-orbit-dot--3 { offset-distance: 30% }
}
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Rayon des orbites (CSS — offset-path: circle(70px) et circle(105px)) |
70 px et 105 px | Changez aussi la taille de l'anneau correspondant (le diamètre vaut deux fois le rayon : 140 et 210 px), sinon le point tourne à côté de son trait. Pour tout agrandir d'un coup, préférez transform: scale() sur .mp-orbit-scene. |
Durée d'un tour (CSS — animation de chaque .mp-orbit-dot--N) |
4 s, 7 s et 5 s | Une durée plus longue ralentit le point. Des durées sans multiple commun (5 et 7) font que les croisements ne reviennent jamais au même endroit. |
Sens de rotation (CSS — mot-clé reverse dans animation) |
horaire, sauf le point cyan | Ajoutez ou retirez reverse pour inverser un point. Le départ est à droite du cercle (3 heures). |
Ajouter un point (HTML + CSS — animation-delay négatif) |
3 points | Dupliquez un .mp-orbit-dot--N et donnez à la copie animation-delay: -2s (la moitié d'un tour de 4 s) : elle part à l'opposé de l'original, sans attendre. |
Couleurs (CSS — background du noyau et des points, border des anneaux) |
violet, rose #ec4899, cyan #06b6d4, ambre #f59e0b |
Le halo de chaque point est un box-shadow de la même teinte à 50 % : changez-le avec la couleur. |
Hauteur du bloc (CSS — height de .fx-0031-root) |
250px | La scène fait 260 px et le bloc la rogne de 5 px en haut et en bas (overflow: hidden), sans toucher aux anneaux. En dessous d'environ 220 px, les points de l'anneau extérieur sont rognés en haut et en bas. |
Les deux posent des points sur des cercles avec offset-path: circle(), mais ils ne racontent pas la même chose. Orbit Circle joue sur le sens : deux anneaux en pointillés, trois points, dont deux qui se croisent à contresens sur le même anneau (flux opposés, rondes de danse). Multi Orbit joue sur la période : trois anneaux presque invisibles, cinq planètes de 6 à 14 px qui tournent toutes dans le même sens en 3, 5 et 8 s, deux à deux en opposition (navettes, tournées, système solaire). Choisissez celui-ci pour montrer deux sens de circulation ; Multi Orbit pour montrer des rythmes différents autour d'un même centre.
L'autre méthode classique fait tourner un bras invisible avec transform: rotate() et pose le point à son bout : il faut un élément de plus par point et une contre-rotation si le point porte un texte ou une icône. Avec offset-path, le point suit le cercle directement, le rayon s'écrit en une valeur et le sens se change par reverse. En contrepartie, circle() comme trajectoire demande Chrome 116 ou Firefox 122 au minimum ; avant, les points restent cachés au centre.
Oui : un .mp-orbit-dot peut contenir une image ou un emoji. Par défaut offset-rotate vaut auto : l'élément s'oriente selon la tangente du cercle et son contenu tourne avec lui. Pour garder une icône droite, ajoutez offset-rotate: 0deg sur le point.