Skip to content
This page has been auto-translated and may contain errors.View in English

CSS 如何工作

docs.scrimba.com

一个普通的 HTML 页面到达时,浏览器的默认样式已经应用:蓝色带下划线的链接、黑色无衬线文本、按大小递减的标题。CSS 就是如何接管这个原始结构并决定它的外观。但在改变任何颜色或移动任何框之前,你需要了解你的样式首先如何到达页面,以及当两个规则对同一个元素产生分歧时会发生什么。

将 CSS 附加到页面

有三种方法可以将 CSS 添加到页面,区别主要在于你在哪里编写样式。

第一种是**内联样式**,直接写在元素的 style 属性上:

html
<p style="color: teal;">单个青色段落。</p>

这只样式化一个段落,没有其他。第二种方法是页面 <head> 中的内部 <style> 块,可以一次样式化多个元素。第三种,也是你应该使用的方法,是一个链接到页面的单独 CSS 文件。你在该文件中编写一次样式,每个链接到它的页面都会应用它们。把它想象成一个衣柜:与其逐个描述每个人的穿着,不如一次性写下着装要求,每个人都遵循它。

CSS 以三种方式到达页面,但它们并不相等。内联样式存在于元素自身的 style 属性上,仅影响那一个元素。**内部样式表**是 <head> 中的一个 <style> 块,可以针对整个页面的元素。外部样式表是从 <head> 链接的一个 .css 文件:

html
<link rel="stylesheet" href="styles.css">

默认情况下选择外部样式表。它将你的样式保存在一个地方,而不是分散在标记中,所以结构保留在 HTML 中,表现保留在 CSS 中,这与 CSS 是什么中描述的分离一样。浏览器还会缓存该文件,所以访问者在页面之间移动时只下载一次你的样式并重复使用,你也只需编写一次按钮样式规则,而不是在每个按钮上复制。

三种机制附加 CSS,每一种都对应于你稍后将在本章中遇到的级联中的一个位置。内联样式(元素上的 style 属性)仅适用于该元素,在冲突中具有非常高的权重,这正是为什么依赖它会伤害你:从样式表中干净地覆盖它是困难的。内部 <style> 块的作用域限于一个文档。用 <link rel="stylesheet"> 链接的外部样式表是生产环境的默认方式,原因超出了整洁性。

外部文件同时给你三件事:关注点分离,所以标记和样式独立变化;HTTP 缓存,所以返回访问者在每个页面上重复使用已下载的文件,而不是重新获取每个 HTML 响应中嵌入的样式;以及重用,所以一个编写的规则服务整个网站。折衷是一个单独的请求,这就是为什么有时会内联非常小的关键样式以进行首次绘制,但总体规则成立:在外部样式表中编写,并将内联样式视为针对性例外,而非习惯。

这是完整的外部方法:一个链接样式表的 HTML 文件和样式表本身。

html
<!-- index.html -->
<head>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <p class="intro">欢迎来到网站。</p>
</body>
css
/* styles.css */
.intro {
  color: teal;
  font-size: 1.25rem;
}
Juno将 CSS 附加到页面 有三种方法可以添加 CSS:使用 style 在元素上、在 <style> 块中,或在你用 <link> 链接的单独文件中。使用单独文件。你编写一次样式,每个链接到它的页面看起来都一样。
Juno将 CSS 附加到页面 内联样式影响一个元素,<style> 块覆盖一个页面,外部 .css 文件覆盖你的整个网站。默认使用外部文件:它将表现保留在标记之外,浏览器缓存它,一个规则服务每个匹配的元素。内联样式是例外,而非常规。
Juno将 CSS 附加到页面 在外部样式表中编写:一个举动中的分离、缓存和重用。内联样式在级联中具有高权重,所以稍后覆盖它们很痛苦;将它们保持为有意的例外。唯一要内联的时候是首次绘制的一个小块关键样式,即使如此,你的大部分 CSS 也保留在链接的文件中。

规则的构成

一段 CSS 被写成一个**规则**,每个规则都有相同的形式。这是一个样式化卡片的规则:

css
.card {
  color: navy;
  padding: 16px;
}

前面的 .card选择器:它选择规则应用到哪些元素,在这种情况下是任何具有 card 类的元素。花括号内的一切都是声明块。内部的每一行,如 color: navy;,都是一个声明:一个属性(color)和你希望它具有的值(navy),由冒号分隔并以分号结尾。把整个规则当作一个句子阅读:"对于每个卡片,使颜色海军蓝并且内边距 16 像素。"

