CSS 基本语法

CSS 基本语法

HTML 中引入 CSS 的方式

有 4 种方式可以在 HTML 中引入 CSS。其中有 2 种方式是在 HTML 文件中直接添加 CSS 代码,另外两种是引入 外部 CSS 文件。下面我们就来看看这些方式和它们的优缺点。

内联方式

内联方式指的是直接在 HTML 标签中的 style 属性中添加 CSS。

示例:

1
<div style="background: red"></div>

这通常是个很糟糕的书写方式,它只能改变当前标签的样式,如果想要多个<div> 拥有相同的样式,你不得不重复地为每个 <div> 添加相同的样式,如果想要修改一种样式,又不得不修改所有的 style 中的代码。很显然,内联方式引入 CSS 代码会导致 HTML 代码变得冗长,且使得网页难以维护。

嵌入方式

嵌入方式指的是在 HTML 头部中的 <style> 标签下书写 CSS 代码。

示例:

1
2
3
<head>     
<style>.content { background: red; } </style>
</head>

嵌入方式的 CSS 只对当前的网页有效。因为 CSS 代码是在 HTML 文件中,所以会使得代码比较集中,当我们写模板网页时这通常比较有利。因为查看模板代码的人可以一目了然地查看 HTML 结构和 CSS 样式。因为嵌入的 CSS 只对当前页面有效,所以当多个页面需要引入相同的 CSS 代码时,这样写会导致代码冗余,也不利于维护。

链接方式

链接方式指的是使用 HTML 头部的 <head> 标签引入外部的 CSS 文件。

示例:

1
2
3
<head>     
<link rel="stylesheet" type="text/css" href="style.css">
</head>

这是最常见的也是最推荐的引入 CSS 的方式。使用这种方式,所有的 CSS 代码只存在于单独的 CSS 文件中,所以具有良好的可维护性。并且所有的 CSS 代码只存在于 CSS 文件中,CSS 文件会在第一次加载时引入,以后切换页面时只需加载 HTML 文件即可。

导入方式

导入方式指的是使用 CSS 规则引入外部 CSS 文件。

示例:

1
2
3
<style>     
@import url(style.css);
</style>

比较链接方式和导入方式

链接方式(下面用 link 代替)和导入方式(下面用 @import 代替)都是引入外部的 CSS 文件的方式,下面我们来比较这两种方式,并且说明为什么不推荐使用 @import

  • link 属于 HTML,通过 <link>标签中的 href 属性来引入外部文件,而 @import 属于 CSS,所以导入语句应写在 CSS 中,要注意的是导入语句应写在样式表的开头,否则无法正确导入外部文件;
  • @import 是 CSS2.1 才出现的概念,所以如果浏览器版本较低,无法正确导入外部样式文件;
  • 当 HTML 文件被加载时,link 引用的文件会同时被加载,而 @import 引用的文件则会等页面全部下载完毕再被加载;
  • 小结:我们应尽量使用<link> 标签导入外部 CSS 文件,避免或者少用使用其他三种方式。

@ 规则

CSS 的 @rules(读作“at-rules”)是一些特殊的规则,提供了关于 CSS 应该执行什么或如何表现的指令。有些@规则很简单,只有一个关键词和一个值。例如,@import 将一个样式表导入另一个 CSS 样式表:

1
@import "styles2.css";

一个常见的@规则是 @media,它被用来创建媒体查询。媒体查询使用条件逻辑来应用 CSS 样式。

在下面的例子中,样式表为 <body> 元素定义了一个默认的粉红色背景。然而,如果浏览器的视口宽于 30em,接下来的媒体查询则定义了蓝色背景。

1
2
3
4
5
6
7
8
9
body {
background-color: pink;
}

@media (min-width: 30em) {
body {
background-color: blue;
}
}

层叠、优先级和继承

CSS 语言有一些规则来控制在发生冲突的情况下哪个选择器更强大。这些规则被称为层叠(cascade)和优先级(specificity)。也有继承的概念,也就是在默认情况下,一些 css 属性继承当前元素的父元素上设置的值,有些则不继承。这也可能导致一些和期望不同的结果。

层叠

样式表层叠——简单的说,就是 CSS 规则的顺序很重要;当应用两条同级别的规则到一个元素的时候,写在后面的就是实际使用的规则

  • 层叠:后面的样式会替换样式表中较早出现的冲突样式。

