CSS 代码示例编写指南

以下指南涵盖了如何为 MDN Web Docs 编写 CSS 示例代码。

CSS 代码示例通用指南

选择格式

关于正确缩进、空格和行长度的看法一直备受争议。关于这些话题的讨论会分散创建和维护内容的注意力。

在 MDN Web 文档中,我们使用 Prettier 作为代码格式化程序,以保持代码风格一致(并避免离题讨论)。您可以查阅我们的 配置文件 以了解当前规则,并阅读 Prettier 文档

Prettier 格式化所有代码并保持风格一致。然而,还有一些额外的规则需要您遵循。

规划你的 CSS

在深入编写大量 CSS 代码之前,请仔细规划你的样式。需要哪些通用样式,你需要创建哪些不同的布局,需要创建哪些特定的覆盖,以及它们是否可重用?最重要的是,你需要尽量避免过多的覆盖。如果你发现自己一直在编写样式,然后又在几条规则之后取消它们,你可能需要重新考虑你的策略。

在支持时使用现代 CSS 特性

一旦所有主流浏览器——Chrome、Edge、Firefox 和 Safari——都支持新特性(即基线),你就可以使用它们。

此规则不适用于页面上正在文档化的 CSS 特性(这由包含标准决定)。例如,你可以文档化非标准或实验性特性,并编写完整的示例来演示它们的行为,但你应该避免在其他不相关特性的演示中使用这些特性,例如 Web API。

遵循常见的最佳实践

有一些普遍公认的原则,我们不需要在这里详尽地说明

不要使用预处理器

不要在示例代码中使用预处理器语法,例如 SassLessStylus。在 MDN Web Docs 上,我们记录了纯 CSS 语言。使用预处理器只会提高理解示例的门槛,可能会让读者感到困惑。

不要使用特定的 CSS 方法论

与上一条指南的精神相同,不要在 MDN Web Docs 上使用特定的 CSS 方法论(例如 BEMSMACSS)编写示例代码。即使它们是有效的 CSS 语法,命名约定也可能让不熟悉这些方法论的人感到困惑。

不要使用重置

为了最大程度地控制跨平台的 CSS,许多人过去常常使用 CSS 重置来删除所有样式,然后再自己构建。这当然有其优点,但特别是在现代世界中,CSS 重置可能矫枉过正,导致花费大量额外时间重新实现原本并非完全损坏的东西,例如默认边距和列表样式。

正式语法和伪代码

正式语法是 MDN CSS 文档不可或缺的一部分(例如,请参阅 background-image 属性页面上的正式语法部分)。由于许多开发人员熟悉这种格式的语法,因此在描述和示例中以类似正式语法的方式编写伪代码是可以接受的。但是,任何不符合语法规范的 CSS 代码都不应标记为 CSS。css 代码块中的语法错误会导致静态检查器无法解析代码,使期望看到有效 CSS 代码的读者感到困惑,甚至可能导致毫无意义的语法高亮。要么将你的代码块标记为 plain,要么使用 CSSSyntaxRaw 宏来渲染完整的正式语法。

不要像这样写描述(无论如何这都不是真正的正式语法;它只是带有占位符的伪 CSS)

md
The `border` property has the following general form:

```css
border: <border-width> <border-style> <border-color>;
```

相反,使用 plain

md
The `border` property has the following general form:

```plain
border: <border-width> <border-style> <border-color>;
```

或者,当你觉得合适时,使用 CSSSyntaxRaw 宏编写实际的正式语法

md
The `border` property is specified as a line width, a line style, and a color, in any order:

{{CSSSyntaxRaw(`border = <line-width> || <line-style> || <color>`)}}

此外,单个值在语法上并非格式良好的 CSS。CSS 代码至少需要一个属性及其值。如果你要文档化 rgb() 函数,请这样写

css
color: rgb(31 41 59);
color: rgb(31 41 59 / 26%);

不要使用这种风格

css
rgb(31 41 59);
rgb(31 41 59 / 26%);

请注意,此规则不适用于“语法”部分中的第一个代码块,该代码块由语法部分指定,并且要求函数在没有属性名称的情况下编写。

动画

关键帧选择器

指定关键帧时,0%100% 选择器也可以写成 fromto。如果 @keyframes 规则只包含这两个选择器,请使用 fromto 而不是 0%100%。这使你的代码更具语义性。

所以避免这样

