CSS en TypeScript con extracto de vainilla

Nodo de origen: 1121024

extracto de vainilla es una nueva biblioteca CSS-in-TypeScript independiente del marco. Es una forma ligera, robusta e intuitiva de escribir sus estilos. vainilla-extract no es un marco CSS prescriptivo, sino una pieza flexible de herramientas para desarrolladores. Las herramientas CSS han sido un espacio relativamente estable en los últimos años con PostCSS, Hablar con descaro a, Módulos CSSy componentes-estilizados todos salieron antes de 2017 (algunos mucho antes de eso) y seguir siendo popular . Tailwind es una de las pocas herramientas que ha revolucionado las herramientas CSS en los últimos años.

El extracto de vainilla tiene como objetivo sacudir las cosas nuevamente. Se lanzó este año y tiene la ventaja de poder aprovechar algunas tendencias recientes, que incluyen:

  • Desarrolladores de JavaScript que cambian a TypeScript
  • Soporte del navegador para propiedades personalizadas de CSS
  • Estilo de utilidad primero

Hay un montón de innovaciones inteligentes en el extracto de vainilla que creo que lo convierten en un gran problema.

Tiempo de ejecución cero

Las bibliotecas CSS-in-JS generalmente inyectan estilos en el documento en tiempo de ejecución. Esto tiene beneficios, que incluyen CSS crítico extracción y peinado dinámico.

Pero como regla general, un archivo CSS separado será más eficaz. Esto se debe a que el código JavaScript debe pasar por un análisis / compilación más costoso, mientras que un archivo CSS separado se puede almacenar en caché mientras que el protocolo HTTP2 reduce el costo de la solicitud adicional. También, propiedades personalizadas ahora puede proporcionar una gran cantidad de estilo dinámico de forma gratuita.

Entonces, en lugar de inyectar estilos en tiempo de ejecución, el extracto de vainilla toma después Linária y astroturf. Estas bibliotecas le permiten crear estilos utilizando funciones de JavaScript que se extraen en el momento de la compilación y se utilizan para construir un archivo CSS. Aunque escribe extracto de vainilla en TypeScript, no afecta el tamaño general de su paquete de producción de JavaScript.

Mecanografiado

Una gran propuesta de valor de extracto de vainilla es que te pones a escribir. Si es lo suficientemente importante como para mantener el resto de su código base seguro, ¿por qué no hacer lo mismo con sus estilos?

TypeScript ofrece una serie de beneficios. Primero, está el autocompletado. Si escribe "fo", en un editor compatible con TypeScript, obtendrá una lista de opciones de fuentes en un menú desplegable: fontFamily, fontKerning, fontWeight, o cualquier otra cosa que coincida, para elegir. Esto hace que las propiedades de CSS sean detectables desde la comodidad de su editor. Si no recuerdas el nombre de fontVariant pero sepa que va a comenzar con la palabra "fuente", la escribe y desplácese por las opciones. En VS Code, no necesita descargar ninguna herramienta adicional para que esto suceda.

Esto realmente acelera la creación de estilos:

También significa que su editor está mirando por encima del hombro para asegurarse de que no cometa ningún error de ortografía que pueda causar errores frustrantes.

Los tipos de extracto de vainilla también proporcionan una explicación de la sintaxis en su definición de tipo. y un enlace a la Documentación MDN para la propiedad CSS que está editando. Esto elimina un paso de buscar frenéticamente en Google cuando los estilos se comportan de forma inesperada.

Imagen de VSCode con el cursor sobre la propiedad fontKerning y una ventana emergente que describe lo que hace la propiedad con un enlace a la documentación de Mozilla para la propiedad

Escribir en TypeScript significa que está usando nombres de mayúsculas y minúsculas para las propiedades de CSS, como backgroundColor. Esto podría suponer un pequeño cambio para los desarrolladores que utilizan la sintaxis CSS normal, como background-color.

Integraciones

vainilla-extract proporciona integraciones de primera clase para todos los paquetes más nuevos. Aquí hay una lista completa de integraciones actualmente admite:

  • paquete web
  • esconstruir
  • tornillo
  • la capa de nieve
  • SiguienteJS
  • Gatsby

También es completamente independiente del marco. Todo lo que necesita hacer es importar nombres de clases de vanilla-Extract, que se convierten en una cadena en el momento de la compilación.

Uso

