CSS-in-JS sin runtime: experiencia de desarrollo y rendimiento excepcional
1. La “doble cara” de CSS-in-JS
Las soluciones CSS-in-JS, como styled-components y Emotion, transformaron la gestión de estilos en el desarrollo basado en componentes al permitir escribir CSS dentro de archivos JavaScript o TypeScript. Aportan numerosas ventajas:
- Ámbito de componente: Los estilos quedan asociados al componente de forma predeterminada, lo que resuelve los conflictos globales de nombres CSS.
- Estilos dinámicos: Se pueden crear fácilmente estilos dinámicos a partir de las props o el state del componente.
- Código conjunto: Los estilos y la lógica del componente viven en el mismo archivo, lo que facilita su mantenimiento y organización.
Sin embargo, estas comodidades no son gratuitas. El núcleo de las bibliotecas CSS-in-JS tradicionales es el runtime. Cuando un componente se monta en el navegador, el runtime JavaScript de la biblioteca CSS-in-JS:
- Analiza el CSS de los template strings o los objetos.
- Genera nombres de clase únicos.
- Inyecta dinámicamente los estilos en el
<head>del documento, dentro de etiquetas<style>.
Este proceso aumenta el tamaño del paquete JavaScript y añade cierto coste computacional durante el arranque y el renderizado de la aplicación, lo que afecta al rendimiento.
2. La salida del “runtime cero”
Para resolver el problema del rendimiento en tiempo de ejecución, la comunidad propuso un enfoque nuevo: CSS-in-JS sin runtime (Zero-Runtime).
La idea central es conservar la experiencia de desarrollo de CSS-in-JS, pero completar todo el trabajo durante la compilación (build time). Una herramienta de compilación, normalmente un plugin de Babel o Vite, analiza el código, encuentra todos los usos de CSS-in-JS y entonces:
- Extrae el texto CSS.
- Genera archivos
.cssestáticos. - Sustituye el código CSS-in-JS original por nombres de clase únicos generados.
Como resultado, el paquete JavaScript entregado al navegador no contiene ninguna biblioteca CSS-in-JS en tiempo de ejecución, y el resultado equivale a archivos CSS estáticos escritos a mano y altamente optimizados.
3. Principales soluciones sin runtime
a. Linaria
Linaria es una de las pioneras del CSS-in-JS sin runtime. Permite utilizar la conocida sintaxis de template literals etiquetados con styled.
// YourComponent.js
import { styled } from '@linaria/react';
const Title = styled.h1`
font-size: 2rem;
color: tomato;
`;
// 构建时,这会被转换为:
// <h1 class="Title_a1b2c3d">...</h1>
//
// 并在一个静态 .css 文件中生成:
// .Title_a1b2c3d {
// font-size: 2rem;
// color: tomato;
// }b. vanilla-extract
Desarrollado por el equipo de SEEK, vanilla-extract va un paso más allá y utiliza TypeScript para crear estilos completamente seguros en cuanto a tipos. Todas las definiciones de estilo son variables exportadas desde archivos .css.ts, con una potente inferencia de tipos y autocompletado.
// styles.css.ts
import { style } from '@vanilla-extract/css';
export const title = style({
fontSize: '2rem',
color: 'tomato',
});c. Panda CSS
Panda CSS es un competidor más reciente. Inspirado en Tailwind CSS, ofrece una experiencia de desarrollo basada en “Style Props” y, al mismo tiempo, garantiza una salida sin runtime.
import { css } from '../styled-system/css';
function MyComponent() {
return <div className={css({ fontSize: '2rem', color: 'tomato' })} />;
}4. Ventajas y compromisos
Ventajas:
- Rendimiento excepcional: El resultado final es CSS estático, sin coste de un runtime JavaScript.
- Paquetes más pequeños: No es necesario cargar una biblioteca CSS-in-JS en el cliente.
- Potente experiencia de desarrollo: Se mantienen las ventajas del ámbito por componente, la seguridad de tipos de TypeScript y la colocación conjunta del código.
Compromisos:
- Dependencia durante la compilación: Debe integrarse en el proceso de build, por lo que la configuración resulta algo más compleja.
- Dinamismo limitado: No puede generar estilos completamente nuevos a partir de valores que solo existen en tiempo de ejecución, como datos procedentes de una API. No obstante, técnicas como las variables CSS pueden cubrir la mayoría de los casos dinámicos.
Conclusión
El CSS-in-JS sin runtime es una corrección del rumbo del paradigma CSS-in-JS tradicional. Separa de forma inteligente la “experiencia durante el desarrollo” del “rendimiento en tiempo de ejecución”, para que ya no tengamos que elegir entre ambos. Para las aplicaciones web modernas que buscan un rendimiento extremo y paquetes más pequeños, ofrece una solución casi perfecta.