Aujourd'hui
Dernière entrée 45 minutes avant la fermeture
- Grand bassin · 25 m7:00 – 20:30
- Bassin ludique10:00 – 18:00
- Bassin nordiqueFermé
- Pataugeoire10:00 – 18:00
Une ligne de textes qui défile de droite à gauche à vitesse constante, sans fin ni trou quelle que soit la largeur, et qui s'arrête au survol ou d'un clic sur Pause.
Mis à jour le
Cet effet est gratuit — la catégorie Galerie en contient 44 au total, dont 6 gratuits. Effect.Labs regroupe 840 effets vanilla. Découvrir la catégorie →
Dernière entrée 45 minutes avant la fermeture
Limonade artisanale
Du vrai fruit, du sucre de canne, rien d'autre.
Bouteille consignée 33 clCaisses de 12Livrée en 48 h
Nouveau clip
Extrait de l'album du 6 mars. Tournée dans toute la France ce printemps.
Vous écrivez vos messages une seule fois, chacun dans un <li> de la liste .bmq-group. Au chargement, le script mesure la largeur de cette liste et celle de la fenêtre .bmq-viewport, puis ajoute derrière autant de copies qu'il en faut pour couvrir la fenêtre plus une : une copie sur un téléphone, deux dans une zone de 1 900 px avec le texte de démonstration (environ 1 240 px de long). L'ancienne version doublait le texte une fois pour toutes et laissait un vide à droite dès que la zone dépassait la longueur du texte.
L'animation CSS bmq-scroll déplace la piste d'exactement une longueur de liste, puis reprend : la copie suivante a pris la place de l'original au pixel près, le raccord ne se voit pas. La durée est calculée par le script à partir de data-speed (85 px par seconde par défaut) : un texte deux fois plus long met deux fois plus de temps, il ne file pas deux fois plus vite. data-direction="right" inverse le sens.
Un ResizeObserver refait le compte quand la zone ou le texte changent de taille (rotation du téléphone, police chargée après coup), et un MutationObserver refait les copies si vous changez le contenu de la liste par script. Chaque bande est traitée séparément : plusieurs bandes dans la même page ont chacune leur vitesse et leur bouton.
aria-pressed) arrête et relance la bande, à la souris, au doigt ou au clavier ; le survol de la bande l'arrête aussi le temps de lire. Une bande qui bouge plus de 5 secondes doit pouvoir être arrêtée (critère WCAG 2.2.2).aria-hidden="true". Mesuré avant réparation : chaque message était lu deux fois.tabindex="-1"). Dès qu'un lien a le focus, la bande revient au début, s'immobilise et amène ce lien entièrement en vue ; elle repart quand le focus la quitte.prefers-reduced-motion: reduce, rien ne défile seul, les copies et le bouton disparaissent, et la ligne se fait défiler à la main (doigt, pavé tactile, Maj + molette, barre fine) pour lire la fin ; quand elle dépasse, elle reçoit aussi le focus au clavier (Tab) et se fait défiler aux flèches. Sans JavaScript, elle reste immobile et défilable à la main.--bmq-color.CSS et 4,5 Ko de JavaScript commenté, aucune dépendance. Animation CSS dont le décalage vient d'une variable (var(--bmq-shift) dans @keyframes), ResizeObserver (Chrome 64, Firefox 69, Safari 13.1), MutationObserver, prefers-reduced-motion (Chrome 74, Firefox 63, Safari 10.1). Mesuré dans Chromium 151, Firefox 153 et WebKit 26.5 : aucun vide à 390, 800 et 1 900 px, deux bandes indépendantes, script collé deux fois sans copie en trop, 0 erreur.
Sans JavaScript, la liste reste immobile, affichée une seule fois et défilable à la main. Sans ResizeObserver (Safari avant 13.1), le compte des copies est refait au redimensionnement de la fenêtre seulement. La barre de défilement fine du mode mouvement réduit (scrollbar-width) n'existe que dans Chrome 121+, Firefox 64+ et Safari 18.2+ ; ailleurs, la barre normale s'affiche.
Copiez les trois blocs dans votre page. Aucune dépendance.
<div class="fx-0187-root" data-speed="85" data-direction="left">
<div class="bmq-band">
<div class="bmq-viewport">
<div class="bmq-track">
<ul class="bmq-group" role="list">
<li>Welcome to Effect.Labs</li>
<li>Premium Web Effects</li>
<li>Modern CSS Animations</li>
<li>Infinite Scrolling</li>
</ul>
</div>
</div>
<button type="button" class="bmq-toggle" aria-pressed="false" aria-label="Pause"></button>
</div>
</div>
.fx-0187-root,
.fx-0187-root *,
.fx-0187-root *::before,
.fx-0187-root *::after {
box-sizing: border-box;
}
/* Réglages : variables ci-dessous ; vitesse (px/s) et sens dans les attributs data-speed et data-direction du HTML */
.fx-0187-root {
--bmq-height: 250px; /* hauteur du cadre (auto : celle de la bande) */
--bmq-bg: rgb(26, 26, 36); /* fond du cadre */
--bmq-color: #6366f1; /* couleur du texte */
--bmq-size: 1.5rem; /* taille du texte */
--bmq-space: 4rem; /* espace entre deux éléments */
--bmq-button: rgba(255, 255, 255, .8); /* couleur du bouton Pause */
--bmq-padding: 1rem 0; /* marges intérieures du cadre */
--bmq-button-size: 2rem; /* diamètre du bouton Pause */
display: flex;
align-items: center;
width: 100%;
min-height: var(--bmq-height);
padding: var(--bmq-padding);
overflow: hidden;
position: relative;
background: var(--bmq-bg);
color: #fff;
font-family: sans-serif;
}
.bmq-band {
display: flex;
align-items: center;
gap: .75rem;
width: 100%;
min-width: 0;
}
.bmq-viewport {
flex: 1;
min-width: 0;
overflow: hidden;
}
.bmq-track {
display: flex;
width: max-content;
}
.bmq-group {
display: flex;
align-items: center;
flex-shrink: 0;
margin: 0;
padding: 0;
list-style: none;
font-size: var(--bmq-size);
font-weight: 600;
color: var(--bmq-color);
}
.bmq-group > li {
margin: 0 calc(var(--bmq-space) / 2);
white-space: nowrap;
}
/* Défilement : lancé par le script une fois la piste remplie (classe bmq-on) */
.fx-0187-root.bmq-on .bmq-track {
animation-name: bmq-scroll;
animation-duration: var(--bmq-duration, 15s);
animation-timing-function: linear;
animation-iteration-count: infinite;
will-change: transform;
}
.fx-0187-root[data-direction="right"] .bmq-track {
animation-direction: reverse;
}
@keyframes bmq-scroll {
from {
transform: translateX(0);
}
to {
transform: translateX(var(--bmq-shift));
}
}
/* Pause : survol de la bande ou bouton Pause */
.bmq-viewport:hover .bmq-track,
.fx-0187-root.bmq-paused .bmq-track {
animation-play-state: paused;
}
/* Focus clavier dans la bande (classe bmq-focus) : bande remise au début et immobile, le navigateur fait défiler jusqu'au lien */
.fx-0187-root.bmq-focus .bmq-track {
animation: none;
}
/* Bouton Pause / Lecture (supprimez-le du HTML si la bande est courte et purement décorative) */
.bmq-toggle {
flex: none;
position: relative;
width: var(--bmq-button-size);
height: var(--bmq-button-size);
margin: 0 1rem 0 0;
padding: 0;
border: 1px solid currentColor;
border-radius: 50%;
background: transparent;
color: var(--bmq-button);
cursor: pointer;
}
.bmq-toggle::before,
.bmq-toggle::after {
content: "";
position: absolute;
top: 50%;
width: 3px;
height: 10px;
margin-top: -5px;
border-radius: 1px;
background: currentColor;
}
.bmq-toggle::before {
left: calc(50% - 4px);
}
.bmq-toggle::after {
left: calc(50% + 1px);
}
.bmq-toggle[aria-pressed="true"]::before {
left: calc(50% - 3px);
width: 0;
height: 0;
margin-top: -6px;
border-style: solid;
border-width: 6px 0 6px 10px;
border-color: transparent transparent transparent currentColor;
border-radius: 0;
background: none;
}
.bmq-toggle[aria-pressed="true"]::after {
display: none;
}
.bmq-toggle:hover {
background: rgba(127, 127, 127, .18);
}
.bmq-toggle:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
/* Sans script : bande immobile, défilable à la main */
.fx-0187-root:not(.bmq-on) .bmq-viewport {
overflow-x: auto;
}
.fx-0187-root:not(.bmq-on) .bmq-toggle {
display: none;
}
/* Mouvement réduit : rien ne bouge seul, le contenu reste lisible et défilable à la main */
@media (prefers-reduced-motion: reduce) {
.fx-0187-root.bmq-on .bmq-track {
animation: none;
}
.fx-0187-root .bmq-viewport {
overflow-x: auto;
scrollbar-width: thin;
}
.fx-0187-root .bmq-viewport:focus-visible {
outline: 2px solid currentColor;
outline-offset: -2px;
}
.fx-0187-root .bmq-clone,
.fx-0187-root .bmq-toggle {
display: none;
}
}
(function () {
'use strict';
// fx-0187 — Basic Marquee : le contenu est écrit une fois, le script le recopie pour remplir la bande
var ROOT = '.fx-0187-root';
var VERTICAL = false;
var DEFAULT_SPEED = 85; // px par seconde
var FOCUSABLE = 'a[href], button, input, select, textarea, [tabindex]';
// Copie décorative : cachée aux lecteurs d'écran et hors du parcours clavier
function copyOf(group) {
var copy = group.cloneNode(true);
copy.classList.add('bmq-clone');
copy.setAttribute('aria-hidden', 'true');
copy.removeAttribute('id');
copy.querySelectorAll('[id]').forEach(function (el) { el.removeAttribute('id'); });
copy.querySelectorAll(FOCUSABLE).forEach(function (el) { el.setAttribute('tabindex', '-1'); });
return copy;
}
function setup(root) {
if (root.bmqReady) return; // script collé deux fois
root.bmqReady = true;
var reduced = window.matchMedia('(prefers-reduced-motion: reduce)');
var bands = [];
root.querySelectorAll('.bmq-viewport').forEach(function (viewport) {
var track = viewport.querySelector('.bmq-track');
var group = track && track.querySelector('.bmq-group');
if (!group) return;
var holder = viewport.closest('[data-speed]');
bands.push({ viewport: viewport, track: track, group: group, holder: holder && root.contains(holder) ? holder : root });
});
if (!bands.length) return;
// Assez de copies pour couvrir la zone visible + une copie qui entre ; décalage = un groupe
function fill(band) {
var box = band.group.getBoundingClientRect();
var size = VERTICAL ? box.height : box.width;
var room = VERTICAL ? band.viewport.clientHeight : band.viewport.clientWidth;
if (!size) return;
var copies = band.track.children.length;
var needed = Math.ceil(room / size) + 1;
for (; copies < needed; copies++) band.track.appendChild(copyOf(band.group));
var speed = parseFloat(band.holder.getAttribute('data-speed')) || DEFAULT_SPEED;
band.track.style.setProperty('--bmq-shift', -size + 'px');
band.track.style.setProperty('--bmq-duration', (size / speed) + 's');
// Mouvement réduit : bande défilable à la main, donc aussi au clavier (tabindex) quand elle dépasse
var over = VERTICAL ? band.viewport.scrollHeight > band.viewport.clientHeight + 1 : band.viewport.scrollWidth > band.viewport.clientWidth + 1;
if (reduced.matches && over) band.viewport.setAttribute('tabindex', '0');
else band.viewport.removeAttribute('tabindex');
root.classList.add('bmq-on');
}
function fillAll() { bands.forEach(fill); }
fillAll();
// Contenu modifié après coup (texte traduit, nouvelle info) : les copies sont refaites
if ('MutationObserver' in window) {
bands.forEach(function (band) {
new MutationObserver(function () {
band.track.querySelectorAll('.bmq-clone').forEach(function (copy) { copy.remove(); });
fill(band);
}).observe(band.group, { childList: true, subtree: true, characterData: true });
});
}
if ('ResizeObserver' in window) {
var observer = new ResizeObserver(fillAll);
bands.forEach(function (band) {
observer.observe(band.viewport);
observer.observe(band.group);
});
} else {
window.addEventListener('resize', fillAll);
}
// Focus clavier sur un lien de la bande : bande immobile (bmq-focus) et lien amené en vue, remise en place à la sortie
root.addEventListener('focusin', function (event) {
var viewport = event.target.closest('.bmq-viewport');
root.classList.toggle('bmq-focus', !!viewport);
if (!viewport) return;
var view = viewport.getBoundingClientRect();
var item = event.target.getBoundingClientRect();
if (VERTICAL) {
if (item.bottom > view.bottom) viewport.scrollTop += item.bottom - view.bottom;
if (item.top < view.top) viewport.scrollTop -= view.top - item.top;
} else {
if (item.right > view.right) viewport.scrollLeft += item.right - view.right;
if (item.left < view.left) viewport.scrollLeft -= view.left - item.left;
}
});
root.addEventListener('focusout', function () {
root.classList.remove('bmq-focus');
if (!reduced.matches) bands.forEach(function (band) { band.viewport.scrollLeft = 0; band.viewport.scrollTop = 0; });
});
var toggle = root.querySelector('.bmq-toggle');
if (toggle) {
toggle.addEventListener('click', function () {
var paused = toggle.getAttribute('aria-pressed') !== 'true';
toggle.setAttribute('aria-pressed', paused ? 'true' : 'false');
root.classList.toggle('bmq-paused', paused);
});
}
}
function init() {
document.querySelectorAll(ROOT).forEach(setup);
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Contenu (HTML — les <li> de .bmq-group) |
4 textes de démonstration | Écrivez chaque message une seule fois : texte, liens, icônes ou images. Le script fabrique les copies, et les refait si le contenu change ensuite. |
data-speed (sur la racine) |
85 | Vitesse en pixels par seconde, la même quelle que soit la longueur du texte. 30 à 50 pour des phrases à lire, 80 à 120 pour un décor. |
data-direction |
left | right fait défiler de gauche à droite. |
--bmq-color / --bmq-size |
#6366f1 / 1.5rem | Couleur et taille du texte de la bande. |
--bmq-space |
4rem | Écart entre deux messages, le même au raccord entre deux copies. |
--bmq-height / --bmq-padding / --bmq-bg |
250px / 1rem 0 / rgb(26, 26, 36) | Cadre de démonstration. Pour une bande posée dans une page : auto, 0 et transparent. |
--bmq-button / --bmq-button-size |
rgba(255, 255, 255, .8) / 2rem | Couleur et diamètre du bouton Pause. Retirez le <button> du HTML seulement pour une bande courte et décorative. |
Avant, le texte était écrit deux fois dans le HTML et l'animation le décalait de 50 % : si la zone faisait plus que la longueur du texte (environ 1 240 px ici), la fin de la deuxième copie arrivait avant le bord droit. Le script compte maintenant les copies d'après la largeur réelle, et refait le compte à chaque redimensionnement.
Ajoutez un <li> à la liste .bmq-group (par exemple avec append()) : le script voit le changement, retire les anciennes copies, en refait de nouvelles et recalcule la durée pour garder la même vitesse.
Le bouton Pause est le moyen sûr. Mesuré dans Chromium en mode tactile : un toucher sur la bande l'arrête aussi, car le navigateur simule un survol jusqu'au toucher suivant ailleurs dans la page ; tous les navigateurs mobiles ne le font pas. Glisser le doigt verticalement sur la bande fait toujours défiler la page, et toucher un lien de la bande l'ouvre, comme ailleurs.