有三个因素需要考虑,根据重要性排序如下,后面的更重要:

  • 资源顺序

    • 如果你有超过一条规则,而且都是相同的权重,那么最后面的规则会应用。可以理解为后面的规则覆盖前面的规则,直到最后一个开始设置样式。资源顺序仅在规则的优先级相同时才体现出来。
  • 优先级

    • 在一些情况下,有些规则在最后出现,但是却应用了前面的具有冲突的规则。这是因为前面的有更高的优先级——它范围更小,因此浏览器就把它选择为元素的样式。
    • 类选择器的权重大于元素选择器,因此类上定义的属性将覆盖应用于元素上的属性。
    • 一种常见的做法是给基本元素定义通用样式,然后给不同的元素创建对应的类。
    • 本质上,不同类型的选择器有不同的分数值,把这些分数相加就得到特定选择器的权重,然后就可以进行匹配。一个选择器的优先级可以说是由三个不同的值(或分量)相加,可以认为是百(ID)十(类)个(元素)——三位数的三个位数:
      • ID:选择器中包含 ID 选择器则百位得一分。
      • :选择器中包含类选择器、属性选择器或者伪类则十位得一分。
      • 元素:选择器中包含元素、伪元素选择器则个位得一分。

选择器 ID 元素 优先级
h1 0 0 1 0-0-1
h1 + p::first-letter 0 0 3 0-0-3
li > a[href*=”en-US”] > .inline-warning 0 2 2 0-2-2
#identifier 1 0 0 1-0-0
button:not(#mainBtn, .cta) 1 0 1 1-0-1

备注: 通用选择器(*)、组合符(+、>、~、’ ‘)和调整优先级的选择器(:where())不会影响优先级。

  • 重要程度

    • 内联样式,即style属性内的样式声明,优先于所有普通的样式,无论其优先级如何。这样的声明没有选择器,但它们的优先级可以理解为 1-0-0-0;即无论选择器中有多少个 ID,它总是比其他任何优先级的权重都要高。
    • !important,有一个特殊的 CSS 可以用来覆盖所有上面所有优先级计算,不过需要很小心的使用。用于修改特定属性的值,能够覆盖普通规则的层叠。
      • 了解 !important 是为了在阅读别人代码的时候知道有什么作用。但是,强烈建议除了非常情况不要使用它。!important 改变了层叠的常规工作方式,它会使调试 CSS 问题非常困难,特别是在大型样式表中。

优先级

浏览器是根据优先级来决定当多个规则有不同选择器对应相同的元素的时候需要使用哪个规则。它基本上是一个衡量选择器具体选择哪些区域的尺度:

  • 一个元素选择器不是很具体,则会选择页面上该类型的所有元素,所以它的优先级就会低一些。
  • 一个类选择器稍微具体点,则会选择该页面中有特定 class 属性值的元素,所以它的优先级就要高一点。
  • 优先级:类选择器>元素选择器

继承

继承也需要在上下文中去理解——一些设置在父元素上的 CSS 属性是可以被子元素继承的,有些则不能。

  • 像 width、margin、padding 和 border 不会被继承。

  • CSS 为控制继承提供了五个特殊的通用属性值。

    • inherit:设置该属性会使子元素属性和父元素相同。实际上,就是“开启继承”。
    • initial:将应用于选定元素的属性值设置为该属性的初始值
    • unset:将属性重置为自然值,也就是如果属性是自然继承那么就是inherit,否则和 initial 一样。
    • revert:将应用于选定元素的属性值重置为浏览器的默认样式,而不是应用于该属性的默认值。在许多情况下,此值的作用类似于 unset。
    • revert-layer:将应用于选定元素的属性值重置为在上一个层叠层中建立的值。
    • CSS 的简写属性 all 可以用于同时将这些继承值中的一个应用于(几乎)所有属性。它的值可以是其中任意一个(inherit、initial、unset 或 revert)。这是一种撤销对样式所做更改的简便方法,以便回到之前已知的起点

层叠层

使用来自多个源的 CSS,或当存在冲突的 CSS 选择器和竞争优先级时,又或者当你考虑使用 !important(en-US) 时,层叠层最为相关。

有三种层叠来源类型:用户代理样式表、用户样式表和作者样式表。“用户代理”指的是浏览器。“用户”指的是是网站访问者。“作者”指的是你,开发者。

层叠层的优先权顺序

类似于我们有六个基于来源和重要性的优先权级别,层叠层使我们能够在这些来源中创建子来源级别的优先权。

在六个来源中的每一个,都可以有多个层叠层。层创建的顺序非常重要。层创建的顺序确定了同一来源内层的优先权顺序。

普通来源中,层按照创建的顺序排序。优先权顺序是从首个创建的层到最后一个层,然后是未分层的普通样式。

对于重要样式,这个顺序是相反的。所有未分层的重要样式会层叠在一起,形成一个隐式层,优先权高于所有非过渡的普通样式。未分层的重要样式的优先权低于任何重要分层样式。在同一来源内,先前声明的层中的重要样式优先于后续声明的层中的重要样式。

层叠层可以解决的问题

大型代码库可能会有来自多个团队、组件库、框架和第三方的样式。无论包含了多少样式表,所有这些样式都会层叠在一个单一的来源中:作者样式表。

将许多来源的样式层叠在一起,特别是来自不同团队的样式,可能会导致问题。优先级冲突可能会迅速升级。Web 开发人员可能通过添加 !important 标志来进行“快速修复”。虽然这可能看起来是一种简单的解决方案,但它通常只是将优先级战争从普通声明转移到重要声明。

就像层叠来源在用户、用户代理和作者样式之间提供了力量平衡一样,层叠层提供了一种结构化的方式来组织和平衡单一来源内的关注点,就好像来源中的每个层都是一个子来源。可以为每个团队、组件和第三方创建一个层,其中的样式优先权基于层的顺序。

层内的规则层叠在一起,而不会与层外的样式规则竞争。层叠层使得可以优先考虑整个样式表而不必担心这些子来源之间的优先级。层的优先权始终高于选择器的优先级。

嵌套层叠层可以解决的问题

层叠层允许创建嵌套层。每个层叠层可以包含嵌套层。

嵌套层的能力非常适用于开发组件库、框架、第三方小部件和主题的任何人。

创建层叠层

可以使用以下任一方法创建层叠层:

  • 使用 @layer 声明 at 规则,使用 @layer 后跟一个或多个层的名称来声明层。这将创建一个没有分配任何样式的具名层。
  • 使用 @layer 块 at 规则,在块中的所有样式都将添加到一个命名或未命名的层中。
  • 使用具有 layer 关键字或 layer() 函数的 @import 规则,将导入文件的内容分配到该层中。

用于具名层的 @layer 声明 at 规则

使用 @layer 后跟一个或多个层的名称而不分配任何样式是定义层顺序的一种方式。

1
@layer theme,layout,utilities;

如果上述声明是站点 CSS 的第一行,那么层的顺序将是 theme、layout 和 utilities。如果在上述语句之前已经创建了一些层,只要同名的层还不存在,这三个层就会被创建并添加到现有层列表的末尾。但是,如果同名的层已经存在,那么上述语句只会创建两个新层。例如,如果 layout 已经存在,只会创建 theme 和 utilities, 但在这种情况下的层顺序将是 layout、theme 和 utilities。

优先级从前到后越来越高,utilities优先级最高。

用于具名层和匿名层的 @layer 块 at 规则

如果在使用 @layer 创建块样式时没有指定名称,则该规则中的样式将被添加到一个新的匿名层中。

示例中,使用了四个块和一个内联的 @layer at 规则:

  1. 创建一个命名的 layout 层
  2. 创建一个未命名的匿名层
  3. 声明三个层的列表并只创建两个新层 theme 和 utilities,因为 layout 已经存在
  4. 向已经存在的 layout 层添加额外的样式
  5. 创建第二个未命名的匿名层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* 文件:layers1.css */

/* 未分层的样式 */
body {
color: #333;
}

/* 创建第一个层:`layout` */
@layer layout {
main {
display: grid;
}
}

/* 创建第二个层:一个未命名的匿名层 */
@layer {
body {
margin: 0;
}
}

/* 创建第三和第四个层:`theme` 和 `utilities` */
@layer theme,layout,utilities;
/* 向已经存在的 `layout` 层添加样式 */
@layer layout {
main {
color: #000;
}
}

/* 创建第五个层:一个未命名的匿名层 */
@layer {
body {
margin: 1vw;
}
}

在上面的 CSS 中,我们创建了五个层:layout、<anonymous(01)>、theme、utilities 和 <anonymous(02)>——按这个顺序——第六个隐含的未分层样式层包含在 body 样式块中。层的顺序是层的创建顺序,前面的优先级低于后面的优先级。未分层样式的隐含层总是在最后的,优先级最高。一旦创建了层之后就无法改变层的顺序

层创建和媒体查询

如果你使用媒体特性查询来定义层,且媒体不匹配或特征不被支持,则不会创建该层。

下面的示例展示了改变设备或浏览器的尺寸可能会改变层的顺序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@media (min-width: 50em) {
@layer site;
}

@layer page {
h1 {
text-decoration: overline;
color: red;
}
}

@layer site {
h1 {
text-decoration: underline;
color: green;
}
}

宽屏上,site 层在第一行被声明,这意味着 site 的优先权低于 page。否则在窄屏上,site 的优先权高于 page,因为它在后面被声明。

使用 @import 将样式表导入具名层和匿名层

@import 规则允许用户直接从其他样式表导入样式规则到 CSS 文件或<style> 元素中。

可以将样式表导入具名层、嵌套具名层或匿名层。

以下层分别将样式表导入 components 层、components 层中的嵌套 dialog 层和一个未命名层:

1
2
3
@import url("components-lib.css") layer(components);
@import url("dialog.css") layer(components.dialog);
@import url("marketing.css") layer();

你可以使用媒体查询特性查询根据特定条件导入样式并创建层。

以下将样式表导入到 international 层,但前提是浏览器支持 display: ruby,而且被导入的文件取决于屏幕的宽度。

1
2
3
4
@import url("ruby-narrow.css") layer(international) supports(display: ruby) and
(width < 32rem);
@import url("ruby-wide.css") layer(international) supports(display: ruby) and
(width >= 32rem);

嵌套层的概述

嵌套层是具名层或匿名层中的子层。每个层叠层(即使是匿名的)都可以包含嵌套层。导入到另一个层中的层会成为该层中的嵌套层。

嵌套层的优点

嵌套层的能力使团队可以创建层叠层,而不用担心其他团队会将它们导入到一个层中。同样,嵌套使你可以将第三方样式表导入到一个层中,而不用担心该样式表本身是否具有层。因为层可以嵌套,所以你不必担心外部和内部样式表之间会有冲突的层名称

创建嵌套层叠层

嵌套层可以使用与常规层相同的方法创建。例如,可以使用点表示法,在 @layer 规则后跟一个或多个层名称来创建。多个点和层名称表示多重嵌套

1
2
@import url("components-lib.css") layer(components);
@import url("narrowtheme.css") layer(components.narrow);

在第一行中,我们将 components-lib.css 导入 components 层。如果该文件包含任何层,无论命名与否,这些层都会成为 components 层中的嵌套层。

第二行将 narrowtheme.css 导入 narrow 层,narrow 是 components 的子层。嵌套的 components.narrow 会作为 components 层中的最后一个层创建,除非 components-lib.css 已经包含一个 narrow 层,在这种情况下,narrowtheme.css 的内容会被附加到 components.narrow 嵌套层。可以使用 components.<layerName> 模式向 components 层添加更多命名嵌套层。如前所述,可以创建未命名层,但随后无法访问它们。

根据层的顺序确定优先权

层的顺序决定了它们的优先权顺序。因此,层的顺序非常重要。与层叠根据来源和重要性进行排序的方式相同,层叠也会根据来源层和重要性对每个 CSS 声明进行排序。

常规层叠层的优先权顺序

1
2
3
@import url(A.css) layer(firstLayer);
@import url(B.css) layer(secondLayer);
@import url(C.css);

上述代码创建了两个具名层和一个未命名层。假设这三个文件(A.css、 B.css 和 C.css)本身不包含任何额外的层。以下列表显示了在这些文件内外声明的样式将以从最低(1)优先权到最高(10)优先权进行排序。

  1. firstLayer 普通样式(A.css)
  2. secondLayer 普通样式(B.css)
  3. 未分层普通样式(C.css)
  4. 内联普通样式
  5. 动画样式
  6. 未分层重要样式(C.css)
  7. secondLayer 重要样式(B.css)
  8. firstLayer 重要样式(A.css)
  9. 内联重要样式
  10. 过渡样式

在层中声明的普通样式具有最低的优先权,并按照创建层的顺序进行排序。在最先创建的层中声明的普通样式具有最低的优先权,而在最后创建的层中声明的普通样式在所有层中具有最高的优先权。换句话说,如果存在冲突的话,在 firstLayer 中声明的普通样式将被列表中任何后续的样式覆盖。

接下来是在层外声明的任何样式。C.css 中的样式没有导入到层中,并将覆盖任何来自 firstLayer 和 secondLayer 的冲突样式。在层外声明的普通样式总是比层内的普通样式具有更的优先权。

过渡样式具有最高的优先权。当正在过渡普通属性值时,它优先于所有其他属性值声明,甚至是内联重要样式;但是只在过渡时。

总结:

  • 层的优先权顺序是创建层的顺序。
  • 一旦创建,就无法更改层顺序。
  • 普通样式的层优先权是创建层的顺序。
  • 未分层普通样式优先于有层普通样式。
  • 重要样式的层优先权被反转,早期创建的层具有优先权。
  • 所有有层的重要样式都优先于未分层的重要(和普通)样式。
  • 普通内联样式优先于所有普通样式,无论是否分层。
  • 重要内联样式优先于所有其他样式,正在过渡的样式除外。
  • 作者样式无法覆盖重要内联样式(过渡除外,但这是临时的)。

嵌套层叠层的优先权顺序

嵌套层的层叠优先权顺序与常规层类似,但包含在层内。优先权顺序基于嵌套层创建的顺序。层中的非嵌套样式优先于嵌套的普通样式,对于重要样式则相反。嵌套层之间的优先级权重并不重要,但它在嵌套层内的冲突样式中确实很重要

下面创建并向 components 层和 components.narrow 嵌套层添加样式,然后创建并追加样式到新的 components.wide 层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@import url("components-lib.css") layer(components);
@import url("narrowtheme.css") layer(components.narrow);

@layer components {
:root {
--theme: red;
font-family: serif !important;
}
}
@layer components.narrow {
:root {
--theme: blue;
font-family: sans-serif !important;
}
}
@layer components.wide {
:root {
--theme: purple;
font-family: cursive !important;
}
}

因为未分层普通样式优先于分层普通样式,并且在层内,非嵌套样式优先于普通嵌套样式,所以 red 优先于其他 theme 颜色。

对于重要样式分层样式优先未分层样式,并且早期声明的层中的重要样式优先后来声明的层。在这个例子中,嵌套层的创建顺序是 components.narrow,然后是 components.wide,所以 components.narrow 中的重要样式优先于 components.wide 中的重要样式,这意味着 sans-serif 获胜。

盒模型

块级盒子(Block box)和 内联盒子(Inline box)

在 CSS 中我们广泛地使用两种“盒子” —— 块级盒子 (block box) 和 内联盒子 (inline box)。这两种盒子会在页面流(page flow)和元素之间的关系方面表现出不同的行为:

一个被定义成块级的(block)盒子会表现出以下行为:

  • 盒子会在内联的方向上扩展并占据父容器在该方向上的所有可用空间,在绝大数情况下意味着盒子会和父容器一样宽
  • 每个盒子都会换行
  • width 和 height 属性可以发挥作用
  • 内边距(padding), 外边距(margin)和 边框(border)将其他元素从当前盒子周围“推开

除非特殊指定,诸如标题 (<h1>等) 和段落 (<p>) 默认情况下都是块级的盒子。

如果一个盒子对外显示为 inline,那么他的行为如下:

  • 盒子不会产生换行
  • width 和 height 属性将不起作用
  • 垂直方向的内边距、外边距以及边框会被应用但是不会把其他处于 inline 状态的盒子推开
  • 水平方向的内边距、外边距以及边框会被应用且把其他处于 inline 状态的盒子推开

用做链接的 <a> 元素、<span><em> 以及 <strong> 都是默认处于 inline 状态的。

通过对盒子display 属性的设置,比如 inline 或者 block ,来控制盒子的外部显示类型。

什么是 CSS 盒模型

完整的 CSS 盒模型应用于块级盒子,内联盒子只使用盒模型中定义的部分内容。模型定义了盒的每个部分 —— margin, border, padding, and content —— 合在一起就可以创建我们在页面上看到的内容。为了增加一些额外的复杂性,有一个标准的和替代(IE)的盒模型。

盒模型的各个部分

CSS 中组成一个块级盒子需要:

  • Content box: 这个区域是用来显示内容,大小可以通过设置 width 和 height.
  • Padding box: 包围在内容区域外部的空白区域;大小通过 padding 相关属性设置。
  • Border box: 边框盒包裹内容和内边距。大小通过 border 相关属性设置。
  • Margin box: 这是最外面的区域,是盒子和其他元素之间的空白区域。大小通过 margin 相关属性设置。

标准盒模型

在标准模型中,如果你给盒设置 width 和 height,实际设置的是 content box。padding 和 border 再加上设置的宽高一起决定整个盒子的大小。见下图。

假设定义了 width, height, margin, border, and padding:

1
2
3
4
5
6
7
.box {
width: 350px;
height: 150px;
margin: 25px;
padding: 25px;
border: 5px solid black;
}

如果使用标准模型,实际占用空间的宽高分别为:宽度 = 410px (350 + 25 + 25 + 5 + 5),高度 = 210px (150 + 25 + 25 + 5 + 5)。

margin 不计入实际大小 —— 当然,它会影响盒子在页面所占空间,但是影响的是盒子外部空间。盒子的范围到边框为止 —— 不会延伸到 margin。

替代(IE)盒模型

css 还有一个替代盒模型。使用这个模型,所有宽度都是可见宽度,所以内容宽度是该宽度减去边框和填充部分。使用上面相同的样式得到 (width = 350px, height = 150px).

默认浏览器会使用标准模型。如果需要使用替代模型,你可以通过为其设置 box-sizing: border-box 来实现。这样就可以告诉浏览器使用 border-box 来定义区域,从而设定你想要的大小。

外边距折叠

理解外边距的一个关键是外边距折叠的概念。如果你有两个外边距相接的元素,这些外边距将合并为一个外边距,即最大的单个外边距的大小

在下面的例子中,我们有两个段落。顶部段落的页 margin-bottom为 50px。第二段的margin-top 为 30px。因为外边距折叠的概念,所以框之间的实际外边距是 50px,而不是两个外边距的总和。

使用 display: inline-block

display 有一个特殊的值,它在内联和块之间提供了一个中间状态。这对于以下情况非常有用:你不希望一个项切换到新行,但希望它可以设定宽度和高度,并避免上面看到的重叠。

一个元素使用 display: inline-block,实现我们需要的块级的部分效果:

  • 设置width 和height 属性会生效。
  • padding, margin, 以及border 会推开其他元素。

但是,它不会跳转到新行,如果显式添加 width 和 height 属性,它只会变得比其内容更大。

当你想要通过添加内边距使链接具有更大的命中区域时,这是很有用的。<a> 是像 <span>一样的内联元素;你可以使用 display: inline-block 来设置内边距,让用户更容易点击链接。

这种情况在导航栏中很常见。

背景

控制背景平铺行为

background-repeat 属性用于控制图像的平铺行为。可用的值是:

  • no-repeat——阻止背景重复平铺。
  • repeat-x——仅水平方向上重复平铺。
  • repeat-y——仅垂直方向上重复平铺。
  • repeat——默认值,在水平和垂直两个方向重复平铺。

调整背景图像的大小

使用 background-size 属性,它可以设置长度或百分比值,来调整图像的大小以适应背景。

也可以使用关键字:

  • cover:浏览器将使图像足够大,使它完全覆盖了盒子区域,同时仍然保持其宽高比。在这种情况下,图像的部分区域可能会跳出盒子外
  • contain:浏览器会将图像调整到适合框内的尺寸。在这种情况下,如果图像的长宽比与盒子的长宽比不同,你可能会在图像的两边或顶部和底部出现空隙

背景图像定位

background-position 属性允许你选择背景图片出现在它所应用的盒子上的位置。这使用了一个坐标系统,其中方框的左上角是 (0,0),方框沿水平(x)和垂直(y)轴定位。

默认的 background-position 值是 (0,0)。

渐变背景

当渐变用于背景时,也可以使用像图像一样的 background-image 属性设置。

<gradient> 数据类型是由下面列出的函数类型中的一个定义的。

线性渐变

线性渐变会在一个假想的直线上过渡颜色。线性渐变是由 linear-gradient() 函数产生的。

径向渐变

径向渐变从一个中间点(原点)开始过渡颜色。径向渐变是由 radial-gradient() 函数产生的。

重复渐变

重复渐变可根据需要复制渐变,以填充指定区域。重复渐变是使用 repeating-linear-gradient() 和 repeating-radial-gradient() 函数生成的。

锥形渐变

锥形渐变会沿着一个圆过渡颜色。锥形渐变是由 conic-gradient() 函数产生的。

多个背景图像

也可以有多个背景图像——在单个属性值中指定多个 background-image 值,用逗号分隔每个值。

当你这样做时,你可能会出现背景图片相互重叠的情况。背景将分层,最后列出的背景图片位于最下层,而之前的每张图片都堆在代码中紧随其后的那张图片之上。

渐变可以与常规的背景图像很好地混合在一起。

背景附加

为背景提供的另一个选项是指定内容滚动时的滚动方式。这是用 background-attachment 属性控制的,它可以取以下值:

  • scroll:使元素的背景在页面滚动时滚动。如果滚动了元素内容,则背景不会移动。实际上,背景被固定在页面的相同位置,所以它会随着页面的滚动而滚动。
  • fixed:使元素的背景固定在视口上,这样当页面或元素内容滚动时,它就不会滚动。它将始终保持在屏幕上相同的位置。
  • local:将背景固定在它所设置的元素上,所以当你滚动该元素时,背景也随之滚动

使用 background 简写属性

在简写背景图像属性时遵循,例如:

  • background-color 只能在最后一个逗号之后指定。
  • background-size 值只能立即包含在 background-position 之后,用“/”字符分隔,例如:center/80%。

处理不同方向的文本

使用writing-mode: vertical-rl对一个标题的显示进行设置。现在,标题文本是竖向的了。

1
2
3
h1 {
writing-mode: vertical-rl;
}

writing-mode的三个值分别是:

  • horizontal-tb: 块流向从上至下。对应的文本方向是横向的。
  • vertical-rl: 块流向从右向左。对应的文本方向是纵向的。
  • vertical-lr: 块流向从左向右。对应的文本方向是纵向的。

逻辑属性和逻辑值

两个盒子——一个用horizontal-tb设定了书写模式,一个用vertical-rl设定了书写模式。我为这两个盒子分别设定了宽度( width)。可以看到,当盒子处于纵向书写模式下时,宽度也发生了变化,从而导致文本超出了盒子的范围。

当处于纵向书写模式之下时,我们希望盒子可以向横向模式下一样得到拓宽。

为了更容易实现这样的转变,CSS 最近开发了一系列映射属性。这些属性用逻辑logical)和相对变化flow relative)代替了像宽width和高height一样的物理属性。

