Cómo crear una sección about con parallax al hacer scroll en React
Una sección about con parallax al hacer scroll en React usa useScroll y useTransform de Framer Motion para desplazar la imagen verticalmente mientras el usuario hace scroll por la sección, creando una ilusión de profundidad. El contenedor de la imagen recorta el overflow mientras un motion.div interior se traslada en un rango de -6%/+6% mapeado a la progresión del scroll.
- Stack: React 18 + Framer Motion 11, ~334 líneas, cero dependencias de iconos.
- API principal: useScroll (target + offset), useTransform, stagger con whileInView.
- Accesible: los puntos y líneas decorativos llevan aria-hidden="true"; el slot de imagen usa un aria-label.
- Responsive: la grilla auto-fit se reduce a una sola columna en viewports estrechos; el parallax es independiente del viewport.
- La fila de estadísticas es opcional; pasa un array vacío para omitirla por completo.
About Parallax Image es una sección React de dos columnas diseñada para páginas de misión y empresa. La columna izquierda contiene un marco de imagen cuyo relleno interior se desplaza ligeramente al hacer scroll, aportando sensación de profundidad sin ninguna librería 3D pesada. La columna derecha apila una etiqueta, un título de peso mixto con una palabra de acento en serif itálica, un párrafo de cuerpo y una fila opcional de cifras clave.
Anatomía
La sección exterior es una grilla CSS con `repeat(auto-fit, minmax(300px, 1fr))`, no necesita ninguna media query de breakpoint porque las columnas se reorganizan de forma natural. El lado de la imagen (order 1) es un contenedor posicionado con siete elementos decorativos flotantes: cinco puntos y dos líneas horizontales, todos animados de forma independiente en bucles infinitos. Dentro hay un div redondeado con overflow:hidden que actúa como marco de recorte; el motion.div interior recibe el translateY parallax. El lado del texto (order 2) contiene cuatro elementos motion escalonados: etiqueta, h2, párrafo y la fila flex de estadísticas opcional.
Cómo funciona
Dos refs controlan el efecto. `sectionRef` se pasa a `useScroll` con `offset: ['start end', 'end start']`, esto mapea el rango de scroll desde que la parte superior de la sección entra en el viewport hasta que su parte inferior lo abandona. `useTransform` convierte esa progresión de 0 a 1 en un valor Y de `-6%` a `+6%` sobre el div interior de la imagen. Como el contenedor de la imagen recorta el overflow y el div interior está dimensionado a `inset: -8%`, siempre hay imagen suficiente para rellenar el marco en ambos extremos. Los puntos y líneas flotantes corren bucles `animate` de Framer Motion independientes con retardos escalonados; los elementos de texto usan `whileInView` con `once: true` para animarse una vez y permanecer visibles.
Cómo crearlo en React
Configurar el ref de seguimiento del scroll
Asocia un ref al elemento section exterior y pásalo a useScroll. El array offset le indica a Framer Motion que empiece el seguimiento cuando la parte superior de la sección entra por la parte inferior del viewport y que se detenga cuando la parte inferior sale por arriba.
const sectionRef = useRef<HTMLElement>(null); const { scrollYProgress } = useScroll({ target: sectionRef, offset: ["start end", "end start"], });Mapear la progresión del scroll a una traslación Y
useTransform convierte el valor de progresión de 0-1 en una cadena de porcentaje que el navegador puede aplicar directamente como transform CSS. Mantén el rango pequeño, ±6% basta para un toque premium sutil sin que parezca un bug.
const imageY = useTransform(scrollYProgress, [0, 1], ["-6%", "6%"]);Recortar el marco y aplicar el motion value
Envuelve la imagen en un div con overflow:hidden y border-radius. Dentro, renderiza un motion.div con el valor imageY y ajusta inset a -8% para que el relleno sobredimensionado nunca deje un hueco en ninguno de los extremos del rango parallax.
<div style={{ overflow: "hidden", borderRadius: "var(--radius-xl)" }}> <motion.div style={{ y: imageY, position: "absolute", inset: "-8%" }}> {/* image or gradient fill */} </motion.div> </div>Escalonar la aparición del texto con whileInView
Cada elemento de texto parte de un estado inicial x:20/opacity:0 y se anima hacia x:0/opacity:1 cuando entra en el viewport. Incrementa el retardo en unos 80ms por elemento para que etiqueta, título, cuerpo y estadísticas aparezcan en secuencia en lugar de todos a la vez.
<motion.h2 initial={{ opacity: 0, x: 24 }} whileInView={{ opacity: 1, x: 0 }} viewport={{ once: true }} transition={{ duration: 0.55, delay: 0.12, ease: [0.16, 1, 0.3, 1] }} >
Cuándo usarlo
Esta sección encaja mejor en páginas de agencia, portfolio y marketing SaaS donde la historia de marca o la misión necesitan peso visual. La imagen parallax aporta una sensación premium y editorial sin ninguna sobrecarga 3D. Evítala en páginas de documentación densas o donde la tasa de rebote sea crítica, la animación añade carga y distracción. Sustituye el degradado placeholder por una foto real del equipo o una captura de producto para lograr el impacto completo.
Usado por
- Stripe, Usa diseños de columnas divididas con una sutil profundidad de imagen controlada por el scroll en sus páginas de producto y empresa.
- Notion, Las páginas about y de equipo combinan tipografía editorial con elementos decorativos flotantes y visuales superpuestos al hacer scroll.
- Loom, Las secciones de empresa y misión usan divisiones de dos columnas con filas de estadísticas y profundidad de imagen influida por el parallax.
- Pitch, Las páginas de marketing y about incorporan palabras de acento en serif itálica en los títulos, junto a paneles de imagen animados al hacer scroll.
FAQ
¿Cómo cambio el degradado placeholder por una imagen real?
Sustituye el fondo degradado del motion.div interior por un background-image o una etiqueta <img>. Mantén el inset: -8% y el overflow:hidden en el contenedor exterior para que el parallax conserve margen de movimiento sin mostrar huecos.
¿Funciona el efecto parallax en móvil?
Sí, useScroll detecta el scroll táctil, así que el parallax funciona en teléfonos y tablets. La grilla se reduce a una sola columna automáticamente, apilando la imagen encima del texto.
¿Puedo quitar los puntos decorativos flotantes?
Elimina los elementos FloatingDot y FloatingLine del contenedor de la imagen. Son puramente decorativos y llevan aria-hidden, así que borrarlos no tiene ningún impacto funcional ni de accesibilidad.
¿Cómo añado la fila de estadísticas?
Pasa un array stats no vacío como prop: cada elemento es un objeto con una cadena value (p. ej. '200+') y una cadena label. La fila se renderiza automáticamente y desaparece cuando el array está vacío.