css
@keyframes example {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

改为使用 fromto

css
@keyframes example {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

另一方面,如果你的 @keyframes 规则包含的不仅仅是开始和结束帧,请使用 0%100% 选择器以保持一致性。

css
@keyframes example {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 0.8;
  }
  100% {
    opacity: 1;
  }
}

层叠、属性和选择器

控制特异性

如果可能,请避免因增加或减少特异性而产生的意外,例如过度使用:where() 伪类或重复选择器。相反,请考虑以下技术来管理特异性

  • 更改声明的顺序以利用层叠
  • 重新排列每个声明中的属性,使它们不会相互覆盖
  • 在 HTML id 本身合理的情况下使用 ID 选择器

!important

!important 是最后的手段,通常只在你需要覆盖某些内容且没有其他方法时使用。使用 !important 是一种不良做法,应尽可能避免。

css
.bad-code {
  font-size: 4rem !important;
}

排序

通常,当两个声明针对相同元素时,特异性较高的声明应在样式表中靠后。

css
button {
  color: blue;
}

.my-form button {
  color: red;
}

在声明中,最好将相关属性(例如尺寸、定位和颜色)放在一起。自定义属性应在声明块的顶部声明,这允许快速识别所有可用的自定义属性。

空行

建议在声明块之间使用空行。如果连续的声明高度相关,例如同一实用程序的变体,则可以删除它们。

属性之间的空行应谨慎使用。仅当每组属性形成清晰的语义块时才添加它们。

简写属性

  • 如果简写属性的每个组成属性都分配了一个非默认值,请使用简写属性而不是组成的长手属性。这使你的代码更短,更容易阅读。

    替换这些长手属性

    css
    margin-top: 1em;
    margin-right: 2em;
    margin-bottom: 1em;
    margin-left: 2em;
    

    使用它们对应的简写

    css
    margin: 1em 2em;
    
  • 如果简写属性的部分组成属性分配了非默认值,则简写属性的使用是可选的。以下两种情况都是可以接受的

    css
    margin-top: 1em;
    margin-bottom: 1em;
    
    css
    margin: 1em 0;
    
  • 使用最短的简写语法。这样写

    css
    margin: 1em;
    

    避免这些

    css
    margin: 1em 1em;
    margin: 1em 1em 1em 1em;
    
  • 规范顺序编写简写属性。这样写

    css
    /* width style color */
    border: 1px solid red;
    

    不要这样写

    css
    border: solid red 1px;
    
  • 对于每个简写,要么使用它,要么使用它的长手组成部分,绝不能混用,因为覆盖关系复杂且容易出错。避免这些

    css
    margin-top: 1em;
    margin: 2em; /* Oops, margin-top is ignored */
    
    border-width: 1px;
    border-bottom-width: 5px; /* Overrides one border's width *only* */
    

使用类选择器

通常,首选类选择器(并在 HTML 中使用 class 而不是 id)。它们可以组合:多个元素可以使用相同的类,同一个类也可以用于多个元素。

css
.footnote {
  /* ... */
}
css
#footnote {
  /* ... */
}

使用类进行样式设置,并将 ID 保留用于非 CSS 用途,例如在 JavaScript 中使用或链接到唯一的页面锚点(<a href="#section1">)。在 ID 的使用合理的情况下,你可以将其用作选择器,可能用于控制特异性

旧的伪元素选择器

::before::after::first-letter::first-line 伪元素也可以用单个冒号编写(如 :before)。避免使用单冒号语法,因为它不被推荐,并且可能被读者误认为是伪类:hover)。

复杂选择器列表

:is():where():not() 伪类接受复杂选择器列表。使用它们来缩短你的选择器。

这样写

css
input:not(:checked, :disabled) {
  /* ... */
}

不要这样写

css
input:not(:checked):not(:disabled) {
  /* ... */
}

大小写

默认情况下,所有标识符都应为小写。这适用于选择器、函数和关键字。自定义标识符应使用kebab-case,例如 --custom-propertymy-animation。有关作为 CSS 选择器引用的 HTML ID 和类的命名约定,请参阅 HTML 样式指南

例外情况包括 SVG 中定义的关键字值,由于历史原因它们是camelCase,并且应该这样编写以增强可读性。这些关键字包括:currentColortext-rendering 值、shape-rendering 值、pointer-events 值和 color-interpolation-filters 值。

颜色

选择表示法

通常,如果特定的调色板不是问题,默认使用常见的命名颜色。例如,使用 black 而不是 rgb(0 0 0)#000000,以及 green 而不是 chartreuse

如果需要特定颜色,默认使用 rgb() 表示法。hsl() 和其他函数应仅在特定表示法有意义(例如,色轮或渐变)时使用。十六进制表示法更简洁,但可读性可能较差;它可以与 rgb() 互换,具体取决于你觉得哪个更方便。

