Cómo crear una sección about estilo magazine editorial en React
Una sección about estilo magazine editorial en React combina una cuadrícula CSS de 12 columnas con animaciones whileInView escalonadas de Framer Motion. El layout combina una gran imagen hero con un pull quote, y luego fluye hacia texto multicolumna y un bloque de stats junto a una segunda imagen de retrato.
- Stack: React + Framer Motion + Tailwind v4, ~70 líneas, cero dependencias adicionales.
- Animación: fade+slide activado al entrar en el viewport (whileInView, once:true) con retardos escalonados de 0,1 a 0,5 s.
- Layout: cuadrícula de 12 columnas en pantallas grandes, apilado en una sola columna en móvil, totalmente responsive.
- Accesible: blockquote semántico, jerarquía de encabezados preservada, color mediante CSS custom properties únicamente.
- Las imágenes son opcionales: los marcadores de posición usan var(--color-background-alt) si no se pasa ninguna URL.
Este componente lleva la densidad visual de las revistas editoriales impresas a una sección about en React. Una cuadrícula de 12 columnas rompe la simetría a propósito: una amplia imagen hero ancla un lado, un pull quote flota enfrente, el cuerpo de texto se divide en tres columnas y una columna de stats cierra junto a una segunda imagen de retrato. Cada bloque aparece en fundido al hacer scroll con un retardo escalonado, así la sección se construye sola a medida que el usuario lee hacia abajo.
Anatomía
El componente tiene cuatro bandas verticales. Primero, un bloque de cabecera (max-w-3xl) contiene el badge y el encabezado principal, alineado a la izquierda sin centrar, como una dateline de revista. Después, una cuadrícula de 12 columnas se divide en 7/5: la celda izquierda muestra la primera imagen en relación 4:3; la celda derecha, centrada verticalmente, contiene un pull quote en cursiva serif con borde izquierdo. Luego una cuadrícula responsive de 1 a 3 columnas distribuye cada párrafo en su propia columna de texto. Por último, otra división de 12 columnas (4/8) combina una lista vertical de stats a la izquierda con una imagen de retrato más alta a la derecha.
Cómo funciona
Cada bloque principal se envuelve en un motion.div con initial={{ opacity: 0, y: 30 }} y whileInView={{ opacity: 1, y: 0 }}. La opción viewport once:true dispara cada animación una sola vez y libera el listener. Los retardos aumentan 0,1 s por bloque (0,1, 0,2, 0,3, 0,4, 0,5), creando un flujo de lectura natural sin cálculos de posición de scroll. Las columnas de la cuadrícula se definen con las utilidades Tailwind lg:col-span-* sobre un padre de 12 columnas, así que la asimetría es CSS puro, sin lógica de layout en JavaScript.
Cómo crearlo en React
Configurar el contenedor de cuadrícula de 12 columnas
Envuelve la banda imagen+cita en un div con `grid grid-cols-1 lg:grid-cols-12 gap-8`. Asigna `lg:col-span-7` a la celda de imagen y `lg:col-span-5` a la celda de cita. El contenedor padre max-w-6xl se encarga del centrado horizontal.
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8"> <div className="lg:col-span-7">/* image */</div> <div className="lg:col-span-5 flex flex-col justify-center">/* quote */</div> </div>Añadir el pull quote con un blockquote semántico
Usa un `<blockquote>` nativo con un borde izquierdo controlado por `var(--color-accent)` y texto en cursiva serif. Un `<p>` aparte debajo lleva la atribución del autor. Ambos se renderizan de forma condicional: si no se pasa la prop pullQuote, no aparece ninguno.
<blockquote className="text-xl md:text-2xl font-serif italic leading-relaxed border-l-2 pl-6" style={{ color: "var(--color-foreground)", borderColor: "var(--color-accent)" }} > {pullQuote} </blockquote>Conectar las animaciones whileInView escalonadas
Reemplaza cada `div` por un `motion.div` y pasa `initial={{ opacity: 0, y: 30 }}`, `whileInView={{ opacity: 1, y: 0 }}`, `viewport={{ once: true }}` y un `transition={{ duration: 0.6, delay: N }}`. Incrementa el retardo en 0,1 s para cada bloque sucesivo para que caigan en cascada hacia abajo.
<motion.div initial={{ opacity: 0, y: 30 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.6, delay: 0.3 }} >Renderizar la columna de stats
Mapea el array `stats` en una pila `space-y-8`. Cada elemento muestra el `value` en un gran encabezado con color de acento y el `label` en texto pequeño atenuado debajo. Combina esta columna (col-span-4) con la segunda imagen (col-span-8) usando el mismo patrón de cuadrícula de 12 columnas del paso 1.
{stats.map((stat, i) => ( <div key={i}> <p className="text-3xl font-bold" style={{ color: "var(--color-accent)" }}>{stat.value}</p> <p className="text-sm mt-1" style={{ color: "var(--color-foreground-muted)" }}>{stat.label}</p> </div> ))}
Cuándo usarlo
Úsalo cuando la historia de marca necesita peso visual: agencias, estudios, SaaS premium, blogs editoriales. La cuadrícula asimétrica y el pull quote transmiten un cuidado y una intencionalidad que un layout de dos columnas centrado no puede comunicar. Evítalo en páginas de marketing ligeras donde el tiempo en pantalla es corto: las revelaciones escalonadas exigen que el usuario recorra toda la sección, así que recompensan a los lectores más que a los que solo ojean. En páginas con objetivos de conversión estrictos, un bloque about más compacto sin retardo de animación rendirá mejor.
Usado por
- Stripe, Página about multibloque que mezcla gran fotografía, declaraciones estilo pull quote y stats numéricas en una cuadrícula editorial.
- Loom, Cuadrícula imagen-texto asimétrica con métricas en negrita usada para contar la historia de crecimiento de la empresa.
- Notion, Secciones de estilo editorial que combinan fotografía con declaraciones de misión y cifras clave, reveladas progresivamente al hacer scroll.
FAQ
¿Se pueden usar más de dos imágenes?
El componente acepta image1 e image2 como props separadas. Para añadir más imágenes, amplía la interfaz de props e inserta bloques de imagen motion.div adicionales en la cuadrícula: el sistema de 12 columnas ofrece suficiente flexibilidad para colocarlas en col-span-4, 6 u 8 según haga falta.
¿Cómo desactivo las animaciones al hacer scroll para un render estático?
Reemplaza cada motion.div por un div normal. El layout y los estilos son independientes de Framer Motion: quitar los wrappers de animación no cambia nada visualmente en reposo.
El array paragraphs solo tiene dos elementos, ¿por qué usa una cuadrícula de 3 columnas?
La cuadrícula siempre tiene 3 columnas en pantallas grandes sin importar cuántos párrafos haya en el array. Con dos elementos, la tercera columna queda vacía: es un espacio en blanco intencionado. Pasa tres párrafos para llenarla, o cambia lg:grid-cols-3 por lg:grid-cols-2 si siempre proporcionas dos párrafos.
¿La opción viewport once:true causa problemas con las transiciones de página?
Con once:true, cada bloque se anima en la primera entrada y nunca se vuelve a reproducir. En cargas de página estándar es el comportamiento correcto. Si tu aplicación usa navegación del lado del cliente y vuelve a montar el componente al navegar hacia atrás, Framer Motion volverá a disparar la animación porque el componente se monta de nuevo realmente, así que once:true sigue siendo correcto.