material 3 en un sitio personal: qué sobrevivió y qué no
dev · Oct 4, 2026 · 5 min read
este sitio funciona con material 3. no inspirado en él, no vagamente basado en él — los nombres de token reales, los esquemas de paleta reales, el lenguaje de formas real. quería saber si un design system construido para una app de teléfono sobrevive al contacto con un sitio personal, que tiene prioridades completamente distintas.
respuesta corta: sobrevivió alrededor del 70%, y el 30% que murió es la parte que más me alegra haber tirado.
qué entró
la capa de tokens, que es lo verdadero. --primary-container, --on-primary-container, --surface-variant, --outline-variant — esos son los nombres de m3, no nombres míos, y cada componente los consume en lugar de codificar un color. esta es la parte que más rindió, y no por razones estéticas.
rindió porque pasé el sitio entero de claro a oscuro y de vuelta, y cambié el acento, seis veces, mientras lo escribía. nada se rompió. no hay ningún if (dark) en mis componentes. cada color de la hoja de estilos se resuelve a través de una variable, y la paleta oscura es un segundo conjunto de valores para los mismos nombres.
los seis esquemas de paleta: tonal-spot, fidelity, content, neutral, expressive y fruit-salad. están en el diálogo de ajustes y todos funcionan, porque son como los llama m3 y no seis temas ajustados a mano.
la escala de formas. m3 tiene una escalera definida de radio de esquina y las cards se sitúan en su parte alta. mis cards son rounded-[2.4rem], los botones van completamente redondeados, las pastillas de navegación también. esta es la señal de m3 más reconocible y sobrevive sin problema a la traducción a un sitio personal.
el ripple, con la opacidad correcta:
opacity: var(--ripple-hover-opacity, 0.08);
0,08 es el valor de la capa de estado de m3. se siente casi demasiado sutil, y eso es correcto — el punto de la capa de estado es que no deberías darte cuenta conscientemente.
el ámbito del ripple. esta fue la parte que no sabía que necesitaba. el ripple solo sigue al puntero dentro del elemento que pulsaste de verdad, no en toda la página. hace que los clics rápidos se sientan precisos en lugar de descuidados.
los componentes que tenían sentido como pequeñas versiones web: interruptor, deslizador, campo de texto, y dos barras de desplazamiento, una para la ventana y una para los paneles. son victorias puras.
qué tiré
la elevación. m3 define seis niveles, del 0 al 5, con una sombra concreta para cada uno. no uso ninguno. no hay ni un token de elevación en mi hoja de estilos, y las únicas sombras son estados de hover en cards y botones — nada que describa a qué altura está una superficie.
no fue pereza, fue una decisión. el modelo de elevación de m3 asume superficies opacas apiladas unas sobre otras. este sitio tiene una barra lateral translúcida con desenfoque de fondo, y contenido desplazándose por debajo. la elevación es una metáfora de profundidad para planos opacos; cuando el plano es transparente, la sombra miente sobre qué está encima de qué. así que aquí separan los bordes, no las sombras.
los valores de elevación de m3 son buenos y copié el espíritu — bordes en --outline-variant, radio en la parte alta de la escala — sin copiar los tokens.
la escala tipográfica. m3 tiene cinco roles: display, headline, title, body, label, cada uno con tres tamaños. uso aproximadamente dos de ellos, porque un rol display dimensionado para un teléfono te da unos 57px, que no es un titular en una pantalla ancha. la escala no sobrevive al salto de una ventana de 6 pulgadas a una de 2560px sin reescalarse, y una vez reescalada ya no estás usando la escala de m3, estás usando la tuya que se le parece.
me quedé con la idea — un único tipo expresivo para los momentos grandes, un monoespaciado para las superficies de desarrollo, un sans sencillo para el texto — y tiré la rampa concreta.
la que nunca funcionó
el movimiento.
m3 especifica duraciones y curvas de interpolación, y están ajustadas para un teléfono: cortas, porque un pulgar está cerca de la pantalla. en un sitio de escritorio guiado por el puntero esas mismas curvas se sienten perezosas de un modo difícil de explicar con palabras. mi ojo no está donde estaría mi pulgar.
el problema mayor es que las especificaciones cargadas de movimiento asumen un presupuesto de fotogramas fiable. no asumen que el presupuesto de fotogramas pueda ser cero.
choqué con esto de golpe. mi animación de colapso de la barra lateral dejó de funcionar en silencio: la caja se quedaba a ancho completo, para siempre, sin ningún error en ninguna parte. la causa no era la lógica de la animación sino una proyección de diseño peleando con una transición de ancho sobre el mismo elemento — dos cosas intentando poseer la caja, y la perdedora nunca alcanzaba su valor final. y la única razón por la que lo encontré fue medir el ancho calculado en vez de confiar en que el código «parecía correcto».
moví el ancho de un valor de motion a una transición css normal, y borré la proyección de diseño. la caja ahora alcanza su objetivo en 60ms, medido, siempre.
la lección no tenía que ver con framer motion. era que un design system te dice cómo es un estado terminado y no dice nada de cómo llegar a él cuando el presupuesto de fotogramas colapsa. para una app de teléfono esa suposición se cumple. para una página web corriendo en una pestaña que alguien podría haber puesto en segundo plano, no.
qué me quedaría si empezara de nuevo
la capa de tokens, sin dudarlo. es la parte de m3 realmente reutilizable fuera de android, y el motivo es aburrido: es un esquema de nombres que te obliga a responder «cuál es el papel de este color» en lugar de «qué color es». esa pregunta merece la pena incluso si nunca abres la documentación de material.
los esquemas de paleta y la escala de formas, porque son gratis una vez que existen los tokens.
la opacidad de la capa de estado, porque es un solo número y es correcto.
y la elevación, la rampa tipográfica y las curvas de movimiento, fuera, sin remordimiento — son suposiciones sobre un contexto en el que este sitio no está.
el resumen honesto: m3 es una respuesta muy buena a «cómo se ve y se siente una app android nativa», y un punto de partida decente para un design system web, siempre que estés dispuesto a tratarlo como vocabulario en lugar de como especificación. los tokens se transfieren. los valores en píxeles no.