Marquesina infinita
Contenido que se desplaza sin fin, con bordes que se desvanecen.
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
/**
* Marquesina infinita solo con CSS: el contenido se duplica y se desplaza sin saltos, con bordes que se desvanecen.
* Se pausa al pasar el puntero o enfocar dentro, y se detiene con movimiento reducido.
*
* <Marquee duration={30}>
* <span>React</span><span>Next.js</span><span>TypeScript</span>
* </Marquee>
* <Marquee reverse duration={40}>…</Marquee>
*
* El contenido se hereda en dos copias; la segunda se oculta a lectores de pantalla.
*/
import type { CSSProperties, ReactNode } from "react";
export type MarqueeProps = {
children: ReactNode;
/** Segundos que tarda una vuelta completa. */
duration?: number;
/** Espacio entre elementos. */
gap?: number | string;
reverse?: boolean;
pauseOnHover?: boolean;
/** Desvanece los bordes. */
fade?: boolean;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gcmq-root { display: flex; overflow: hidden; width: 100%; }
.gcmq-root[data-fade="true"] { -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); }
.gcmq-track { display: flex; flex: none; min-width: 100%; align-items: center; justify-content: space-around; gap: var(--gcmq-gap, 32px); padding-right: var(--gcmq-gap, 32px); animation: gcmq-run var(--gcmq-duration, 30s) linear infinite; animation-direction: var(--gcmq-direction, normal); }
.gcmq-root[data-pause="true"]:hover .gcmq-track, .gcmq-root[data-pause="true"]:focus-within .gcmq-track { animation-play-state: paused; }
@keyframes gcmq-run { to { transform: translateX(-100%); } }
@media (prefers-reduced-motion: reduce) { .gcmq-track { animation: none; } .gcmq-track[aria-hidden="true"] { display: none; } .gcmq-root { overflow-x: auto; } }
`;
export function Marquee({ children, duration = 30, gap = 32, reverse = false, pauseOnHover = true, fade = true, className, style }: MarqueeProps) {
const vars = { ["--gcmq-duration" as string]: `${duration}s`, ["--gcmq-gap" as string]: typeof gap === "number" ? `${gap}px` : gap, ["--gcmq-direction" as string]: reverse ? "reverse" : "normal", ...style } as CSSProperties;
return (
<>
<style>{CSS}</style>
<div className={["gcmq-root", className].filter(Boolean).join(" ")} style={vars} data-fade={fade} data-pause={pauseOnHover}>
<div className="gcmq-track">{children}</div>
<div className="gcmq-track" aria-hidden="true">{children}</div>
</div>
</>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/marquee-infinitoEjemplo de uso de Marquesina infinita
Después de copiar marquee.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { Marquee } from "./marquee";
export default function Ejemplo() {
return <Marquee reverse>Contenido</Marquee>;
}Propiedades de Marquee
Marquee acepta 8 propiedades; 1 es obligatoria.
| Propiedad | Tipo | Descripción |
|---|---|---|
children | ReactNode | Obligatoria. |
duration? | number | Segundos que tarda una vuelta completa. |
gap? | number | string | Espacio entre elementos. |
reverse? | boolean | Opcional. |
pauseOnHover? | boolean | Opcional. |
fade? | boolean | Desvanece los bordes. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Personaliza Marquesina infinita con variables CSS
Define estas variables en el contenedor o en tu hoja de estilos para cambiar los colores sin tocar el componente. Si no las defines, se usa el valor por defecto.
| Variable | Valor por defecto |
|---|---|
--gcmq-gap | 32px |
--gcmq-duration | 30s |
--gcmq-direction | normal |
Accesibilidad y rendimiento
El archivo tiene 51 líneas (2 KB) y define 1 animación con @keyframes. Esto es lo que hace Marquesina infinita por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Expone su estado a tecnologías de apoyo con atributos aria-*.
Acerca del producto
Una marquesina que desplaza cualquier contenido sin saltos solo con CSS: duplica el contenido y mueve la pista de cero a menos cien por ciento. Se pausa al pasar el puntero o enfocar, se puede invertir y detiene al reducir el movimiento.
Incluye
Un solo archivo React + TypeScript, con los estilos dentro. No usa Tailwind ni bibliotecas externas.
- Duración, separación y dirección configurables
- Bordes que se desvanecen (opcional)
- Pausa al pasar el puntero o enfocar
- La copia duplicada se oculta a lectores de pantalla
Cómo usarlo
Pasa tus elementos como hijos. Usa duration más alto para ir más despacio y reverse para invertir el sentido.