Para usar el extracto de vainilla, escribe un .css.ts archivo que sus componentes pueden importar. Las llamadas a estas funciones se convierten en cadenas de nombres de clase con hash y ámbito en el paso de compilación. Esto puede sonar similar a Módulos CSS, y esto no es una coincidencia: el creador de vainilla-Extract, marca dalgleish, también es co-creador de módulos CSS.

style()

Puede crear una clase CSS de ámbito automático utilizando el style() función. Pasas los estilos del elemento y luego exportas el valor devuelto. Importe este valor en algún lugar de su código de usuario y se convertirá en un nombre de clase con ámbito.

// title.css.ts
import {style} from "@vanilla-extract/css"; export const titleStyle = style({ backgroundColor: "hsl(210deg,30%,90%)", fontFamily: "helvetica, Sans-Serif", color: "hsl(210deg,60%,25%)", padding: 30, borderRadius: 20,
});
// title.ts
import {titleStyle} from "./title.css"; document.getElementById("root").innerHTML = `<h1 class="${titleStyle}">Vanilla Extract</h1>`;

Las consultas de medios y los pseudo selectores también se pueden incluir dentro de las declaraciones de estilo:

// title.css.ts
backgroundColor: "hsl(210deg,30%,90%)",
fontFamily: "helvetica, Sans-Serif",
color: "hsl(210deg,60%,25%)",
padding: 30,
borderRadius: 20, "@media": { "screen and (max-width: 700px)": { padding: 10 }
}, ":hover":{ backgroundColor: "hsl(210deg,70%,80%)"
}

Estas style Las llamadas a funciones son una abstracción delgada sobre CSS: todos los nombres y valores de propiedad se asignan a las propiedades y valores de CSS con los que está familiarizado. Un cambio al que hay que acostumbrarse es que los valores a veces se pueden declarar como un número (p. Ej. padding: 30) cuyo valor predeterminado es un valor de unidad de píxel, mientras que algunos valores deben declararse como una cadena (p. ej. padding: "10px 20px 15px 15px").

Las propiedades que van dentro de la función de estilo solo pueden afectar a un único nodo HTML. Esto significa que no puede usar el anidamiento para declarar estilos para los hijos de un elemento, algo a lo que podría estar acostumbrado en Hablar con descaro a or PostCSS. En su lugar, debe diseñar a los niños por separado. Si un elemento hijo necesita diferentes estilos basado en el padre, puede usar el selectors propiedad para agregar estilos que dependen del padre:

// title.css.ts
export const innerSpan = style({ selectors:{[`${titleStyle} &`]:{ color: "hsl(190deg,90%,25%)", fontStyle: "italic", textDecoration: "underline" }}
});
// title.ts
import {titleStyle,innerSpan} from "./title.css";
document.getElementById("root").innerHTML = `<h1 class="${titleStyle}">Vanilla <span class="${innerSpan}">Extract</span></h1>
<span class="${innerSpan}">Unstyled</span>`;

O también puede usar la API de Theming (que veremos a continuación) para crear propiedades personalizadas en el elemento principal que consumen los nodos secundarios. Esto puede parecer restrictivo, pero se ha dejado intencionalmente de esta manera para aumentar la capacidad de mantenimiento en bases de código más grandes. Significa que sabrá exactamente dónde se han declarado los estilos para cada elemento de su proyecto.

Theming

Puede utilizar el createTheme función para construir variables en un objeto TypeScript:

// title.css.ts
import {style,createTheme } from "@vanilla-extract/css"; // Creating the theme
export const [mainTheme,vars] = createTheme({ color:{ text: "hsl(210deg,60%,25%)", background: "hsl(210deg,30%,90%)" }, lengths:{ mediumGap: "30px" }
}) // Using the theme
export const titleStyle = style({ backgroundColor:vars.color.background, color: vars.color.text, fontFamily: "helvetica, Sans-Serif", padding: vars.lengths.mediumGap, borderRadius: 20,
});

Luego, el extracto de vainilla te permite hacer una variante de tu tema. TypeScript lo ayuda a garantizar que su variante use los mismos nombres de propiedad, por lo que recibirá una advertencia si olvida agregar el background propiedad al tema.

Imagen de VS Code donde se muestra un tema que se declara pero falta la propiedad de fondo, lo que provoca una gran cantidad de líneas onduladas rojas para advertir que la propiedad se ha olvidado

Así es como puede crear un tema normal y un modo oscuro:

// title.css.ts
import {style,createTheme } from "@vanilla-extract/css"; export const [mainTheme,vars] = createTheme({ color:{ text: "hsl(210deg,60%,25%)", background: "hsl(210deg,30%,90%)" }, lengths:{ mediumGap: "30px" }
})
// Theme variant - note this part does not use the array syntax
export const darkMode = createTheme(vars,{ color:{ text:"hsl(210deg,60%,80%)", background: "hsl(210deg,30%,7%)", }, lengths:{ mediumGap: "30px" }
})
// Consuming the theme export const titleStyle = style({ backgroundColor: vars.color.background, color: vars.color.text, fontFamily: "helvetica, Sans-Serif", padding: vars.lengths.mediumGap, borderRadius: 20,
});

Luego, usando JavaScript, puede aplicar dinámicamente los nombres de clase devueltos por vainilla-extract para cambiar de tema:

// title.ts
import {titleStyle,mainTheme,darkMode} from "./title.css"; document.getElementById("root").innerHTML = `<div class="${mainTheme}" id="wrapper"> <h1 class="${titleStyle}">Vanilla Extract</h1> <button onClick="document.getElementById('wrapper').className='${darkMode}'">Dark mode</button>
</div>`

¿Cómo funciona esto bajo el capó? Los objetos que declaras en el createTheme La función se convierte en propiedades personalizadas de CSS adjuntas a la clase del elemento. Estas propiedades personalizadas tienen hash para evitar conflictos. El CSS de salida para nuestro mainTheme El ejemplo se ve así:

.src__ohrzop0 { --color-brand__ohrzop1: hsl(210deg,80%,25%); --color-text__ohrzop2: hsl(210deg,60%,25%); --color-background__ohrzop3: hsl(210deg,30%,90%); --lengths-mediumGap__ohrzop4: 30px;
}

Y la salida CSS de nuestro darkMode el tema se ve así:

.src__ohrzop5 { --color-brand__ohrzop1: hsl(210deg,80%,60%); --color-text__ohrzop2: hsl(210deg,60%,80%); --color-background__ohrzop3: hsl(210deg,30%,10%); --lengths-mediumGap__ohrzop4: 30px;
}

Entonces, todo lo que necesitamos cambiar en nuestro código de usuario es el nombre de la clase. Aplica el darkmode el nombre de la clase al elemento padre, y el mainTheme las propiedades personalizadas se cambian por darkMode queridos.

API de recetas

El style y createTheme Las funciones proporcionan suficiente poder para diseñar un sitio web por sí mismas, pero vainilla-extract proporciona algunas API adicionales para promover la reutilización. La API de recetas le permite crear un montón de variantes para un elemento, que puede elegir en su marcado o código de usuario.

Primero, debe instalarse por separado:

npm install @vanilla-extract/recipes

Así es como funciona. Importa el recipe función y pasar un objeto con las propiedades base y variants:

// button.css.ts
import { recipe } from '@vanilla-extract/recipes'; export const buttonStyles = recipe({ base:{ // Styles that get applied to ALL buttons go in here }, variants:{ // Styles that we choose from go in here }
});

Dentro de base, puede declarar los estilos que se aplicarán a todos variantes. Dentro variants, puede proporcionar diferentes formas de personalizar el elemento:

// button.css.ts
import { recipe } from '@vanilla-extract/recipes';
export const buttonStyles = recipe({ base: { fontWeight: "bold", }, variants: { color: { normal: { backgroundColor: "hsl(210deg,30%,90%)", }, callToAction: { backgroundColor: "hsl(210deg,80%,65%)", }, }, size: { large: { padding: 30, }, medium: { padding: 15, }, }, },
});

Luego puede declarar qué variante desea usar en el marcado:

// button.ts
import { buttonStyles } from "./button.css"; <button class=`${buttonStyles({color: "normal",size: "medium",})}`>Click me</button>

Y el extracto de vainilla aprovecha TypeScript para proporcionar autocompletado para su propio nombres de variantes!

Puede nombrar sus variantes como desee y poner las propiedades que desee en ellas, así:

// button.css.ts
export const buttonStyles = recipe({ variants: { animal: { dog: { backgroundImage: 'url("./dog.png")', }, cat: { backgroundImage: 'url("./cat.png")', }, rabbit: { backgroundImage: 'url("./rabbit.png")', }, }, },
});

Puede ver cómo esto sería increíblemente útil para construir un sistema de diseño, ya que puede crear componentes reutilizables y controlar las formas en que varían. Estas variaciones se vuelven fácilmente detectables con TypeScript; todo lo que necesita escribir es CMD/CTRL + Space (en la mayoría de los editores) y obtendrá una lista desplegable de las diferentes formas de personalizar su componente.

Utilidad primero con Sprinkles

Sprinkles es un marco de utilidad primero construido sobre extracto de vainilla. Así es como documenta el extracto de vainilla describirlo:

Básicamente, es como crear su propia versión de tiempo de ejecución cero y con seguridad de tipos de Tailwind, Sistema de estilo, etc.

Entonces, si no eres fanático de nombrar cosas (todos tenemos pesadillas de crear un outer-wrapper div y luego nos damos cuenta de que tenemos que envolverlo con un. . . outer-outer-wrapper ) Sprinkles podría ser su forma preferida de utilizar el extracto de vainilla.

La API de Sprinkles también debe instalarse por separado:

npm install @vanilla-extract/sprinkles

Ahora podemos crear algunos bloques de construcción para que los utilicen nuestras funciones de utilidad. Creemos una lista de colores y longitudes declarando un par de objetos. Los nombres de las claves de JavaScript pueden ser los que queramos. Los valores deberán ser valores CSS válidos para las propiedades CSS para las que planeamos usarlos:

// sprinkles.css.ts
const colors = { blue100: "hsl(210deg,70%,15%)", blue200: "hsl(210deg,60%,25%)", blue300: "hsl(210deg,55%,35%)", blue400: "hsl(210deg,50%,45%)", blue500: "hsl(210deg,45%,55%)", blue600: "hsl(210deg,50%,65%)", blue700: "hsl(207deg,55%,75%)", blue800: "hsl(205deg,60%,80%)", blue900: "hsl(203deg,70%,85%)",
}; const lengths = { small: "4px", medium: "8px", large: "16px", humungous: "64px"
};

Podemos declarar a qué propiedades CSS se aplicarán estos valores mediante el uso de defineProperties función:

  • Pásale un objeto con un properties propiedad.
  • In properties, declaramos un objeto donde el claves son las propiedades CSS que el usuario puede establecer (deben ser propiedades CSS válidas) y valores son los objetos que creamos anteriormente (nuestras listas de colors y lengths).
// sprinkles.css.ts
import { defineProperties } from "@vanilla-extract/sprinkles"; const colors = { blue100: "hsl(210deg,70%,15%)" // etc.
} const lengths = { small: "4px", // etc.
} const properties = defineProperties({ properties: { // The keys of this object need to be valid CSS properties // The values are the options we provide the user color: colors, backgroundColor: colors, padding: lengths, },
});

Entonces el paso final es pasar el valor de retorno de defineProperties En el correo electrónico “Su Cuenta de Usuario en su Nuevo Sistema XNUMXCX”. createSprinkles función y exportar el valor devuelto:

// sprinkles.css.ts
import { defineProperties, createSprinkles } from "@vanilla-extract/sprinkles"; const colors = { blue100: "hsl(210deg,70%,15%)" // etc.
} const lengths = { small: "4px", // etc. } const properties = defineProperties({ properties: { color: colors, // etc. },
});
export const sprinkles = createSprinkles(properties);

Entonces podemos comenzar a diseñar dentro de nuestros componentes en línea llamando al sprinkles función en el atributo de clase y eligiendo qué opciones queremos para cada elemento.

// index.ts
import { sprinkles } from "./sprinkles.css";
document.getElementById("root").innerHTML = `<button class="${sprinkles({ color: "blue200", backgroundColor: "blue800", padding: "large",
})}">Click me</button>
</div>`;

La salida de JavaScript contiene una cadena de nombre de clase para cada propiedad de estilo. Estos nombres de clase coinciden con una sola regla en el archivo CSS de salida.

<button class="src_color_blue200__ohrzop1 src_backgroundColor_blue800__ohrzopg src_padding_large__ohrzopk">Click me</button>

Como puede ver, esta API le permite diseñar elementos dentro de su marcado utilizando un conjunto de restricciones predefinidas. También evita la difícil tarea de crear nombres de clases para cada elemento. El resultado es algo que se parece mucho a Tailwind, pero también se beneficia de toda la infraestructura que se ha construido alrededor de TypeScript.

La API de Sprinkles también le permite escribir condiciones y taquigrafía para crear estilos receptivos usando clases de utilidad.

Terminando

vainilla-extract se siente como un gran paso nuevo en las herramientas CSS. Se ha pensado mucho en convertirlo en una solución intuitiva y robusta para diseñar que utilice toda la potencia que proporciona la escritura estática.

Seguí leyendo

Fuente: https://css-tricks.com/css-in-typescript-with-vanilla-extract/

Sello de tiempo:

Mas de Trucos CSS