横向书写模式下,映射到width的属性被称作内联尺寸(inline-size——内联维度的尺寸。而映射height的属性被称为块级尺寸(block-size,这是块级维度的尺寸。

逻辑外边距、边框和内边距属性

margin-top属性的映射是margin-block-start——总是指向块级维度开始处的边距。

padding-left属性映射到 padding-inline-start,这是应用到内联开始方向(这是该书写模式文本开始的地方)上的内边距。

border-bottom属性映射到的是border-block-end,也就是块级维度结尾处的边框。

逻辑值

有一些属性的取值是一些物理值(如top、right、bottom和left)。这些值同样拥有逻辑值映射(block-startinline-endblock-endinline-start

溢出的内容(BFC)

什么是溢出?

CSS 中万物皆盒,因此我们可以通过给 width 和 height(或者 inline-size 和 block-size)赋值的方式来约束盒子的尺寸。溢出是在你往盒子里面塞太多东西的时候发生的,所以盒子里面的东西也不会老老实实待着。

CSS 尽力减少“数据损失”

只要有可能,CSS 就不会隐藏你的内容,隐藏引起的数据损失通常会造成困扰。在 CSS 的术语里面,这会导致一些内容消失,你的访客可能不会注意到这一点,如果消失的是表格上的提交按钮,没有人能填完这个表格,这是很麻烦的事情!所以 CSS 反而会把它以可见的形式溢出出去。这样做的结果就是,你会看到错误的 CSS 导致的一片混乱,或者最坏的情况也只是你的网站的访客会告诉你有些内容冒了出来,你的网站需要修缮。

overflow 属性

overflow属性是你控制一个元素溢出的方式,它告诉浏览器你想怎样处理溢出。

overflow 的默认值为 visible,这就是我们的内容溢出的时候,我们在默认情况下看到它们的原因。

如果你想在内容溢出的时候把它裁剪掉,你可以在你的盒子上设置 overflow: hidden。这就会像它表面上所显示的那样作用——隐藏掉溢出。这可能会很自然地让东西消失掉,所以你只应该在判断隐藏内容不会引起问题的时候这样做。

在有内容溢出的时候加个滚动条?如果你用了 overflow: scroll,那么你的浏览器总会显示滚动条,即使没有足够多引起溢出的内容。你可能会需要这样的样式,它避免了滚动条在内容变化的时候出现和消失。

想让滚动条在有比盒子所能装下更多的内容的时候才显示,那么使用 overflow: auto

如果你真的需要在小盒子里面和长英文词打交道,那么你可能要了解一下 word-break 或者 overflow-wrap 属性。

区别和选择:

  • overflow-wrap 主要关注的是如何处理整个单词的换行,而 word-break 更侧重于在何处断开换行,即使这涉及到单词内部的断行。
  • 在处理非拉丁字符(例如中文、日文)时,word-break: break-all; 会在字符之间插入换行,而 overflow-wrap: break-word; 不会。

通常情况下,如果你更关注整个单词的处理,可以使用 overflow-wrap,而如果你更关注在非拉丁字符之间的处理,可以使用 word-break。在某些情况下,你可能需要同时使用这两个属性以达到期望的效果。

溢出建立了区块格式化上下文

CSS 中有所谓区块格式化上下文(Block Formatting Context,BFC)的概念。在你使用诸如 scroll 或者 auto 的时候,你就建立了一个块级排版上下文。结果就是,你改变了 overflow 的值的话,对应的盒子就变成了更加小巧的状态。在容器之外的东西没法混进容器内,也没有东西可以突出盒子,进入周围的版面。激活了滚动动作,你的盒子里面所有的内容会被收纳,而且不会遮到页面上其他的物件,于是就产生了一个协调的滚动体验。

CSS 的值与单位

在 CSS 规范和 MDN 的属性页上,你将能够发现值的存在,因为它们将被尖括号包围,如 <color><length>。当你看到值 <color> 对特定属性有效时,这意味着你可以使用任何有效的颜色作为该属性的值。

你还将看到被称为数据类型的 CSS 值。这些术语基本上是可以互换的——当你在 CSS 中看到一些被称为数据类型的东西时,它实际上只是一种表示值的奇特方式。

CSS 值倾向于使用尖括号表示,以区别于 CSS 属性(例如 color 属性和 <color> 数据类型)。你可能还会混淆 CSS 数据类型和 HTML 元素,因为它们都使用尖括号,但这不太可能——它们在完全不一样的上下文中使用。

在 CSS 中使用了各种数值数据类型。以下全部归类为数值:

数值类型 描述
<integer> <integer>是一个整数,比如 1024 或 -55。
<number> <number> 表示一个小数——它可能有小数点后面的部分,也可能没有,例如 0.255、128 或 -1.2。
<dimension> <dimension> 是一个 <number> 它有一个附加的单位,例如 45deg、5s 或 10px。<dimension> 是一个伞形类别,包括 <length><angle><time><resolution> 类型。
<percentage> <percentage> 表示一些其他值的一部分,例如 50%。百分比值总是相对于另一个量。例如,一个元素的长度相对于其父元素的长度。

在 CSS 中调整大小

原始尺寸,或固有尺寸

在受 CSS 设置影响之前,HTML 元素有其原始的尺寸。一个直观的例子就是图像。一幅图像的长和宽由这个图像文件自身确定。这个尺寸就是固有尺寸。

元素的固有尺寸是由其所包含的内容决定。

设置具体的尺寸

当给元素指定尺寸(然后其内容需要适合该尺寸)时,我们将其称为外部尺寸。以上面例子中的 <div> 举例——我们可以给它一个具体的 widthheight 值,然后不论我们放什么内容进去它都是该尺寸。

由于存在溢出问题,在网络上使用长度或百分比固定元素的高度需要非常小心

使用百分数:

当使用百分数时,你需要清楚,它是什么东西的百分数。对于一个处于另外一个容器当中的盒子,如果你给予了子盒子一个百分数作为宽度,那么它指的是父容器宽度的百分数。

使用百分比作为元素外边距(margin)或填充(padding)的单位时,值是以包含块的内联尺寸进行计算的,也就是元素的水平宽度。

min- 和 max- 尺寸:

如果你有一个包含了变化容量的内容的盒子,而且你总是想让它至少有个确定的高度,你应该给它设置一个 min-height 属性。盒子就会一直保持大于这个最小高度,但是如果有比这个盒子在最小高度状态下所能容纳的更多内容,那么盒子就会变大。这在避免溢出的同时并处理变化容量的内容的时候是很有用的。

max-width 的常见用法为,在没有足够空间以原有宽度展示图像时,让图像缩小,同时确保它们不会比这一宽度大。这个技术是用来让图片可响应的,所以在更小的设备上浏览的时候,它们会合适地缩放。

视口单位:

视口,即你在浏览器中看到的部分页面,也是有尺寸的。在 CSS 中,我们有与视口尺寸相关的度量单位,即意为视口宽度的 vw 单位,以及意为视口高度的 vh 单位。使用这些单位,你可以把一些东西做得随用户的视口改变大小。

1vh 等于视口高度的 1%,1vw 则为视口宽度的 1%。

如果你改变了 vh 和 vw 的对应值,盒子和字体的大小也会改变;视口大小的变化也会让它们的大小变化,因为它们是依照视口来定大小的。根据视口改变物件的大小是很有用的。

图像、媒体

替换元素

图像和视频被描述为替换元素。这意味着 CSS 不能影响它们的内部布局——而仅影响它们在页面上相对于其他元素的位置。但是,正如我们将看到的,CSS 可以对图像执行多种操作。

某些替换元素(例如图像和视频)也具有宽高比。这意味着它在水平(x)和垂直(y)方向上均具有大小,并且默认情况下将使用文件的固有尺寸进行显示。

调整图像大小

下面的示例中有两个盒子,长宽均为 200 像素:

  • 一个包含了一张小于 200 像素的图像,它比盒子小,并且不会自动拉伸来充满盒子。
  • 另一张图像大于 200 像素,溢出了盒子。

那么该如何处理溢出问题呢?

一个常用的方法是将一张图片的max-width设为100% 。这将会使图片的尺寸小于等于盒子。这个技术也会对其他替换元素(例如 <video>,或者 <iframe> 起作用)。

想把一张图像调整到能够完全盖住一个盒子的大小。object-fit 属性可以在这里帮助你。当使用 object-fit 时,替换元素可以以多种方式被调整到合乎盒子的大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.box {
width: 200px;
height: 200px;
}

img {
height: 100%;
width: 100%;
}

.cover {
object-fit: cover;
}

.contain {
object-fit: contain;
}

  • 使用了值 cover 来缩小图像,同时维持了图像的原始比例。这样图像就可以充满盒子。但由于比例保持不变,图像多余的一部分将会被盒子裁切掉。
  • 使用值 contain,图像就会被缩放到足以完整地放到盒子里面的大小。
  • fill 值,它可以让图像充满盒子,但是不会维持比例

布局中的替换元素

在对替换元素使用各种 CSS 布局时,你可能会发现他们的表现方式与其他元素有一些细节上的差异。例如,flex 或者 grid 布局中,默认情况下元素会被拉伸到充满整块区域。但是图像不会被拉伸,而会对齐到网格区域或者弹性容器的起始处。

替换元素在成为网格或者弹性布局的一部分时,有不同的默认行为。这一默认行为很有必要,因为它避免了替换元素被布局拉伸成奇怪的样子。

样式化表格

列出了有用的点:

  • 使你的表格标记尽可能简单,并且保持灵活性,例如使用百分比,这样设计就更有响应性。
  • 使用 table-layout: fixed 创建更可控的表布局,可以通过在标题width中设置width来轻松设置列的宽度。
  • 使用 border-collapse: collapse 使表元素边框合并,生成一个更整洁、更易于控制的外观。
  • 使用<thead>, <tbody><tfoot> 将表格分割成逻辑块,并提供额外的应用 CSS 的地方,因此如果需要的话,可以更容易地将样式层叠在一起。
  • 使用斑马线来让其他行更容易阅读。
  • 使用 text-align直线对齐你的<th><td>文本,使内容更整洁、更易于跟随。
  • caption-side: bottom属性使标题被放置在表格的底部。
作者

冷冷

发布于

2019-05-09

更新于

2020-10-10

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×