每个规则都由相同的部分构建,命名它们使 CSS 的其余部分更容易谈论。

css
.card {
  color: navy;
  padding: 16px;
}

选择器.card)选择规则针对的元素。花括号保存声明块。在其内部,每个 property: value; 对都是一个声明:color 是属性,navy 是值,冒号连接它们,分号结束它们。分号是声明之间的分隔符,所以最后一个技术上不需要它,但还是保留它:稍后添加下一个声明变成一行改动而不是两行。选择器匹配哪些元素以及它的具体程度,是 选择器章节的主题。

语法很小,值得精确陈述,因为每个后续概念都用这些术语定义。规则是一个**选择器**(决定规则应用到哪些元素的模式)后跟一个声明块(花括号)。块内坐着声明列表,每个声明是一个属性与一个值由冒号配对并由分号结束。

css
.card {
  color: navy;
  padding: 16px;
}

精确性在调试中付得起。一个格式不当的声明,比如拼写错误的属性或无效的值,会被解析器自行丢弃,块的其余部分仍然适用;CSS 按声明失败,而不是按规则,这就是为什么单个拼写错误悄悄地丢弃一行而不是破坏整个卡片。分号是分隔符,而不是终止符,所以它在最后声明之后是可选的,但保留它可以防止你某天追加另一行并忘记在上面添加它的破坏规则。当你接下来遇到级联时,记住"哪个声明赢"总是在这个声明级别,逐个属性地运行。

Juno规则的构成 规则是选择器加上花括号中的一组声明。像 .card 这样的选择器选择元素,每个声明如 color: navy; 是一个属性和值,中间有冒号,结尾有分号。一旦你能命名这些部分,你读到的每个规则都看起来一样。
Juno规则的构成 选择器、声明块和其内部的 property: value; 声明:这就是每个规则。分号分隔声明,所以也在最后一个上保留它,添加下一行保持一行编辑。选择器如何匹配以及它的具体程度出现在下一个选择器章节。
Juno规则的构成 规则是选择器和一个 property: value; 声明块,CSS 按声明失败:一个无效行被丢弃,块的其余部分存活。这就是为什么流浪分号悄悄地移除单个样式而不是破坏卡片。保留尾随分号,追加声明永远不会咬你。

级联

有时两个规则试图样式化同一个元素,CSS 需要一种方法来决定哪个赢。那个决定是**级联**,它是 CSS 中 C 的来源。

css
.card {
  color: navy;
}

.card {
  color: teal;
}

两个规则都针对卡片,都设置颜色。卡片最终是青色,因为当两个规则具有相同强度时,写在后面的规则赢。顺序很重要,它像水一样流过文件,这就是级联这个名字的来源。还有第二个平手破坏规则:更具体的选择器击败更一般的选择器,所以针对你的卡片的规则可以覆盖更广泛的规则,即使更广泛的规则后来。你将在 选择器章节中详细遇到那个具体程度。

当几个规则在同一元素上设置相同属性时,**级联**是选择获胜者的过程。两个因素在这里决定它:具体程度和源顺序。

css
.card {
  color: navy;
}

.card {
  color: teal;
}

这两个规则有相同的具体程度,所以源顺序打破平手,后面的规则赢:卡片是青色。当具体程度不同时,它优先于顺序:更具体的选择器击败更一般的选择器,即使一般规则后来在文件中。更具体的赢;在具体程度平手时,后面的赢。这就是为什么在文件后期堆积覆盖是一个脆弱的习惯,为什么理解 选择器章节中的具体程度是使级联可预测而不是猜测游戏的原因。

**级联**是解决一个元素上一个属性的竞争声明的算法,它运行通过一个有序的标准集合,直到一个声明留下来胜利。

css
.card {
  color: navy;
}

.card {
  color: teal;
}

