Volver al blog

Framer Motion para landing pages: guía completa de animación

Publicado el 20 de marzo de 2026·7 min read

Las landing pages estáticas convierten. Las animadas convierten mejor. Un movimiento sutil guía la mirada, refuerza la jerarquía y hace que las interacciones se sientan intencionadas en lugar de bruscas. Framer Motion es la librería de animación de referencia en React, y en esta guía repasamos los cinco patrones de animación que más importan en una landing page.

¿Por qué Framer Motion?

Las animaciones CSS resuelven bien las transiciones simples. Pero en cuanto necesitas reveals disparados por scroll, secuencias orquestadas con stagger, animaciones de layout o interacciones basadas en gestos, el CSS puro se vuelve difícil de manejar. Framer Motion te ofrece una API declarativa que encaja de forma natural con el modelo de componentes de React:

npm install motion

Desde la v11, el paquete se publica como motion (antes framer-motion). En proyectos nuevos, importa desde "motion/react":

import { motion } from "motion/react";

1. Animaciones de entrada

El patrón más habitual: hacer que los elementos aparezcan con un fundido y deslizamiento al cargar la página. Usa las props initial y animate en los componentes motion:

"use client";

import { motion } from "motion/react";

const ease = [0.16, 1, 0.3, 1] as const;

export function HeroHeadline() {
  return (
    <motion.h1
      initial={{ opacity: 0, y: 32 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.7, ease }}
      className="text-5xl font-bold tracking-tight"
    >
      Ship faster with production-ready sections
    </motion.h1>
  );
}

La curva cubic bezier [0.16, 1, 0.3, 1] produce una sensación de entrada rápida y salida lenta que popularizó Apple. Resulta ágil sin ser abrupta, mucho mejor que la curva ease por defecto para entradas de UI.

Aplica este patrón en las secciones hero, donde el titular, el subtítulo y el botón CTA aparecen uno tras otro en secuencia.

2. Animaciones disparadas por scroll

Las animaciones de entrada se ejecutan al montar el componente. Para las secciones que quedan por debajo del pliegue, conviene disparar la animación cuando el usuario llega a ellas con el scroll. La prop whileInView de Framer Motion se encarga de eso:

<motion.div
  initial={{ opacity: 0, y: 24 }}
  whileInView={{ opacity: 1, y: 0 }}
  transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1] }}
  viewport={{ once: true, margin: "-100px" }}
>
  <h2>Features that matter</h2>
  <p>Everything you need to ship a landing page in hours, not weeks.</p>
</motion.div>

Detalles clave:

  • viewport.once: true: la animación se ejecuta una sola vez y se queda en su estado final. Sin esto, volver hacia arriba la reinicia, lo que da una sensación defectuosa.
  • viewport.margin: "-100px": dispara la animación 100px antes de que el elemento entre en el viewport. Así la animación ya está en marcha cuando el usuario la ve.

Este es el patrón estándar para secciones de features y bloques de testimonios.

3. Hijos escalonados

Una rejilla de tarjetas de features que se anima toda de golpe se ve plana. Escalonarlas, haciendo que cada hijo aparezca 80ms después del anterior, crea un ritmo visual. Usa variants con staggerChildren:

"use client";

import { motion } from "motion/react";

const containerVariants = {
  hidden: {},
  visible: {
    transition: {
      staggerChildren: 0.08,
    },
  },
};

const itemVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.5, ease: [0.16, 1, 0.3, 1] },
  },
};

export function FeaturesGrid({ features }: { features: { title: string; description: string }[] }) {
  return (
    <motion.div
      variants={containerVariants}
      initial="hidden"
      whileInView="visible"
      viewport={{ once: true, margin: "-80px" }}
      className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3"
    >
      {features.map((feature) => (
        <motion.div
          key={feature.title}
          variants={itemVariants}
          className="rounded-2xl border border-border bg-card p-6"
        >
          <h3 className="text-lg font-semibold">{feature.title}</h3>
          <p className="mt-2 text-muted-foreground">{feature.description}</p>
        </motion.div>
      ))}
    </motion.div>
  );
}