无论你使用哪种颜色函数,始终使用现代语法(rgb(31 41 59 / 0.26)),而不是旧的逗号分隔语法。始终使用不带 a 后缀的函数(rgb 而不是 rgba),因为它更短,并且如果你以后决定添加或删除 alpha 通道,则无需更改名称。

使用十六进制表示法时,始终使用六(或八)位版本,以避免认知负担:#aabbcc 而不是 #abc

颜色参数

为了保持一致性,所有参数默认应使用数字而不是百分比或度数。这也适用于 alpha 通道。但是,如果特定表示法有意义(例如,在动画、渐变或计算中),请在上下文中使用合适的类型。

如果 alpha 通道为 1,则省略它。写 rgb(31 41 59) 而不是 rgb(31 41 59 / 1)

选择颜色

除了推荐使用常见命名颜色外,你的调色板还应符合我们的可访问性指南。特别是,如果颜色区分元素(例如“红色框”和“蓝色框”),请确保颜色对色觉缺陷的人是可区分的。文本和背景之间的对比度(WCAG AA)目标至少为 4.5:1。

注释

使用 CSS 样式注释来注释不自解释的代码。另请注意,你应在星号和注释之间留一个空格。

css
/* This is a CSS-style comment */

将你的注释放在它们所引用的代码之前的单独行上,如下所示

css
h3 {
  /* Creates a red drop shadow, offset 1px right and down, w/2px blur radius */
  text-shadow: 1px 1px 2px red;
  /* Sets the font-size to double the default document font size */
  font-size: 2rem;
}

字体

指定字体系列

指定字体系列时,始终将通用字体系列名称作为最后的备用。这可确保如果指定的字体不可用,浏览器会显示更合适的备用字体。网页安全字体不受此规则的限制。

css
body {
  font-family: "Helvetica";
}
css
body {
  /* The "sans-serif" family is not needed because Arial is a web-safe font */
  font-family: "Helvetica", "Arial";
}

math {
  font-family: "Latin Modern Math", "STIX Two Math", math;
}

指定字体粗细

首选关键字值,例如 normalbold,以及相对粗细,例如 bolderlighter。仅在需要特定粗细时使用数字值。你应该始终用 normal 替换 400,用 bold 替换 700,除非在使用可变字体声明范围,或为了与其他类似声明保持一致。

长度

使用弹性/相对单位

为了在最广泛的设备范围内实现最大灵活性,所有长度都默认使用相对单位,例如 emrem、百分比和视口单位(如果你希望它们根据视口宽度而变化)。你可以在我们的CSS 值和单位指南中阅读更多相关内容。

这样写

css
margin: 0.5em;
max-width: 50%;

避免这样

css
margin: 20px;
max-width: 500px;

媒体查询

范围语法

使用现代范围语法而不是 min-max-。前者允许指定排他范围,允许同时指定上限和下限,并且总体上更简洁易读。

css
@media (width >= 480px) {
  /* ... */
}
@media (600px < height < 900px) {
  /* ... */
}
css
@media (min-width: 480px) {
  /* ... */
}
@media (min-height: 600px) and (max-height: 900px) {
  /* ... */
}

此原则延伸到媒体查询的非 CSS 用法,例如 <link> 元素的 media 属性或 window.matchMedia()

如果你有通过媒体阈值选择的不同替代样式,请特别注意你的媒体查询。请记住,widthheight 可以是分数,确保在每个值下,只有一个替代样式生效。

移动优先媒体查询

在包含针对不同目标视口大小的媒体查询样式的样式表中,首先包含窄屏幕/移动样式,然后再遇到任何其他媒体查询。通过连续的媒体查询添加更宽视口大小的样式。遵循此规则有许多优点,这些优点在响应式设计中进行了解释。

css
/* Default CSS layout for narrow screens */

@media (width >= 480px) {
  /* CSS for medium width screens */
}

@media (width >= 800px) {
  /* CSS for wide screens */
}

@media (width >= 1100px) {
  /* CSS for really wide screens */
}

字符串

在 CSS 语法中引号可选的地方,请使用它们,并使用双引号。这样做

css
[data-vegetable="liquid"] {
  background-image: url("../../media/examples/lizard.png");
  font-family: "Helvetica", "Arial";
}

不要这样做,因为允许的字符类型更受限制,有时会导致细微的语法错误

css
[data-vegetable=liquid] {
  background-image: url(../../media/examples/lizard.png);
  font-family: Helvetica, Arial;
}

使用 @import at-rule 时,将模块路径指定为字符串,而不是 url()

css
@import "style.css";
css
@import url("style.css");

另见

CSS 参考索引 - 浏览我们的 CSS 属性参考页面,查看一些优秀、简洁、有意义的 CSS 片段。“试一试”部分中的交互式示例通常遵循此页面中描述的指南。