自从几年前我了解 CSS 变量后,我最喜欢的功能就是将变量范围限定到组件的能力。但老实说,这些年来我一直没有充分利用这个功能,直到去年我创建了自己的模式库以加快原型设计和客户工作。这就是作用域 CSS 变量真正让我眼前一亮的地方。所以今天我想分享我最喜欢的两种使用 CSS 变量来组织和维护我的项目中的样式的方法。 在过去的几个月里,我开始尝试以不同的方式组织和管理 CSS…… 全局项目设置 今天,在每个项目的开始,我都会创建一个_settings.scss样式表。此样式表包含项目的全局设置。这些设置通常来自我将与之合作的设计团队提供的设计风格指南。 我当前客户项目的样式指南中定义的视觉设置示例。样式指南包含色板、品牌颜色、交互和 UI 颜色、字体样式、类型比例、间距比例、图标等。我使用样式指南作为我的 CSS 的起点,因为我创建和定义了全局项目样式通过从样式指南中的视觉等效项中得出它们的值。 就像样式指南包含颜色、框阴影样式、字体样式、类型比例等视觉样式的设置一样,_settings样式表包含充当这些设置的代码等价物的变量,并在整个 CSS 中使用这些变量来维护视觉效果。整个项目的一致性。 :root { /* UI Colors */ --primary-hue: 12; --color--primary: hsl(var(--primary-hue), 100%, 44%); --color--primary--hover: hsl(var(--primary-hue), 100%, 39%); --color--primary--active: hsl(var(--primary-hue), 84%, 30%); /* ... */ --border-color: #ebebeb; /* Box Shadows */ --shadow-01: 0px 2px 4px rgba(37, 37, 37, 0.1); --shadow-02: 0px 4px 8px rgba(37, 37, 37, 0.1); --shadow-03: 0px 8px 16px rgba(37, 37, 37, 0.1); --shadow-04: 0px 16px 24px rgba(37, 37, 37, 0.1); --shadow-05: 0px 24px 32px rgba(37, 37, 37, 0.1); /* ... */ } _settings.scss我当前客户项目的样式表中定义的全局样式设置示例。 .card { /* ... */ box-shadow: var(--shadow-01); border: 1px solid var(--border-color); transition: box-shadow .2s linear; &:hover, &:focus { box-shadow: var(--shadow-03); } } 如果在项目期间的任何时候需要更改这些设置中的任何一个,我确切地知道在哪里进行更改,并且我知道它会在我的整个系统中一致地传播。 除了这些设置之外,我还发现使用 CSS 变量来定义局部的、组件范围的样式的最大价值和便利性…… 使用“骨架”组件更快地进行原型设计 多年来,为了节省自己的时间并加快原型设计和客户工作的速度,我创建了一个 UI 和设计模式库,我发现自己需要在我的大多数项目中重新创建它们。该库现在包含越来越多的易于重用的 UI 模式集合,我可以在需要时可靠地将它们复制粘贴到我的项目中。每个模式都使用现代 CSS 和 JavaScript 逐步增强,并且可以从头开始跨浏览器和跨平台访问。 由于我将库创建为“内部”项目,因此它目前位于私有 Github 存储库中,并在.dev我网站域的后面。 我将库命名为“骨架”,并使用Fractal构建它。我已经使用 Fractal 几年了。我选择它而不是其他模式库工具是因为它完美地满足了我的需求——我想要一个没有主见且足够灵活的工具,让我能够按照我想要的方式设置和构建我的项目。Fractal 完全符合描述,因为它与我的开发方式或我使用的工具无关。在阅读了 Rachel Andrew 如何使用它使用模式优先的方法管理 CSS后,我对它更加感兴趣,这正是我想要的。我特别喜欢那个组件可以嵌套到文件夹中,以便更轻松地定位特定组件,文件夹的结构完全取决于您。 我组织了我的模式,以便每个模式都位于自己的目录中,其中包含组件的 HTML 模板、CSS 和 vanilla JavaScript 文件,以及任何其他特定于 Fractal 的资产(例如配置文件)。 使用这种结构,我的每个模式都是独立的。我可以根据需要在我的项目中包含和连接模式的样式和脚本。 /* styles.scss */ @import "accordion"; @import "modal"; 引用 Tyler Sticka 在“便携式模式的提示”中的话:模式,就像歌曲一样,当每个主音轨分开时,更容易重新混音。 我创建这个库的目标是创建一个工具,让我可以更快地进行原型设计,并且足够灵活和高效,可以在不同的项目中使用。而且由于模式在我的项目中通常采用不同的样式,我想要一种方法来简化为每个项目定制或“配置”它们的过程。输入 CSS 变量。 范围组件设置 因为我不想在新项目中使用模式时花费大量时间覆盖和撤消样式,所以我创建了这个库,其中的组件默认几乎没有样式 - 主要是白色(无颜色),最小间距, 并且只在视觉上合适的地方使用边框。所以这些图案字面上看起来像某种骨架,因此得名。现在,当我需要使用这些组件之一时,在它们准备好插入新项目之前,我几乎没有要覆盖的 CSS。 对于每个模式,我发现自己在需要使用它时都修改了相同的属性——比如字体、颜色(文本、背景、边框)、框阴影、间距等。所以我认为它会很有用,而且时间——如果我为这些属性创建变量,在组件的“根”中定义这些变量,并在我根据需要使用模式时“传入”这些变量的值,则保存。通过这种方式,我可以通过更改一个规则集中的属性值来自定义或主题化组件,而不必在多个规则之间跳转来执行此操作。 我使用变量来抽象我通常需要覆盖的所有样式。因此,跨项目更改的每个属性通常都会“提升”为变量。然后,如果在项目期间的任何时候,我需要调整模式的样式,我确切地知道在哪里做。这使得每个模式的样式更具可读性和可维护性,这对于其他人需要修改 CSS 时更加重要。 这种方法非常适合我组织 CSS 文件的方法。我喜欢将我的 CSS 组织到每个模式的单独样式表中,其中包括所有模式的样式和响应行为。这条规则会有例外……例如,在一个样式表中定义了跨模式重复使用的“原子”样式(如按钮、输入字段等)。即便如此,当原子的样式变得有点复杂(例如,为自定义文件上传输入设置样式)时,我可能会为此创建一个单独的样式表。我将在另一篇文章中更详细地介绍我组织 CSS 的方式。 例子 像你们中的大多数人一样,我发现自己几乎在所有项目中都创建了一个元素。截至去年,我使用Scott Jehl 的跨浏览器样式技术。我发现我最需要更改图标、边框颜色、边框半径和背景颜色。在每个项目中,我还为交互元素设置了重点大纲。轮廓颜色也因项目而异。 因此,我将这些属性提升为变量。对于每个属性,我设置了一个默认值或空值,并在我根据需要在新项目中使用该组件时更改该值。 .c-custom-select { --icon: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2232%22%20height%3D%2232%22%20viewBox%3D%220%200%2032%2032%22%3E%0A%3Cpath%20fill%3D%22%23777%22%20d%3D%22M9.914%2011.086l-2.829%202.829%208.914%208.914%208.914-8.914-2.828-2.828-6.086%206.086z%22%3E%3C%2Fpath%3E%0A%3C%2Fsvg%3E%0A"); --icon--disabled: ; --border-color: currentColor; --border-color--disabled: ; --color--disabled: ; --border-radius: 0; --background-color: #fff; --gradient-background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%); --outline-color: hsl(265, 50%, 50%); --padding: .5em; } 我喜欢将此规则集视为组件的设置对象。它通过传入您想要的值来更快地对组件进行主题化。 select 组件的其余规则集包含固定规则或样式,这些规则或样式很可能不会跨项目更改: .c-custom-select { -moz-appearance: none; -webkit-appearance: none; appearance: none; box-sizing: border-box; display: block; width: 100%; max-width: 100%; padding: var(--padding); padding-right: calc(var(--padding) * 3); font: inherit; color: inherit; line-height: 1.3; border: 1px solid var(--border-color); border-radius: var(--border-radius); background-color: var(--background-color); background-image: var(--icon), var(--gradient-background); background-repeat: no-repeat, repeat; background-position: right calc(var(--padding) * 1.5) top 50%, 0 0; background-size: 1em auto, 100%; } .c-custom-select::-ms-expand { display: none; } .c-custom-select:focus { outline: none; box-shadow: 0 0 0 3px var(--outline-color); box-shadow: 0 0 0 3px -moz-mac-focusring; } .c-custom-select:focus:not(:focus-visible) { box-shadow: none; } .c-custom-select:disabled, .c-custom-select[aria-disabled=true] { color: var(--color--disabled); background-image: var(--icon--disabled), linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%); } .c-custom-select:disabled:hover, .c-custom-select[aria-disabled=true] { border-color: var(--border-color--disabled); } 向前进 尽管我很想在我的所有项目中这样做,但不幸的是,我目前只能在我自己的项目中使用这种方法来设计和管理组件 CSS。原因是我的大多数客户仍然需要支持至少一两个版本的 IE,这些版本不支持 CSS 变量。虽然CSS 变量有一个 polyfill,但 polyfill 只支持定义在根 HTML 元素上的变量。根据我们对 IE 所需的支持和优化级别,我目前使用 polyfill 并至少使用 CSS 变量来定义全局项目样式。 我认为自己将来会使用这种方法进行样式管理,并结合Web 组件来创建整体更可移植的模式。希望在未来的某个时候,我们将有容器查询,使这些组件真正独立。 至于骷髅,还有很长的路要走。我的目标是创建一个自定义的 Fractal 主题来配合它。我还没有找到关于如何执行此操作的良好且完整的指南,特别是因为我希望从头开始创建一个主题,因此我可以完全控制其样式。如果您了解我,就会知道一旦我弄清楚如何从头开始创建主题,我可能会编写该指南。 我也在不断努力添加更多的模式和模式的变化。我计划包括一个代码片段部分,其中包含我也经常在项目中使用的代码片段,例如 JavaScript 模式和函数。当然,我想着重介绍文档,包括添加有关最佳实践的帖子,例如性能优化技术、图标和图像最佳实践等,而且我已经开始起草这些想法中的大部分内容。 在未来的某个时候,我可能会也可能不会将图书馆变成可共享的产品。但这目前不在其路线图上。就目前而言,我喜欢这是一个没有附加条件的小型个人项目的想法。也就是说,我很乐意将库发布为 npm 包(供私人使用开始)。我还不熟悉如何做到这一点。但是我在 CloudFour 上找到了一篇文章,深入研究了这件事,所以这可能是我的起点。当我想办法解决它时,我肯定会记录我的过程。