El padre define la orquestación (staggerChildren) y cada hijo define su propia animación (itemVariants). El whileInView del padre dispara tanto el contenedor como todos los hijos en secuencia. Sin useEffect, sin IntersectionObserver, solo props declarativas.

4. Transiciones de página

Las single-page apps pueden animar el paso entre rutas con AnimatePresence. En el App Router de Next.js, envuelve el contenido de la página en un AnimatePresence a nivel de layout:

"use client";

import { AnimatePresence, motion } from "motion/react";
import { usePathname } from "next/navigation";

export function PageTransition({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();

  return (
    <AnimatePresence mode="wait">
      <motion.div
        key={pathname}
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
        transition={{ duration: 0.25 }}
      >
        {children}
      </motion.div>
    </AnimatePresence>
  );
}

La prop mode="wait" garantiza que la página saliente se desvanezca por completo antes de que aparezca la entrante. Sin ella, ambas páginas se renderizan a la vez durante la transición, provocando saltos en el layout.

Advertencia: las transiciones de página en el App Router requieren componentes cliente a nivel de layout, lo que significa que esas páginas pierden las ventajas del streaming de Server Components. Usa este patrón con criterio, en sitios de marketing donde cada página es ligera, no en dashboards con muchos datos.

5. Efectos hover

Los elementos interactivos deberían responder al hover y al tap. Las props whileHover y whileTap de Framer Motion lo hacen trivial:

<motion.button
  whileHover={{ scale: 1.03 }}
  whileTap={{ scale: 0.97 }}
  transition={{ type: "spring", stiffness: 400, damping: 17 }}
  className="rounded-xl bg-primary px-6 py-3 text-lg font-semibold text-primary-foreground"
>
  Get started
</motion.button>

La física de spring produce un rebote que se siente natural. Los valores stiffness: 400, damping: 17 dan una sensación rápida y responsiva sin oscilación excesiva. Para las tarjetas, combina el escalado en hover con una ligera elevación de la sombra:

<motion.div
  whileHover={{ y: -4, boxShadow: "0 12px 24px rgba(0,0,0,0.1)" }}
  transition={{ duration: 0.2 }}
  className="rounded-2xl border border-border bg-card p-6"
>
  {/* card content */}
</motion.div>

Consejos de rendimiento

  • Usa solo transform y opacity. Framer Motion las anima por defecto en el hilo del compositor de la GPU. Animar width, height o background-color dispara layout o paint, ambos más lentos.
  • Añade will-change: transform a los elementos con animaciones complejas. Framer Motion lo hace automáticamente para los componentes motion, pero verifícalo en DevTools si notas tirones.
  • viewport.once: true no es solo cuestión de UX: también desconecta el IntersectionObserver tras dispararse, reduciendo la carga en tiempo de ejecución en páginas con mucho scroll.
  • Carga de forma diferida las secciones animadas por debajo del pliegue con next/dynamic, para que el código de animación no entre en el bundle inicial.

Consigue secciones animadas listas para usar

Escribir el código de animación desde cero para cada sección lleva mucho tiempo. El catálogo de Incubator incluye más de 844 variantes de secciones: heroes, rejillas de features, testimonios, tablas de precios, CTAs y más, muchas con animaciones de Framer Motion ya integradas. Explora las secciones hero y las secciones de features para ver en acción las entradas disparadas por scroll, las rejillas escalonadas y los efectos hover. Copia el código, ajusta el contenido y publica.

Relacionado en incubator

VA

Victor Aubague

Desarrollador y creador de Incubator

Desarrollador full-stack especializado en React, Next.js y TypeScript. Creé Incubator para ayudar a los desarrolladores a lanzar interfaces bonitas más rápido, todos los componentes provienen de proyectos reales de clientes y de código en producción.

LinkedIn

Related articles

Framer Motion para landing pages: guía completa de animación