关于 modern-css
modern-css 是面向 Agent 和开发者的 CSS 编写技能,为现代 CSS 制定一致规则。它补充 Modern Web Guidance,明确具体样式选择,并涵盖 stylelint-config-modern 无法强制执行的规则。
主要功能
- 01CSS 层与作用域样式规则
- 02嵌套与范围查询约定
- 03流向相对布局与流式尺寸
- 04排版与颜色系统指导
- 05动态效果偏好约定
- 06CSS 审查与重构流程
适用场景
- 01为新组件编写 CSS
- 02按统一规则重构现有样式
- 03检查 CSS 是否采用现代模式
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ moderncss/ skills --skill modern-css安装后在 Claude Code 中输入/modern-css确认已加载。
详细介绍
现代 CSS
现代 CSS 的约定规则,让 Agent 和开发者以一致的方式编写样式。
这些规则基于 Modern Web Guidance 技能,该技能必须先安装。它会说明每项特性的作用、适用场景以及回退方式,但不会限定具体选择:使用哪种颜色空间、是否进行作用域限定、何时嵌套、如何设置字号。这些规则会明确这些选择;其他内容请查阅该技能的指南。两者意见不一致时,以本规则为准。
stylelint-config-modern 包会强制执行所有可由代码检查器强制执行的规则。此技能让 Agent 从一开始就遵循这些规则编写代码,并涵盖其余规则。
浏览器支持策略:对于属于 Baseline「新近可用」范围内的特性,直接使用,不添加 @supports 回退,作为渐进增强。
规则
架构
组织样式(@layer)
- 规则:将每条样式规则都放在
@layer中。 - 限制:避免未分层的元素默认样式和重置样式。
- 理由:未分层的规则优先级高于所有层;将所有规则分层后,仅由层顺序决定冲突的处理方式。
- 参考:MDN 上的
@layer。 - 示例:
@layer elements, components;
@layer elements {
a {
text-decoration-skip-ink: auto;
}
}
封装样式(@scope)
- 规则:每个组件的样式都使用
@scope;如果组件承载了不归它所有的内容,则使用作用域上限(@scope (outer) to (inner)),例如嵌入式组件、插槽内容或用户内容。 - 限制:避免在作用域之外编写组件样式,也避免对组件不拥有的内容使用无限范围的作用域。
- 理由:作用域选择器不会渗入其他组件;上限可阻止外层作用域的样式影响投影内容。这种方式有时称为甜甜圈式作用域限定。
- 参考:MDN 上的
@scope。 - 示例:
@scope (.card) to (.content) {
h2 {
font-size: var(--large);
}
}
嵌套规则和 at 规则(&)
- 规则:将规则和 at 规则嵌套在父规则中;当嵌套选择器附加到父选择器时,写出
&(&:hover);对于组合符则省略它(写b,而不是& b)。 - 限制:避免未嵌套的选择器(例如
a {} a:hover {})。 - 理由:让规则的状态和查询与规则本身放在同一个代码块中;stylelint-config-modern 会强制使用隐式
&形式。 - 参考:MDN 上的
&嵌套选择器。 - 示例:
a {
color: var(--blue);
&:hover {
text-decoration: underline;
}
code {
font-variant-numeric: tabular-nums;
}
}
范围查询(20em < width <= 40em)
- 规则:尺寸查询使用范围语法(例如
@container (20em < width <= 40em)),并确保范围不重叠。 - 限制:避免使用
min-width/max-width和重叠范围(例如同时使用width <= 20em和width >= 20em,两者都会在20em时匹配)。 - 理由:每种尺寸只会落入一个条件,因此无需让任何条件覆盖其他条件。
- 参考:MDN 上的媒体查询范围语法。
- 示例:
.card {
@container (width <= 20em) {
grid-template-columns: 1fr;
}
@container (20em < width <= 40em) {
grid-template-columns: 1fr 1fr;
}
@container (width > 40em) {
grid-template-columns: repeat(3, 1fr);
}
}
布局
相对流向的布局(*-inline-*、*-block-*、cqi/vi、start/end)
- 规则:布局使用相对流向的属性(例如
padding-block-start、inset-inline、inline-size)、单位(例如cqi、cqb、vi)和关键字(例如text-align: start)。 - 限制:避免使用对应的物理属性(例如
padding-top、width、cqw、vw、text-align: left),即使布局永远不会翻转也不例外。 - 理由:让盒模型与 flexbox 和 grid 已使用的轴保持一致;stylelint-config-modern 会强制执行此规则。
- 参考:MDN 上的逻辑属性和值。
- 示例:
.card {
max-inline-size: 60ch;
padding-block-start: 2cqi;
text-align: start;
}
双值显示(display: block flex)
- 规则:使用双值
display语法(例如display: block flex、display: inline grid)。 - 限制:避免使用单值关键字(例如
display: block、display: flex、display: inline-block)。 - 理由:将盒子在父级中的排列方式与其子元素的布局方式区分开来,因此
inline flex和inline flow-root可替代特殊关键字inline-flex和inline-block。 - 参考资料:MDN 上的多关键字
display语法。 - 示例:
nav {
display: block flex;
}
.card {
display: block grid;
}
流式间距(cqi)
- 规则:使用容器单位设置间距大小(例如
padding: 2cqi),并在需要设置下限或上限时使用钳制。 - 限制:避免固定间距(例如
padding-block: 16px、margin-inline: 1rem)。 - 理由:间距会随容器缩放,因此组件无论放置在哪里都能灵活适配,不会留下断点造成的接缝。
- 参考资料:MDN 上的容器查询长度单位、响应式设计:接缝与边缘。。
- 示例:
.card {
container: card / inline-size;
gap: 2cqi;
padding: clamp(1rem, 0.5rem + 2cqi, 2rem);
}
自动增长的文本区域(field-sizing: content)
- 规则:在文本区域上使用
field-sizing: content,并用lh明确指定inline-size和min-block-size/max-block-size。 - 限制:避免固定块大小(例如
block-size: 8rem),也不要在输入框上使用field-sizing: content,因为输入框会缩至内容值的宽度。 - 理由:输入的文本会持续显示,而不是在固定大小的框内滚动;
lh限制会随字号缩放时的行高变化。 - 参考资料:MDN 上的
field-sizing。 - 示例:
textarea {
field-sizing: content;
inline-size: 100%;
max-block-size: 12lh;
min-block-size: 3lh;
}
排版
流式字号(clamp())
- 规则:使用带容器单位的
clamp()设置字号,并采用字号比例随容器增大的字号阶梯,例如窄容器使用 Major Second(1.125),宽容器使用 Major Third(1.25)。 - 限制:避免固定字号(例如
px、rem),以及不含rem项的中间值(例如clamp(1.75rem, 5cqi, 2.25rem))。 - 理由:字号会根据容器而非断点调整,且
rem项可确保缩放功能正常。 - 参考资料:MDN 上的
clamp()、使用流式字号阶梯进行设计。 - 示例:
:root {
--medium: clamp(1.3125rem, 1.1821rem + 0.6522cqi, 1.6875rem);
--large: clamp(1.75rem, 1.5761rem + 0.8696cqi, 2.25rem);
}
孤行与寡行(text-wrap)
- 规则:在标题上使用
text-wrap: balance,在所有其他文本上使用text-wrap: pretty。 - 限制:避免在输入框和文本区域之外使用默认换行。
- 理由:默认消除孤行与寡行,而不是只在有人记得选择启用时才处理。
- 参考资料:MDN 上的
text-wrap。 - 示例:
h1,
h2,
h3 {
text-wrap: balance;
}
body {
text-wrap: pretty;
}
颜色
感知均匀的亮度(oklch())
- 规则:所有颜色都使用
oklch()。 - 限制:避免使用
hex、rgb()、hsl()和其他颜色格式。 - 理由:亮度在感知上均匀,因此文本对比度在不同色相下都能保持一致。
- 参考资料:MDN 上的
oklch()。 - 示例:
:root {
--success: oklch(40% 0.15 150deg);
--danger: oklch(40% 0.2 25deg);
}
遵循颜色偏好(light-dark())
- 规则:对于所有在浅色和深色方案之间不同的颜色,都使用
light-dark()。 - 限制:避免使用会重新声明颜色的
prefers-color-scheme块,以及不会自适应的颜色。 - 理由:每个令牌都在同一处包含两种颜色值,因此颜色变化时不会遗漏任何配色方案。
- 参考资料:MDN 上的
light-dark()。 - 示例:
:root {
--surface: light-dark(oklch(98% 0 0deg), oklch(16% 0 0deg));
--text: light-dark(oklch(35% 0 0deg), oklch(75% 0 0deg));
}
相对颜色函数(oklch(from /* .. */) 与 color-mix())
- 规则:使用相对颜色语法(例如
oklch(from var(--primary) l c calc(h - 10deg)))或在oklab中使用color-mix(),派生相关颜色。 - 限制:避免硬编码与其他颜色相关的颜色,以及仅调整高饱和颜色的亮度(例如
oklch(from var(--primary) 90% c h))。 - 原因:源颜色变化时,相关颜色会随之变化。
- 参考资料:MDN 上的相对颜色、MDN 上的
color-mix()。 - 示例:
:root {
--primary: oklch(55% 0.25 350deg);
--primary-hover: oklch(from var(--primary) l c calc(h - 10deg));
--primary-tint: color-mix(in oklab, var(--primary), oklch(100% 0 0deg) 80%);
}
动效
尊重动效偏好(prefers-reduced-motion)
- 规则:应用大型动画和过渡效果时,使用
prefers-reduced-motion: no-preference。 - 限制:避免使用
prefers-reduced-motion: reduce。 - 原因:动效会变为主动选择启用,因此无需为动画设置减少动效的覆盖规则。使用
reduce时,每个动画都需要设置覆盖规则,很容易遗漏。 - 参考资料:MDN 上的
prefers-reduced-motion。 - 示例:
@media (prefers-reduced-motion: no-preference) {
.hero {
animation: bounce-in 0.5s ease;
}
}
应用这些规则
在编写、重构或审查 CSS 时:
- 确定哪些规则适用于当前任务;如果有多条适用规则,就全部应用。
- 阅读周边文件,了解已经在使用哪些规则;遵循现有模式。
- 在整个更改集中一致地应用规则,而不只是应用于改动点。
- 获取适用于当前任务的 Modern Web Guidance 指南,并在这些规则范围内应用;根据上文的浏览器支持策略,跳过其中的回退方案。
- 如果项目使用 Stylelint 和 stylelint-config-modern,在完成前对已更改的文件运行 Stylelint,并修复其报告的问题。
注意事项
以下问题既未在上述规则中提及,也未在 Modern Web Guidance 中说明:
- **
clamp()的中心值需要包含rem项:**使用clamp(1.75rem, 1.5761rem + 0.8696cqi, 2.25rem),不要使用 Modern Web Guidance 的fluid-scaling指南所示的clamp(1rem, 5cqi, 2.5rem)形式。 - **
grid-template-rows: subgrid只会继承子元素声明使用的网格轨道。**应配合grid-row: span N使用;没有跨度时,子元素只会占一行,无法与任何内容对齐。Modern Web Guidance 的css-layout指南展示了跨度写法,但没有说明原因。 - **
container-type已经会应用包含约束:**使用container-type: inline-size的组件具有布局、样式和行内尺寸包含约束,因此不需要contain。Modern Web Guidance 的performance指南为小组件设置的contain: layout style paint会额外应用绘制包含约束,导致溢出的后代元素被裁剪,效果类似overflow: clip。
示例
本站遵循这些规则:
src/styles.css:@layersrc/variables.css:oklch()、light-dark()、clamp()src/elements.css:&、text-wrap、prefers-reduced-motion、cqi、双值display、field-sizingsrc/components/signpost/signpost.css:@scope
仅当项目没有可供匹配的自有 CSS 时,才获取其中一个文件。
评论
支持 Markdown