vanilla-extract:一款新型的、与框架无关的CSS-in-TypeScript库。它提供了一种轻量级、健壮且直观的样式编写方式。vanilla-extract并非强制性的CSS框架,而是一个灵活的开发者工具。近年来,CSS工具领域相对稳定,PostCSS、Sass、CSS Modules和styled-components等工具在2017年之前就已经出现(有些甚至更早),并且至今仍很流行。Tailwind是近年来少数几款在CSS工具领域带来变革的工具之一。
vanilla-extract旨在再次引发变革。它于今年发布,并受益于一些最新的趋势,包括:
vanilla-extract中包含许多巧妙的创新,我认为这使其意义重大。
CSS-in-JS库通常在运行时将样式注入文档中。这有一些好处,包括关键CSS提取和动态样式。
但通常情况下,单独的CSS文件性能更好。这是因为JavaScript代码需要经过更昂贵的解析/编译过程,而单独的CSS文件可以被缓存,同时HTTP2协议降低了额外请求的成本。此外,自定义属性现在可以免费提供许多动态样式。
因此,vanilla-extract效仿Linaria和astroturf,而不是在运行时注入样式。这些库允许您使用在构建时被提取并用于构建CSS文件的JavaScript函数来编写样式。尽管您使用TypeScript编写vanilla-extract,但这不会影响生产JavaScript包的整体大小。
vanilla-extract的一大价值主张是它提供了类型检查。如果保持代码库的类型安全非常重要,那么为什么不也对样式做同样的事情呢?
TypeScript提供了许多好处。首先是自动完成。如果您键入“fo”,那么在支持TypeScript的编辑器中,您会得到一个下拉列表,其中包含字体选项(fontFamily、fontKerning、fontWeight或其他匹配项)供您选择。这使得CSS属性在编辑器的便捷性下变得易于发现。如果您不记得fontVariant的名称,但知道它以“font”开头,您可以键入它并滚动浏览选项。在VS Code中,您无需下载任何额外工具即可实现此功能。
这极大地加快了样式的编写速度:
这也意味着您的编辑器会时刻监视您,确保您不会犯任何拼写错误,这些错误可能会导致令人沮丧的bug。
vanilla-extract类型还在其类型定义中提供了语法解释和指向您正在编辑的CSS属性的MDN文档的链接。当样式行为异常时,这省去了疯狂谷歌搜索的步骤。
使用TypeScript编写意味着您使用驼峰式命名法来表示CSS属性,例如backgroundColor。对于习惯使用常规CSS语法(例如background-color)的开发者来说,这可能需要一些改变。
vanilla-extract为所有最新的打包工具提供了第一方集成。以下是它目前支持的完整集成列表:
它也完全与框架无关。您只需从vanilla-Extract导入类名,这些类名会在构建时转换为字符串。
要使用vanilla-Extract,您可以编写一个.css.ts
文件,您的组件可以导入该文件。对这些函数的调用会在构建步骤中转换为哈希和作用域类名字符串。这听起来可能类似于CSS Modules,这并非巧合:vanilla-Extract的创建者之一Mark Dalgleish也是CSS Modules的共同创建者。
style()
函数您可以使用style()
函数创建一个自动作用域的CSS类。您传入元素的样式,然后导出返回值。在您的用户代码中的某个地方导入此值,它将转换为作用域类名。
// 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>Vanilla Extract</h1>`;
媒体查询和伪选择器也可以包含在样式声明中:
// 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%)" }
这些style
函数调用是对CSS的轻量级抽象——所有属性名称和值都映射到您熟悉的CSS属性和值。需要习惯的一个变化是,值有时可以声明为数字(例如padding: 30),默认为像素单位值,而某些值需要声明为字符串(例如padding: "10px 20px 15px 15px")。
style
函数中的属性只能影响单个HTML节点。这意味着您不能使用嵌套来声明元素子元素的样式——这在Sass或PostCSS中您可能习惯了。相反,您需要分别设置子元素的样式。如果子元素需要基于父元素的不同样式,您可以使用selectors
属性添加依赖于父元素的样式:
// 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>Vanilla Extract</h1> Unstyled`;
或者,您也可以使用主题API(我们接下来会讲到)在父元素中创建自定义属性,这些属性由子节点使用。这听起来可能比较严格,但它被故意设计成这样是为了提高大型代码库的可维护性。这意味着您将确切地知道项目中每个元素的样式在哪里声明。
您可以使用createTheme
函数在TypeScript对象中构建变量:
// 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" } }) // 使用主题 export const titleStyle = style({ backgroundColor:vars.color.background, color: vars.color.text, fontFamily: "helvetica, Sans-Serif", padding: vars.lengths.mediumGap, borderRadius: 20, });
然后,vanilla-extract允许您创建主题的变体。TypeScript帮助它确保您的变体使用相同的属性名称,因此如果您忘记向主题添加background属性,您会收到警告。
以下是如何创建常规主题和暗模式:
// 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" } }) // 主题变体 - 注意这部分不使用数组语法 export const darkMode = createTheme(vars,{ color:{ text:"hsl(210deg,60%,80%)", background: "hsl(210deg,30%,7%)", }, lengths:{ mediumGap: "30px" } }) // 使用主题 export const titleStyle = style({ backgroundColor: vars.color.background, color: vars.color.text, fontFamily: "helvetica, Sans-Serif", padding: vars.lengths.mediumGap, borderRadius: 20, });
然后,使用JavaScript,您可以动态地应用vanilla-extract返回的类名来切换主题:
// title.ts import {titleStyle,mainTheme,darkMode} from "./title.css"; document.getElementById("root").innerHTML = `<div> <h1>Vanilla Extract</h1> Dark mode </div>`
这是如何在底层工作的?您在createTheme
函数中声明的对象将转换为附加到元素类的CSS自定义属性。这些自定义属性经过哈希处理以防止冲突。我们的mainTheme
示例的输出CSS如下所示:
.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; }
而我们的darkMode
主题的CSS输出如下所示:
.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; }
因此,我们只需要更改用户代码中的类名即可。将darkmode
类名应用于父元素,mainTheme
自定义属性将被darkMode
自定义属性替换。
style
和createTheme
函数本身就足以样式化一个网站,但vanilla-extract提供了一些额外的API来提高可重用性。Recipes API允许您为元素创建许多变体,您可以在标记或用户代码中从中选择。
首先,需要单独安装它:
npm install @vanilla-extract/recipes
以下是它的工作原理。您导入recipe
函数并传入一个包含base
和variants
属性的对象:
// button.css.ts import { recipe } from '@vanilla-extract/recipes'; export const buttonStyles = recipe({ base:{ // 应用于所有按钮的样式都放在这里 }, variants:{ // 我们从中选择的样式放在这里 } });
在base
中,您可以声明将应用于所有变体的样式。在variants
中,您可以提供不同的方式来自定义元素:
// 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, }, }, }, });
然后您可以在标记中声明要使用的变体:
// button.ts import { buttonStyles } from "./button.css"; Click me
vanilla-extract利用TypeScript为您自己的变体名称提供自动完成!
您可以随意命名变体,并在其中放入任何您想要的属性,例如:
// button.css.ts export const buttonStyles = recipe({ variants: { animal: { dog: { backgroundImage: 'url("./dog.png")', }, cat: { backgroundImage: 'url("./cat.png")', }, rabbit: { backgroundImage: 'url("./rabbit.png")', }, }, }, });
您可以看到这对于构建设计系统非常有用,因为您可以创建可重用的组件并控制它们变化的方式。这些变化使用TypeScript变得很容易发现——您只需要键入CMD/CTRL Space(在大多数编辑器上),您就会得到一个下拉列表,其中列出了自定义组件的不同方法。
Sprinkles是一个基于vanilla-extract构建的实用优先框架。vanilla-extract文档是这样描述它的:
基本上,它就像构建您自己的零运行时、类型安全的Tailwind、Styled System等版本。
因此,如果您不喜欢命名事物(我们都做噩梦,创建了一个外部包装div,然后意识到我们需要用……外部外部包装器包装它),Sprinkles可能是您首选的vanilla-extract使用方式。
Sprinkles API也需要单独安装:
npm install @vanilla-extract/sprinkles
现在我们可以创建一些构建块供我们的实用函数使用。让我们通过声明几个对象来创建一个颜色和长度列表。JavaScript键名可以是任何我们想要的。值需要是我们计划使用的CSS属性的有效CSS值:
// 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" };
我们可以使用defineProperties
函数声明这些值将应用于哪些CSS属性:
properties
属性的对象。properties
中,我们声明一个对象,其中键是用户可以设置的CSS属性(这些需要是有效的CSS属性),而值是我们之前创建的对象(我们的颜色和长度列表)。// 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: { // 此对象的键需要是有效的CSS属性 // 值是我们为用户提供的选项 color: colors, backgroundColor: colors, padding: lengths, }, });
然后最后一步是将defineProperties
的返回值传递给createSprinkles
函数,并导出返回值:
// 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);
然后我们可以在组件内通过在class
属性中调用sprinkles
函数并为每个元素选择我们想要的选项来开始内联样式化。
// index.ts import { sprinkles } from "./sprinkles.css"; document.getElementById("root").innerHTML = `Click me `;
JavaScript输出为每个样式属性保存一个类名字符串。这些类名与输出CSS文件中的单个规则匹配。
Click me
如您所见,此API允许您使用一组预定义的约束在标记内设置元素的样式。您还可以避免为每个元素想出类名的困难任务。结果是感觉非常像Tailwind的东西,但也受益于围绕TypeScript构建的所有基础设施。
Sprinkles API还允许您编写条件和简写,以使用实用程序类创建响应式样式。
vanilla-extract感觉是CSS工具领域的一大进步。在将其构建为一个直观、健壮的样式化解决方案方面,投入了大量的思考,该解决方案利用了静态类型提供的所有功能。
This revised output maintains the original meaning while using different wording and sentence structures. The images remain in their original format and location.
以上是CSS在打字稿中使用香草 - 提取的详细内容。更多信息请关注PHP中文网其他相关文章!