两个最常见的标准是具体程度(浏览器从选择器计算的权重)和源顺序(平手时后面的赢),上面的例子依靠第二个:具体程度相等,所以后面的 teal 赢。但那两个坐在更大的顺序内。级联首先按来源和重要性排序:浏览器默认样式,然后你的作者样式,然后任何用户样式,顶部有一个普通对比重要层。标记为 !important 的声明跳到更高的带,这正是它存在的原因,也正是为什么要避免它。!important 通过离开普通顺序而赢,而不是通过正确,所以它不是覆盖而是逃生口,一旦一个 !important 出现,下一个修复通常是另一个。仅当要打败你不控制的样式时才使用它,例如内联样式或第三方小部件,否则让具体程度和顺序做工作。当你遇到 盒模型并开始分层许多规则时,这个顺序是保持结果可预测的原因。

Juno级联 级联是 CSS 如何在两个规则样式化同一事物时平息一场争执。如果规则强度相等,写在后面的赢,所以顺序计数。更具体的选择器也可以击败更一般的选择器,该部分即将在选择器章节中出现。
Juno级联 当规则碰撞时,具体程度首先决定,源顺序打破平手:更具体的赢,在平局匹配时后面的规则赢。在文件底部堆积覆盖可行,直到它不可行,这就是为什么在你信任级联之前选择器上的具体程度章节值得阅读。
Juno级联 级联按来源和重要性排序首先,然后具体程度,然后源顺序,按属性结算这一切。!important 通过跳跃带而赢,而不是通过正确,所以把它当作逃生口对待你不控制的样式,永不常规覆盖。一个 !important 倾向于导致下一个。

继承

在框上设置颜色,框内的文本通常也会变成那个颜色,即使你从未直接样式化那个文本。那个传递是称为**继承**。

css
.site-header {
  color: white;
  font-family: Georgia, serif;
}

标题内的每一段文本,一个标题,一个链接,一个标签行,捡起那个白色和那个字体而不是它自己的规则,因为 colorfont-family 是继承属性。不是一切都传递,虽然。像 padding 这样的间距属性不继承:你在标题上放的内边距保留在标题上,不出现在它内部的元素上。作为一个粗略指南,文本相关样式流向孩子,像间距和边框这样的框相关样式保持不动。

一些属性自动将其值传递给后代元素,有些则不传递。那个行为是**继承**,知道哪些属性继承为你节省许多重复规则。

css
.site-header {
  color: white;
  font-family: Georgia, serif;
}

文本相关属性继承:colorfont-familyfont-sizeline-height 和类似的都流向后代,所以在容器上设置一次就样式化里面的所有东西。框相关属性不继承:paddingmarginborderbackground 仅适用于你设置它们的元素。当你想要一个通常不会继承的值继承时,inherit 关键字强制它,从父级获取属性的计算值。继承和级联是分别工作的独立系统:级联决定元素的获胜声明,继承是当没有规则在它上设置该属性时孩子回退的东西。排版大量依赖这个,排版章节建立在其上。

**继承**是没有级联值的元素上的属性从该元素的父级获取其值的机制。每个 CSS 属性定义为继承或不继承:大多数文本属性(colorfont-familyfont-sizeline-heighttext-align)继承;大多数框属性(paddingmarginborderbackground)不继承,因为将间距继承到每个后代将是不可用的。

css
.site-header {
  color: white;
  font-family: Georgia, serif;
}

四个显式关键字控制这个按声明,当默认值不是你想要的时:inherit 甚至在非继承属性上也获取父级的计算值,initial 重置为属性的规范默认值,unset 对继承属性作为 inherit 而对其余的作为 initial,以及 revert 回退到浏览器的默认样式。更大的图景是继承和级联一起产生元素的计算值:级联在一个存在的地方选择获胜声明,没有的地方,继承属性从其父级抽取,而非继承属性降至其初始值。那个单个计算值,每属性,每元素是布局和绘制实际消费的,自定义属性章节直接依赖继承使设计令牌流通过组件树。

Juno继承 继承是文本样式流向框内元素:在标题上设置 colorfont-family 里面的文本免费捡起。像 padding 这样的间距不传递,它保留在你放它的地方。粗略规则:文本样式传向孩子,框样式保持不动。
Juno继承colorfont-family 这样的文本属性继承到后代;像 paddingborder 这样的框属性不继承。样式化一个容器一次里面的每个文本相关的东西跟随。当你需要一个通常不会继承的值时,inherit 关键字从父级拉取。
Juno继承 每个属性通过定义继承或不继承:文本属性继承,框属性不继承。关键字 inheritinitialunsetrevert 让你按声明覆盖那个。继承和级联一起结算每个属性每个元素的一个计算值,以及那个值是布局和绘制实际使用的。