Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

根据前端技能树补缺CSS知识

CSS基础

CSS语法

一门基于规则的语言

语法结构:

  • 一个选择器开头
  • 一对大括号
  • 多个属性-值对的声明

@规则

供了关于 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的如何运行

下面是浏览器加载网页的基本步骤(不同浏览器略有不同,但基本步骤都会包含):

  1. 浏览器载入HTML文件
  2. 将HTML转化为一个DOM(Document Object Model),DOM 是文件在计算机内存中的表现形式
  3. 浏览器拉取HTML相关资源,例如:图片、视频、CSS样式,稍后会处理JS
  4. 浏览器解析CSS,根据选择器类型分到不同的桶,浏览器通过这些桶找到不同的选择器,将不同的规则(基于选择器的规则,如元素选择器、类选择器、id 选择器等)应用到DOM节点中并添加节点依赖的样式(这个中间步骤称为渲染树)。
  5. 上述的规则应用于渲染树之后,渲染树会依照应该出现的结构进行布局。
  6. 网页展示在屏幕上(这一步被称为着色

img

DOM

一个DOM有一个树形结构,标记语言中的每一个元素、属性、以及每一段文字都对应着结构树中的一个节点(Node/DOM 或 DOM node)

当你使用浏览器 F12 调试的时候你需要操作 DOM 以查看使用了哪些规则

以下列 HTML 代码为例:

1
2
3
4
5
6
<p>
Let's use:
<span>Cascading</span>
<span>Style</span>
<span>Sheets</span>
</p>

在这个 DOM 中,<p>元素对应了父节点,它的子节点是一个 text 节点和三个对应了<span>元素的节点,SPAN节点同时也是他们中的 Text 节点的父节点。

1
2
3
4
5
6
7
8
P
├─ "Let's use:"
├─ SPAN
| └─ "Cascading"
├─ SPAN
| └─ "Style"
└─ SPAN
└─ "Sheets"

CSS选择器

选择器列表

使用,连接的多个选择器:

1
2
3
4
h1,
.special {
color: blue;
}

但是在被组合起来以后,如果其中一个选择器有语法错误,那么整个规则都会失效,无论是h1还是这个 class 都不会被样式化。

选择器类型

类型选择器

1
h1 { }

全局选择器

1
2
3
* {
margin: 0;
}

利用全局选择器我们可以使CSS代码更衣读,例如,如果想选中<article>元素的第一个子元素加粗:

1
2
3
article :first-child {

}

但这一操作尝尝会与article:first-child混淆,后者选择了作为其他元素的第一子元素的<article>元素。

为了避免这种混淆,我们可以向:first-child选择器加入全局选择器,这样选择器所做的事情很容易就能看懂。选择器正选中<article>元素的任何第一子元素:

1
2
3
article *:first-child {

}

类(class)选择器

1
.box { }

此外我们还可以指向特定元素的类

1
2
3
4
5
6
7
span.highlight {
background-color: yellow;
}

h1.highlight {
background-color: pink;
}

id选择器

1
#unique { }

标签属性选择器

这组选择器根据一个元素上的某个标签的属性的存在以选择元素的不同方式:

1
a[title] { }

或者根据一个有特定值的标签属性是否存在来选择:

1
a[href="https://example.com"] { }
存否和值选择器
选择器 示例 描述
[*attr*] a[title] 匹配带有一个名为attr的属性的元素——方括号里的值。
[*attr*=*value*] a[href="https://example.com"] 匹配带有一个名为attr的属性的元素,其值正为value——引号中的字符串。
[*attr*~=*value*] p[class~="special"] 匹配带有一个名为attr的属性的元素,其值正为value,或者匹配带有一个attr属性的元素,其值有一个或者更多,至少有一个和value匹配。注意,在一列中的好几个值,是用空格隔开的。
`[attr =value]` `div[lang
子字符串匹配选择器
选择器 示例 描述
[attr^=value] li[class^="box-"] 匹配带有一个名为attr的属性的元素,其值开头为value子字符串。
[attr$=value] li[class$="-box"] 匹配带有一个名为attr的属性的元素,其值结尾为value子字符串
[attr*=value] li[class*="box"] 匹配带有一个名为attr的属性的元素,其值的字符串中的任何地方,至少出现了一次value子字符串。
大小写敏感

如果想在大小写不敏感的情况下,匹配属性值的话,你可以在闭合括号之前,使用i值。

1
2
3
li[class^="a" i] {
color: red;
}

伪类与伪元素

伪类

伪类是选择器的一种,它用于选择处于特定状态的元素,比如当它们是这一类型的第一个元素时,或者是当鼠标指针悬浮在元素上面的时候。它们表现得会像是你向你的文档的某个部分应用了一个类一样,帮你在你的标记文本中减少多余的类,让你的代码更灵活、更易于维护。

伪类就是开头为冒号的关键字:

1
:pseudo-class-name
用户行为伪类

一些伪类只会在用户以某种方式和文档交互的时候应用。这些用户行为伪类,有时叫做动态伪类,表现得就像是一个类在用户和元素交互的时候加到了元素上一样。案例包括:

  • :hover
  • :forcus
伪元素

伪元素以类似方式表现,不过表现得是像你往标记文本中加入全新的 HTML 元素一样,而不是向现有的元素上应用类。伪元素开头为双冒号::

1
2
3
4
article p::first-line {
font-size: 120%;
font-weight: bold;
}

备注: 一些早期的伪元素曾使用单冒号的语法,所以你可能会在代码或者示例中看到。现代的浏览器为了保持后向兼容,支持早期的带有单双冒号语法的伪元素。

伪类用于样式化一个元素的特定状态

1
a:hover { }

伪元素即选择一个元素的某个部分而不是元素自己,例如::first-line将选择一个元素中的第一行

1
p::first-line { }
伪类和伪元素的组合
1
2
3
4
article p:first-child::first-line {
font-size: 120%;
font-weight: bold;
}
生成内容:::before::after

有一组特别的伪元素,它们和content属性一同使用,使用 CSS 将内容插入到你的文档中中。

你能用这些插入一个文本字符串,和在下面的实时示例里那样。试着改变content属性的文本值,看看输出是怎么改变的。你也能改变::before伪元素为::after,看到这段文本插入到了元素的末尾而不是开头。

还可以用来插入一些图形:

1
2
3
4
5
6
7
8
.box::before {
content: "";
display: block;
width: 100px;
height: 100px;
background-color: rebeccapurple;
border: 1px solid black;
}

注意事项

使用CSS插入文本是不推荐的,以为对于一些屏幕阅读器来说,这些文本是不可见的,而且对于未来别人的查找和编辑也是不方便的,更多的是用来插入图标

伪类参考表
选择器 描述
:active 在用户激活(例如点击)元素的时候匹配。
:any-link 匹配一个链接的:link:visited状态。
:blank 匹配空输入值的``元素
:checked 匹配处于选中状态的单选或者复选框。
:current (en-US) xxxxxxxxxx3 1input::placeholder {2    color: red3}css
:default 匹配一组相似的元素中默认的一个或者更多的 UI 元素。
:dir 基于其方向性(HTMLdir属性或者 CSSdirection属性的值)匹配一个元素。
:disabled 匹配处于关闭状态的用户界面元素
:empty 匹配除了可能存在的空格外,没有子元素的元素。
:enabled 匹配处于开启状态的用户界面元素。
:first 匹配分页媒体的第一页。
:first-child 匹配兄弟元素中的第一个元素。
:first-of-type 匹配兄弟元素中第一个某种类型的元素。
:focus 当一个元素有焦点的时候匹配。
:focus-visible 当元素有焦点,且焦点对用户可见的时候匹配。
:focus-within 匹配有焦点的元素,以及子代元素有焦点的元素。
:future (en-US) 匹配当前元素之后的元素。
:hover 当用户悬浮到一个元素之上的时候匹配。
:indeterminate 匹配未定态值的 UI 元素,通常为复选框
:in-range 用一个区间匹配元素,当值处于区间之内时匹配。
:invalid 匹配诸如<input>的位于不可用状态的元素。
:lang 基于语言(HTMLlang属性的值)匹配元素。
:last-child 匹配兄弟元素中最末的那个元素。
:last-of-type 匹配兄弟元素中最后一个某种类型的元素。
:left 分页媒体 (en-US)中,匹配左手边的页。
:link 匹配未曾访问的链接。
:local-link (en-US) 匹配指向和当前文档同一网站页面的链接。
:is() 匹配传入的选择器列表中的任何选择器。
:not 匹配作为值传入自身的选择器未匹配的物件。
:nth-child 匹配一列兄弟元素中的元素——兄弟元素按照an+b形式的式子进行匹配(比如 2n+1 匹配元素 1、3、5、7 等。即所有的奇数个)。
:nth-of-type 匹配某种类型的一列兄弟元素(比如,<p>元素)——兄弟元素按照an+b形式的式子进行匹配(比如 2n+1 匹配元素 1、3、5、7 等。即所有的奇数个)。
:nth-last-child 匹配一列兄弟元素,从后往前倒数。兄弟元素按照an+b形式的式子进行匹配(比如 2n+1 匹配按照顺序来的最后一个元素,然后往前两个,再往前两个,诸如此类。从后往前数的所有奇数个)。
:nth-last-of-type 匹配某种类型的一列兄弟元素(比如,<p>元素),从后往前倒数。兄弟元素按照an+b形式的式子进行匹配(比如 2n+1 匹配按照顺序来的最后一个元素,然后往前两个,再往前两个,诸如此类。从后往前数的所有奇数个)。
:only-child 匹配没有兄弟元素的元素。
:only-of-type 匹配兄弟元素中某类型仅有的元素。
:optional 匹配不是必填的 form 元素。
:out-of-range 按区间匹配元素,当值不在区间内的的时候匹配。
:past (en-US) 匹配当前元素之前的元素。
:placeholder-shown 匹配显示占位文字的 input 元素。
:playing 匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“播放”的元素。
:paused 匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“暂停”的元素。
:read-only 匹配用户不可更改的元素。
:read-write 匹配用户可更改的元素。
:required 匹配必填的 form 元素。
:right 分页媒体 (en-US)中,匹配右手边的页。
:root 匹配文档的根元素。
:scope 匹配任何为参考点元素的的元素。
:valid 匹配诸如<input>元素的处于可用状态的元素。
:target 匹配当前 URL 目标的元素(例如如果它有一个匹配当前URL 分段的元素)。
:visited 匹配已访问链接。
伪元素参考
选择器 描述
::after 匹配出现在原有元素的实际内容之后的一个可样式化元素。
::before 匹配出现在原有元素的实际内容之前的一个可样式化元素。
::first-letter 匹配元素的第一个字母。
::first-line 匹配包含此伪元素的元素的第一行。
::grammar-error 匹配文档中包含了浏览器标记的语法错误的那部分。
::selection 匹配文档中被选择的那部分。
::spelling-error 匹配文档中包含了浏览器标记的拼写错误的那部分。

关系选择器

最后一组选择器可以将其他选择器组合起来,更复杂的选择元素。下面的示例用运算符(>)选择了<article>元素的初代子元素:

1
article > p { }
后代选择器

使用空格隔开:

1
2
3
.box p {
color: red;
}
子代关系选择器
1
article > p { }
邻接兄弟选择器

邻接兄弟选择器(+)用来选中恰好处于另一个在继承关系上同级的元素旁边的物件。例如,选中所有紧随<p>元素之后的<img>元素:

1
2
3
4
5
6
h1 + p {
font-weight: bold;
background-color: #333;
color: #fff;
padding: .5em;
}
通用兄弟

如果你想选中一个元素的兄弟元素,即使它们不直接相邻,你还是可以使用通用兄弟关系选择器(~)。要选中所有的<p>元素后任何地方<img>元素,我们会这样做:

1
2
3
4
5
6
h1 ~ p {
font-weight: bold;
background-color: #333;
color: #fff;
padding: .5em;
}

层叠与继承

层叠

当应用两条同级别的规则到一个元素的时候,写在后面的是实际使用的规则

例如如下两条规则,将会生效后面的蓝色规则:

1
2
3
4
5
6
h1 { 
color: red;
}
h1 {
color: blue;
}

优先级

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

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

继承

某些父元素上的CSS属性可以被子元素继承例如colorfont-family是会被子元素继承的

再如width是不可继承的

关于一个属性能否被继承,可以再MDN CSS属性参考页面查看,以 color 属性的形式定义部分为例。

CSS为控制继承提供了五个特殊的通用属性值。每个CSS属性都接收这些值

  • inherit
    • 使子元素继承父元素
  • intial
    • 使应用于选定元素的属性值设置为该属性的初始值
  • revert
    • 将应用于选定元素的属性值重置为浏览器的默认样式,而不是应用于该属性的默认值。在许多情况下,此值的作用类似于 unset
  • revert-layer
    • 将应用于选定元素的属性值重置为在上一个层叠层中建立的值。
  • unset
    • 将属性重置为自然值,也就是如果属性是自然继承那么就是 inherit,否则和 initial 一样

重设所有属性值

CSS 的简写属性 all 可以用于同时将这些继承值中的一个应用于(几乎)所有属性。它的值可以是其中任意一个(inheritinitialunsetrevert)。这是一种撤销对样式所做更改的简便方法,以便回到之前已知的起点。

下面的示例中有两个块级引用元素。第一个用元素本身的样式,第二个设置 allunset

1
2
3
4
5
6
7
8
blockquote {
background-color: orange;
border: 2px solid blue;
}

.fix-this {
all: unset;
}
1
2
3
4
5
6
7
<blockquote>
<p>This blockquote is styled</p>
</blockquote>

<blockquote class="fix-this">
<p>This blockquote is not styled</p>
</blockquote>

理解层叠

需要理解层叠样式就需要考虑如下三个重点:

  1. 资源顺序
  2. 优先级
  3. 重要程度

资源顺序

资源顺序体现在:

优先级相同的样式,后面的规则将被应用

优先级

浏览器对于优先级的计算是,对不同类型的选择器给与不同的分数值,把这些分数相加就得到特定选择器的权重,然后进行匹配。

一个选择器优先级可以由三个不同的值(或分量)相加,可以认为是百(ID)- 十(类)- 个(元素)——三位数:

  • ID:类选择器中包含ID选择器则百位得一分
  • 类:选择器中包含类选择器、属性选择器或者伪类则十位得一分
  • 元素:选择器中包含元素、伪元素选择器则个位得一分

注意事项:

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

否定(:not())和任意匹配(:is())伪类本身对优先级没有影响,但它们的参数则会带来影响。参数中,对优先级算法有贡献的参数的优先级的最大值将作为该伪类选择器的优先级。

选择器 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

内联样式

style属性内的样式,可以理解为优先级分数为1-0-0-0,即无论如果内敛样式的优先级最高

!important

一个特殊的CSS用来覆盖上述所有优先级计算,但是建议除了非常情况不要使用

1
2
3
4
.better {
background-color: gray;
border: none !important;
}

注意事项

覆盖 !important 唯一的办法就是另一个 !important 具有相同优先级而且顺序靠后,或者更高优先级。

覆盖声明的顺序

相互冲突的声明将按以下顺序应用,后一种声明将覆盖前一种声明:

  1. 用户代理样式表中的声明(例如,浏览器的默认样式,在没有设置其他样式时使用)。
  2. 用户样式表中的常规声明(由用户设置的自定义样式)。
  3. 作者样式表中的常规声明(这些是我们 web 开发人员设置的样式)。
  4. 作者样式表中的 !important 声明
  5. 用户样式表中的 !important 声明
  6. 用户代理样式表中的 !important 声明

级联层的顺序

尽管级联层属于高级的主题,你可能不会立刻使用此特性,但了解层是如何级联的非常重要。

在级联层中声明 CSS 是,优先级的顺序由声明层的顺序来决定。在任何层之外声明的 CSS 样式会被按声明的顺序组合在一起,形成一个未命名的层,它会被当作最后声明的层。对于存在冲突的常规(没有 !important 声明)样式,后面的层比先前定义的层的优先级高。但对于带有 !important 标记的样式,其顺序相反——先前的层中的 important 样式比后面的层以及为在层中声明的 important 样式优先级要高。但内联样式比所有作者定义的样式的优先级都要高,不受级联层规则的影响。

当你在不同的层中有多个样式块,且其中提供了对于某一元素的单一属性的相互冲突的值时,声明该冲突样式的层的顺序将决定其优先级。而不是高优先级的层直接覆盖低优先级的层中的所有样式。需要注意的是单独的一个层中的样式的优先级仍旧会起作用。

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
@layer firstLayer, secondLayer;

p { /* 0-0-1 */
background-color: red;
color: grey !important;
border: 5px inset purple;
}
p#addSpecificity { /* 1-0-1 */
border-style: solid !important;
}

@layer firstLayer {
#addSpecificity { /* 1-0-0 */
background-color: blue;
color: white !important;
border-width: 5px;
border-style: dashed !important;
}
}

@layer secondLayer {
p#addSpecificity { /* 1-0-1 */
background-color: green;
color: orange !important;
border-width: 10px;
border-style: dotted !important;
}
}

盒模型

CSS将HTML中的元素视为一个个盒子(box),CSS中广泛使用的两种盒子有:

  • 块级盒子(block box)
  • 内联盒子(inline box)

这两种盒子的表现会有所区别

块级盒子

块级盒子会表现如下特征:

  • 盒子会在内联的方向上扩展,并占据父容器在该方向的所有空间
  • 通常情况下盒子会与父容器一样宽
  • 每个盒子独占一行
  • widthheight会起作用
  • paddingmarginborder会将其他元素推开

默认状态下为块级盒子的标签有<p><h1>

内联盒子

内联盒子会表现如下特征:

  • 盒子不会产生换行
  • widthheight不起作用
  • 垂直方向的的内边距和外边距会被应用,但不会把其他处于inline状态的盒子推开
  • 水平方向内边距和外边距会被应用且会把其他处于inline状态的盒子推开

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

可以通过属性display切换inlineblock的状态

内部和外部显示类型

盒子除了外部显示类型,还有内部显示类型。

内部显示类型决定了盒子内部元素是如何布局的,默认情况下按照正常文档流布局,即与其它内联以及快元素一样

此外,还可以通过display: flex将内部元素变为flex元素,此时外部显示类型为block,内部显示类型为felx

除了flex还有grid

inline-flex会将内部类型设置为flex的同时将外部类型设置为inline

块级和内联布局是 web 上默认的行为 —— 正如上面所述,它有时候被称为 正常文档流

什么是盒模型

完整的CSS和模型应用于块级盒子,内联盒子只使用和模型中定义的部分内容。

盒的各个部分

  • Content box:用于显示内容的区域,大小可以通过widthheight来设置
  • Padding box:包围在内容外部的空白区域,大小可以通过padding相关属性设置
  • Border box:边框包裹内容和内边距。大小通过border来设置
  • Margin box:最外层区域,与其他盒子之间的空白区域,大小通过margin设置

标准盒模型

我们尝试给一个盒模型设置width, border, padding, margin:

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

那么这个盒子的实际宽高分别是:

  • 宽度 = (350 + 25 * 2 + 5 * 2) = 410px
  • 高度 = (150 + 25 * 2 + 5 * 2) = 210px

注意事项:

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

替代(IE)盒模型

为了避免盒子大小不够直观(即计算实际宽度时还需要加上边框和内边距)CSS还提供了替代盒模型。该模型认为设置的宽度即为所有可见宽度

使用相同的配置:

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

得到的宽高为:

  • 宽 = 350px
  • 高 = 150px

这一选项通过设置box-sizing属性得到:

1
2
3
.box {
box-sizing: border-box;
}

如果希望所有模型都为替代盒模型,可以通过如下配置实现

1
2
3
4
5
6
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}

备注: 一个有趣的历史记录 ——Internet Explorer 默认使用替代盒模型,没有可用的机制来切换。(译者注:IE8+ 支持使用 box-sizing 进行切换)

margin,border,padding

margin,border,padding三者是属性的简写,允许我们一次性控制盒子的四个边

margin

margin用来推开盒子周围的元素,它总是在计算可见部分后额外添加的,包含以下四个单独控制的属性

margin可以接受负数,这样会使得其他元素与该盒子重叠

margin折叠

有时候当两个相邻盒子都设置了margin时,会发生与直觉不相符的情况。

原因时margin属性存在折叠的特性:

两个外边距相接的元素,两个外边距将会合并为一个外边距,即量大的单个外边距的大小

如果我们有下面的一段HTML

1
2
3
4
<div class="container">
<p class="one">I am paragraph one.</p>
<p class="two">I am paragraph two.</p>
</div>

接下来我们为两个p标签设置宽高

1
2
3
4
5
6
7
.one {
margin-bottom: 50px;
}

.two {
margin-top: 30px;
}

此时两个p标签之间的上下间隔为50px,而不是我们直觉的50+30=80px

下面给出边距折叠的定义

块的上外边距 (margin-top)下外边距 (margin-bottom)有时合并 (折叠) 为单个边距,其大小为单个边距的最大值 (或如果它们相等,则仅为其中一个),这种行为称为边距折叠

margin折叠的情况有如下几种:

同一层相邻元素之间

相邻的两个元素之间的外边距重叠,除非后一个元素加上clear-fix 清除浮动

1
2
3
4
5
6
7
8
9
10
11
<style>
p:nth-child(1){
margin-bottom: 13px;
}
p:nth-child(2){
margin-top: 87px;
}
</style>

<p>下边界范围会...</p>
<p>...会跟这个元素的上边界范围重叠。</p>
没有内容将父元素和后代元素分开

发生于父元素与其后代元素之间

  • 如果没有边框border,内边距padding,行内内容,也没有创建块级格式上下文清除浮动来分开一个块级元素的上边界margin-top 与其内一个或多个后代块级元素的上边界margin-top
  • 或没有边框,内边距,行内内容,高度height,最小高度min-height或 最大高度max-height 来分开一个块级元素的下边界margin-bottom与其内的一个或多个后代后代块元素的下边界margin-bottom

则就会出现父块元素和其内后代块元素外边界重叠,重叠部分最终会溢出到父级块元素外面。

如下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style type="text/css">
section {
margin-top: 13px;
margin-bottom: 87px;
}

header {
margin-top: 87px;
}

footer {
margin-bottom: 13px;
}
</style>

<section>
<header>上边界重叠 87</header>
<main></main>
<footer>下边界重叠 87 不能再高了</footer>
</section>

image-20230607151026122

其中header的上边界87px高于selction的13px,于是超出了父元素section(阴影部分),并与父元素的上边界发生了重叠。使得sectiond到页面顶点的实际距离达到了87px

同时footer的下边界与父元素section的下边界也发生了堆叠,导致下边界到section底部的实际距离为0

空的块元素

当一个块元素上边界margin-top 直接贴到元素下边界margin-bottom时也会发生边界折叠。

这种情况会发生在一个空的块元素完全没有设定边框border、内边距padding、高度height、最小高度min-height、最大高度max-height、内容设定为 inline 或是加上clear-fix的时候。

1
2
3
4
5
6
7
8
9
10
11
12
13
<style>
p {
margin: 0;
}
div {
margin-top: 13px;
margin-bottom: 87px;
}
</style>

<p>下边界范围是 87 ...</p>
<div></div>
<p>... 上边界范围是 87</p>

注意事项:

  • 上述情况的组合会产生更复杂的外边距折叠。
  • 即使某一外边距为 0,这些规则仍然适用。因此就算父元素的外边距是 0,第一个或最后一个子元素的外边距仍然会“溢出”到父元素的外面。
  • 如果参与折叠的外边距中包含负值,折叠后的外边距的值为最大的正边距与最小的负边距(即绝对值最大的负边距)的和,;也就是说如果有 -13px 8px 100px 叠在一起,边界范围的技术就是 100px -13px 的 87px。
  • 如果所有参与折叠的外边距都为负,折叠后的外边距的值为最小的负边距的值。这一规则适用于相邻元素和嵌套元素。

border

在标准盒模型中,边框大小将会被添加到盒子的高宽计算中

在替代盒模型中,边框会使得盒子的内容区域变小

边框属性可以设置:

  • 宽高
  • 颜色
  • 样式

padding

内边距无法设置为负数,应用于元素的任何背景都将显示在内边距后面

盒子模型与内联盒子

以上属性还可以应用在内联盒子,但:

  • 宽度喝高度会被忽略
  • 边框和内边距会生效,但是不会改变其他内容与内联盒子的关系
  • 外边距将在水平距离生效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<style>
span {
margin: 10px;
padding: 20px;
width: 80px;
height: 50px;
background-color: lightblue;
border: 2px solid blue;
}
</style>

<p>
I am a paragraph and this is a <span>span</span> inside that paragraph. A span is an inline element and so does not respect width and height.
</p>

inline-block

display属性有一个特殊的值inline-block提供了一个处于块与内联之间的状态

一个inline-block元素具有以下特性:

  • widthheight可以生效
  • padding,margin,以及border会推开其他元素

但并不会独占一行。

依然是上面的例子,可以看出inline-block的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
span {
margin: 10px;
padding: 20px;
width: 80px;
height: 50px;
background-color: lightblue;
border: 2px solid blue;
display: inline-block;
}
</style>

<p>
I am a paragraph and this is a <span>span</span> inside that paragraph. A span is an inline element and so does not respect width and height.
</p>

这种元素通常被用在导航栏中,为了让使用flexbox显示的一行a标签能够根据鼠标的停留更改背景颜色,我们需要让他有比内部文字更大的大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<style>
.links-list a {
background-color: rgb(179,57,81);
color: #fff;
text-decoration: none;
padding: 1em 2em;
display: inline-block;
}

.links-list a:hover {
background-color: rgb(66, 28, 40);
color: #fff;
}
</style>
<nav>
<ul class="links-list">
<li><a href="">Link one</a></li>
<li><a href="">Link two</a></li>
<li><a href="">Link three</a></li>
</ul>
</nav>

总结

元素模式 元素排列 设置样式 默认宽度 包含
块级元素 一行只能放一个块级元素 可以设置宽度和高度 容器的100% 可以包含任意元素,p无法包含div
行内元素 一行可以放多个行内元素 不可直接设置宽高 本身内容的宽度 可包含文本,或其他行内元素
行内块元素 一行可以放多个行内元素 可以设置宽度和高度 本身内容的宽度

背景

颜色

background-color

图像

background-image

  • 当使用比盒子大的图片作为背景时,默认会从图片的左上角开始渲染,且仅渲染盒子范围的图片范围。

  • 当使用比盒子小的图片作为背景时,默认会让图片复制铺满整个盒子。

可以通过background-repeat来控制图像的平铺行为

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

还可以通过background-size来设置背景图片的大小,值可以是长度或百分比。

此外还可以使用两个关键字值:

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

背景定位

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

该属性可以接受长度和百分比作为值

同时也接受关键字:

  • top
  • right
  • center

还支持使用四值语法来指示到盒子的某些边的距离

1
2
3
4
5
.box {
background-image: url(star.png);
background-repeat: no-repeat;
background-position: top 20px right 10px;
}

长度单位是相对于其前面的值的偏移量。

备注: background-positionbackground-position-xbackground-position-y的简写,它们允许用户分别设置不同的坐标轴的值。

渐变背景

使用渐变的一个有趣的方法是使用网络上许多 CSS 渐变生成器中的一个,比如这个

可以像图片一样进行设置,但需要使用linear-gradient()函数来实现,例如:

1
2
3
4
5
6
7
8
.a {
background-image: linear-gradient(105deg, rgba(0,249,255,1) 39%, rgba(51,56,57,1) 96%);
}

.b {
background-image: radial-gradient(circle, rgba(0,249,255,1) 39%, rgba(51,56,57,1) 96%);
background-size: 100px 50px;
}

多背景图片

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

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

其他 background-* 属性也可以像 background-image 一样使用逗号分隔的方式设置:

1
2
3
4
5
background-image: url(image1.png), url(image2.png),url(image3.png),url(image4.png);

background-repeat: no-repeat, repeat-x, repeat;

background-position: 10px 20px, top right;

不同属性的每个值,将与其他属性中相同位置的值匹配。

但当数量无法匹配时,较小数量的值会循环匹配

即如果有四张图片,但是位置只有两个值的话,前两个图片会引用这两个位置值的属性,然后image3会应用position1,image3会引用position2,以此循环

背景附加

background-attachment属性控制滑动时背景的呈现方式,取值有:

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

background简写属性

使用单个background进行控制时需要注意以下规则:

  • background-color 只能在最后一个逗号之后指定。
  • background-size 值只能立即包含在 background-position 之后,用“/”字符分隔,例如:center/80%
1
2
3
4
5
6
.box {
background:
linear-gradient(105deg, rgba(255,255,255,.2) 39%, rgba(51,56,57,1) 96%) center center / 400px 200px no-repeat,
url(big-star.png) center no-repeat,
rebeccapurple;
}

边框

我们可以利用border来配合构建一些更有意思的边框:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<style>
.box {
background-color: #567895;
border: 5px solid #0b385f;
border-bottom-style: dashed;
border-radius: 1em;
border-top-right-radius: 10% 30%;
color: #fff;
}

h2 {
border-top: 2px dotted rebeccapurple;
border-bottom: 1em double rgb(24, 163, 78);
}
</style>
<html>
<body>
<div class="box">
<h2>Borders</h2>
<p>Try changing the borders.</p>
</div>
</body>
</html>

文本

文本方向

可以使用writing-mode: vertical-rl对文本的显示进行设置

该属性有三个取值:

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

书写模式与块、内联布局

块级显示和内联显示与文本的书写模式密切相关

例如,如果使用书写模式的显示是横向的,如英文,那么块在页面上的显示就是从上到下的

1
2
3
4
5
6
7
.horizontal {
writing-mode: horizontal-tb;
}

.vertical {
writing-mode: vertical-rl;
}

当我们修改书写模式时,也在改变块和内联文本的方向。

例如上述代码中:

  • horizontal-tb块的方向是从上到下的横向。
  • vertical-rl块的方向是从右到左的纵向。

即:

块维度指的是块在页面书写模式下的显示方向

内联维度指的是文本方向

逻辑属性和逻辑值

对于上述的两个盒子,如果我们给这两个盒子设定宽度。

1
2
3
4
5
6
7
8
9
10
11
.box {
width: 150px;
}

.horizontal {
writing-mode: horizontal-tb;
}

.vertical {
writing-mode: vertical-rl;
}

当盒子处于纵向书写模式下时,宽度也发生了变化,从而导致文本超出了盒子的范围。

因此CSS使用了一套尺寸映射的属性:

  • width被称作内联尺寸inline-size
  • height被称作内联尺寸block-size

上述代码使用inline-size代替width后box将会随内容宽度变化

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

除了widthheight外,margin,padding,border等等也都有相应的映射,例如:

  • margin-top映射到margin-block-start,总是指向块级维度开始处的边距
  • padding-left映射到padding-inline-start,应用到内联开始方向上的内边距
  • border-bottom映射到border-block-end,引用到块级维度结尾处的边框

逻辑值

除了上述这些物理属性逻辑属性的对应外

类似:

  • top——block-start
  • right——inline-end
  • bottom——block-end
  • left——inline-start

如何使用

逻辑属性是在物理属性之后出现的,因而最近才开始在浏览器中应用。你可以通过查看 MDN 的属性页面来了解浏览器对逻辑属性的支持情况。如果你并没有应用多种书写模式,那么现在你可能更倾向于使用物理属性,因为这些在你使用弹性布局和网格布局时非常有用。

溢出处理

由于CSS的万物皆盒的设计理念,遇到盒子无法装下其中的内容时,溢出就会发生,CSS对这些现象也有自己的处理

CSS尽力减少“数据损失”

即默认情况下,CSS对于溢出的内容采用直接显示的策略:

1
2
3
4
5
6
7
8
9
10
11
<style>
.box {
border: 1px solid #333333;
width: 200px;
height: 100px;
}
</style>

<div class="box">This box has a height and a width. This means that if there is too much content to be displayed within the assigned height, there will be an overflow situation. If overflow is set to hidden then any overflow will not be visible.</div>

<p>This content is outside of the box.</p>

OverFlow属性

用于控制溢出内容的显示方式,默认取值为visible即即使发生溢出了一样会将内容显示出来。

可用取值如下:

  • visible直接显示
  • hidden隐藏溢出内容
  • scroll允许滑动以保证完全显示(无论何时都会显示滚动条)
    • 可以使用overflow-x,overflow-y两个属性控制滑动的方向
  • auto当内容发生溢出时才显示滚动条

溢出建立了块级排版上下文

CSS 中有所谓块级排版上下文(Block Formatting Context,BFC)的概念

此处不过多介绍,在使用诸如scroll或者auto的时候,就建立了一个块级排版上下文。

结果就是,改变了overflow的值的话,对应的盒子就变成了更加小巧的状态。在容器之外的东西没法混进容器内,也没有东西可以突出盒子,进入周围的版面。激活了滚动动作,你的盒子里面所有的内容会被收纳,而且不会遮到页面上其他的物件。

CSS值与单位

数字长度、百分比

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

最常见的数字类型是 <length>例如 10px(像素)或 30em。CSS 中有两种类型的长度——相对长度和绝对长度。

绝对长度单位

绝对长度与任何东西都没有关系,通常认为总是相同的大小

单位 名称 等价换算
cm 厘米 1cm = 37.8px = 25.2/64in
mm 毫米 1mm = 1/10th of 1cm
Q 四分之一毫米 1Q = 1/40th of 1cm
in 英寸 1in = 2.54cm = 96px
pc 派卡 1pc = 1/6th of 1in
pt 1pt = 1/72th of 1in
px 像素 1px = 1/96th of 1in
相对长度单位
单位 相对于
em font-size 中使用是相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如 width
ex 字符“x”的高度。
ch 数字“0”的宽度。
rem 根元素的字体大小。
lh 元素的行高。
rlh 根元素的行高。当用于根元素的 font-sizeline-height 属性时,它指的是这些属性的初始值。
vw 视口宽度的 1%。
vh 视口高度的 1%。
vmin 视口较小尺寸的 1%。
vmax 视口大尺寸的 1%。
vb 在根元素的块向上,初始包含块的尺寸的 1%。
vi 在根元素的行向上,初始包含块的尺寸的 1%。
svwsvh 分别为视口较小尺寸的宽度和高度的 1%。
lvwlvh 分别为视口大尺寸的宽度和高度的 1%。
dvwdvh 分别为动态视口的宽度和高度的 1%。

其中emrem的差别在于前者是依据父元素的字体大小,而后者是依据根节点的字体大小

因此,如果我们定义一组嵌套li元素的字体为1.3em时,字体会逐渐变大:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<style>
html {
font-size: 16px;
}
.ems li {
font-size: 1.3em;
}
</style>

<ul class="ems">
<li>One</li>
<li>Two</li>
<li>Three
<ul>
<li>Three A</li>
<li>Three B
<ul>
<li>Three B 2</li>
</ul>
</li>
</ul>
</li>
</ul>

当我们使用百分比作为值的时候

如果将元素的字体大小设置为百分比,那么它将是元素父元素字体大小的百分比。如果使用百分比作为宽度值,那么它将是父值宽度的百分比。

颜色

颜色允许接受许多值,例如:

  • 颜色关键字
  • 十六进制RGB值
  • RGB和RGBA值
  • HSL和HSLA值

备注: 在颜色上设置 alpha 通道与使用 opacity 属性有一个关键区别: 当使用opacity时,能让元素和它里面的所有东西都不透明,而使用 RGB 与 alpha 参数的颜色只让指定的颜色不透明。

HSL值的方式与RGB略有不同,它使用以下三个通道来定义颜色:

  • 色调:0-360,表示色轮中不同角度的值color wheel (en-US)
  • 饱和度:百分比,0 为无颜色(它将显示为灰色阴影),100% 为全色饱和度
  • 亮度:百分比,其中 0 表示没有光(它将完全显示为黑色),100% 表示完全亮(它将完全显示为白色)

HSLA中的A仍然表示不透明度,与RGBA中的相同

图片

可以通过url()指向实际文件,也可以接受一个渐变函数返回的值

位置

可以使用关键字(如 topleftbottomright 以及 center)将元素与 2D 框的特定边界对齐,以及表示框的顶部和左侧边缘偏移量的长度。

字符串和标识符

例如使用:after,:before这些生成内容时,即可以使用CSS字符串来定义生成的内容

字符串使用“”来与关键字进行区分

CSS中调整大小

这里特别指出使用百分比作为margin,padding的值

1
2
3
4
5
6
7
8
9
10
11
<style>
.box {
border: 5px solid darkblue;
width: 300px;
margin: 10%;
padding: 10%;
}
</style>
<div class="box">
I have margin and padding set to 10% on all sides.
</div>

给了里面的盒子 10% 的 margin 以及 10% 的 padding。盒子底部和顶部的内外边距,和左右外边距有同样的大小。

或许,你期望元素的上下外边距是其高度的百分比,元素的左右外边距是其宽度的百分比。但情况并非如此!

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

min-,max-尺寸

除了运用这两个属性避免盒子过大或者过小无法显示左右内容

max-width 的常见用法为,在没有足够空间以原有宽度展示图像时,让图像缩小,同时确保它们不会比这一宽度大。

即让图像根据盒子大小进行缩放,但不会超过图片原有大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style>
.box {
width: 200px;
}
.minibox {
width: 50px;
}
.width {
width: 100%;
}
.max {
max-width: 100%;
}
</style>
<div class="wrapper">
<div class="box"><img src="star.png" alt="star" class="width"></div>
<div class="box"><img src="star.png" alt="star" class="max"></div>
<div class="minibox"><img src="star.png" alt="star" class="max"></div>
</div>

这个技术是用来让图片可响应

视口单位

单位vh,vw根据视口来定义需要显示的百分比,视口大小的变化也会让它们的大小变化

视口,被认为是浏览器显示网页窗口时的大小

组织CSS

如何组织自己的CSS,让它更易于维护也是一个很重要的事情,通常具有以下几个注意事项:

  1. 将CSS格式化为易读的形式
  2. 为CSS加注释
  3. 在CSS中加入逻辑段落
  4. 避免太特定的选择器
  5. 将大样式表分成几个小样式表

此外还有一些辅助便携的工具,例如面对对象CSS即OOCSS

核心思想是尽量将共同的属性设置抽离为一个新的类。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.comment {
display: grid;
grid-template-columns: 1fr 3fr;
}

.comment img {
border: 1px solid grey;
}

.comment .content {
font-size: .8rem;
}

.list-item {
display: grid;
grid-template-columns: 1fr 3fr;
border-bottom: 1px solid grey;
}

.list-item .content {
font-size: .8rem;
}

其中.comment.list-item基本相同除了.list-item具有一个底边,那么我们可以将相同的属性抽离为一个新的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.media {
display: grid;
grid-template-columns: 1fr 3fr;
}

.media .content {
font-size: .8rem;
}

.comment img {
border: 1px solid grey;
}

.list-item {
border-bottom: 1px solid grey;
}

BEM命名规则

BEM即指Block,Element,Modifier;块、元素、修饰符

B

功能独立的页面元素(或简单或复杂)被视作一个块,它的 CSS 类名具有唯一性,块的特点:

  • 块的命名用来描述这个块的用途
  • 块不应影响它自身所处的环境,意味着不应为块设置外置的几何(margin)或者位置属性
  • 不要使用 CSS 标签选择器 和 ID 选择器

块的使用规则:

  • 块之间可以相互嵌套
  • 可以使用任意多的嵌套层级

E

元素则是块的组成部分,无法脱离块单独使用

元素的特点:

  • 元素的命名用来描述这个元素的用途
  • 元素的整个命名结构是 block-name__element-name

元素使用规则:

  • 元素之间可以相互嵌套
  • 可以使用任意多的嵌套层级

  • 一个元素应始终是其块的组成部分,而不是其他元素的。这意味着元素命名不应被定义成类似层级如 block__elm1__elm2

M

修饰符用来定义元素和块外观、状态或者行为

修饰符的特点如下:

  • 修饰符的命名用来描述:
    • 外观:size_stheme_islands
    • 状态:disabledfocused
    • 行为:directions-left-top
  • 用单下划线 _ 来分割修饰符与块或元素的命名
  • 当修饰符的存在与否起主要影响时使用 Boolean 类型
  • 命名遵循如下形式:
    • blockName--modifierName
    • blockName__elementName--modifierName

__表示下级元素

--表示修饰状态

具体例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.overview {} /* 块 */
.overview__row {} /* 元素 */
.overview__row--right {} /* 修饰符 */

/* 嵌套写法 */
/* 其中&表示嵌套层的上一级 */
.overview {
&__row{
&__right{
}
}
&__row--right {
}
}

详细请参考BEM — Naming (getbem.com)

其他体系

此外还有一些体系例如:

CSS的构建体系

而偶尔为了更程序化地编写CSS,较为流行的工具有Sass

可以很方便的提供一些预处理和后处理

此外还有一些可以对CSS进行后处理的工具,例如cssnano,可以将CSS文件中的额外的注释和空格去掉来优化CSS

Emmet语法

用于Html和css的代码快速生成:

html:

语法 效果
div 生成<div></div>
div*3 生成3对标签
ul > li 生成2对父子关系标签
div+p 生成2对兄弟关系标签
div.demodiv#two 生成带有类名或id名的标签
div.demo$*5 生成5对类名为demo1、demo2、…、demo5的序号自动排序标签
div{我是内容} 生成有内容的div

css:

使用属性首字母缩写+内容即可生成css代码,例如:

ti2em即可生成text-indent:2em

CSS书写顺序

建议遵循以下顺序书写:

  1. 布局定位属性display/position/float/clear/visibility/overflow(建议display第一个写,关系到盒子模式
  2. 自身属性width/height/margin/padding/border/background
  3. 文字书写color/font/text-decoration/text-align/vertical-align/white-space/break-word
  4. 其他属性(CSS3)content/cursor/border-radius/box-shadow/text-shadow/background:linear-gradient...

页面布局准则

  1. 通过测量确定页面的版心(可视区域,内容区域宽度)
  2. 页面布局第一准则:分析行模块以及每个行模块中的列模块。即多个块级元素纵向排列使用标准流,多个跨级元素横向排列使用浮动流
  3. 页面布局第二准则:一行中的列模块经常浮动布局,先确定每个列的大小,之后确定列的位置
  4. 制作HTML结构。先结构后样式

样式化文本

基本文本和字体样式

用于样式文本的CSS属性通常可以分为两类:

  • 字体样式:用于字体的属性,会直接应用到文本中,比如:
    • 字体
    • 字体大小
    • 字体粗细
    • 是否倾斜
  • 文本布局风格:作用于文本的间距以及其他布局功能的属性,比如:
    • 行于字之间的空间
    • 内容框中文本如何对齐

注意事项

无法将文本中一部分选中或添加样式,如果想要这么做,需要使用等标签将其包裹,或者使用伪元,比如::first-letter::first-line或者::selection(当前光标双击选中的内容)

字体

颜色可以直接使用color属性设置,color属性设置的内容是元素的前景内容的颜色(前景通常是文本,但也包含一些其他东西),或者使用text-decoration属性放置在文本下方或上方的线 (underline overline)。

1
2
3
4
p {
color: red;
text-decoration: underline overline #FF3028;
}

字体种类

css允许使用font-family属性设置字体,但浏览器只会将当前机器上可用的字体引用到元素上,如果指定字体不可用,则会使用默认字体替代。

1
2
3
p {
font-family: arial;
}

所以诞生了一些可以毫无顾忌的使用的,可以应用到所有系统的字体,被称为网页安全字体:

字体名称 泛型 注意
Arial sans-serif 通常认为最佳做法还是添加 Helvetica 作为 Arial 的首选替代品,尽管它们的字体面几乎相同,但 Helvetica 被认为具有更好的形状,即使 Arial 更广泛地可用。
Courier New monospace 某些操作系统有一个 Courier New 字体的替代(可能较旧的)版本叫 Courier。使用 Courier New 作为 Courier 的首选替代方案,被认为是最佳做法。
Georgia serif
Times New Roman serif 某些操作系统有一个 Times New Roman 字体的替代(可能较旧的)版本叫 Times。使用 Times 作为 Times New Roman 的首选替代方案,被认为是最佳做法。
Trebuchet MS sans-serif 您应该小心使用这种字体——它在移动操作系统上并不广泛。
Verdana sans-serif

备注: 在各种资源中,cssfontstack.com 网站维护了一个可用在 Windows 和 Mac 操作系统上使用的网页安全字体的列表,这可以帮助决策网站的安全性。

默认字体

CSS 定义了 5 个常用的字体名称:

  • serif

  • sans-serif

  • monospace

  • cursive

  • fantasy

这些都是非常通用的,当使用这些通用名称时,使用的字体完全取决于每个浏览器,而且它们所运行的每个操作系统也会有所不同。

浏览器会尽力提供一个看上去合适的字体。 serif, sans-serifmonospace 是比较好预测的,默认的情况应该比较合理,另一方面,cursivefantasy 是不太好预测的,建议使用的时候注意。

名称 定义 示例
serif 衬线字体,即有衬线的字体(衬线是指字体笔画尾端的小装饰,存在于某些印刷体字体中)。
sans-serif 无衬线字体。
monospace 等宽字体,指包含的全部字符的宽度相同的字体,通常在编辑代码时使用。
cursive 手写字体,对于英文字符而言通常具有顺滑的连接笔画以模拟手写效果。
fantasy 装饰字体。

字体栈

由于无法保证你想在你的网页上使用的字体的可用性,可以提供一个字体栈 (font stack)

1
2
3
p {
font-family: "Trebuchet MS", Verdana, sans-serif;
}

字体大小

字体可以取大多数上文提到的单位值,甚至百分比值,然而调整大小最常用的单位是:

  • px:绝对单位,在任何情况下计算出来的像素值都一样
  • em:相对单位,1em等于当前元素的父元素上设置的字体大小,使用em会使得网站维护更简单
  • rem:相对单位,1rem等于HTML中根元素的字体大小,不支持IE8以下不支持

文本样式

CSS提供了4种常用属性来定义文本样子:

  • font-style: 用来打开和关闭文本 italic (斜体):

    • normal: 将文本设置为普通字体 (将存在的斜体关闭)
    • italic: 如果当前字体的斜体版本可用,那么文本设置为斜体版本;如果不可用,那么会利用 oblique 状态来模拟 italics。
    • oblique: 将文本设置为斜体字体的模拟版本,也就是将普通文本倾斜的样式应用到文本中。
  • font-weight: 设置文字的粗体大小。这里有很多值可选 (比如-light,-normal,-bold,-extrabold,-black, 等等), 不过事实上除了normalbold以外,很少会用到,可取值如下:

    • normal, bold: 普通或者加粗的字体粗细
    • lighter, bolder: 将当前元素的粗体设置为比其父元素粗体更细或更粗一点。100900: 数值粗体值,如果需要,可提供比上述关键字更精细的粒度控制。
  • text-transform: 允许你设置要转换的字体。值包括:

    • none: 防止任何转型。
    • uppercase: 将所有文本转为大写。
    • lowercase: 将所有文本转为小写。
    • capitalize: 转换所有单词让其首字母大写。
    • full-width: 将所有字形转换成全角,即固定宽度的正方形,类似于等宽字体,允许拉丁字符和亚洲语言字形(如中文,日文,韩文)对齐。
  • text-decoration: 设置/取消字体上的文本装饰 (你将主要使用此方法在设置链接时取消设置链接上的默认下划线。) 可用值为:

    • none: 取消已经存在的任何文本装饰。
    • underline: 文本下划线。
    • overline: 文本上划线
    • line-through: 穿过文本的线。

    注意到text-decoration可以一次接受多个值,如果想要同时添加多个装饰值,比如

    1
    text-decoration: underline overline

    同时注意text-decoration是一个缩写形式,它由text-decoration-line,text-decoration-styletext-decoration-color构成。可以使用这些属性值的组合来创建有趣的效果,比如

    1
    text-decoration: line-through red wavy

文字阴影

可以使用text-shadow属性为文字添加阴影,最多需要4个值:

1
text-shadow: 4px 4px 5px red;

每个属性的代表的含义如下:

  1. 阴影与原始文本的水平偏移,可以使用大多数的 CSS 单位 length and size units, 但是 px 是比较合适的。这个值必须指定。
  2. 阴影与原始文本的垂直偏移;效果基本上就像水平偏移,除了它向上/向下移动阴影,而不是左/右。这个值必须指定。
  3. 模糊半径 - 更高的值意味着阴影分散得更广泛。如果不包含此值,则默认为 0,这意味着没有模糊。可以使用大多数的 CSS 单位 length and size units.
  4. 阴影的基础颜色,可以使用大多数的 CSS 颜色单位 CSS color unit. 如果没有指定,默认为 black

备注: 正偏移值可以向右移动阴影,但也可以使用负偏移值来左右移动阴影,例如 -1px -1px.

多种阴影

多影音可以使用逗号分隔:

1
2
3
4
text-shadow: -1px -1px 1px #aaa,
0px 4px 1px rgba(0,0,0,0.5),
4px 4px 5px rgba(0,0,0,0.7),
0px 0px 7px rgba(0,0,0,0.4);

文字布局

使用text-align属性可以控制文本如何和它所在的盒子内对其:

  • left:左对齐
  • right:右对齐
  • center:居中对齐
  • justify:使文本展开,改变单词之间的间距,使所有文本行的宽度相同。如果需要使用这个值,则通常需要考虑

行高

使用line-height可以设置行高,可以接受大多数单位 length and size units

不过也可以设置一个无单位值作为乘数,使用无单位的值乘以fony-size来获得line-height。推荐的行高大约是1.5-2(双倍间距

行高种的数值表示 = 上间距 + 文本高度 + 下间距

  • 当行高设置为和字体等高时,字体上下将不会存在空隙
  • 行高 > 字体高度时,行高 - 字体高度 / 2即为上间距和下间距的值

字母和单词间距

letter-spacingword-spacing 属性允许设置文本中的字母与字母之间的间距、或是单词与单词之间的间距。

1
2
3
4
p::first-line {
letter-spacing: 2px;
word-spacing: 4px;
}

其他一些属性值

Font样式:

文本布局样式

  • text-indent: 指定文本内容的第一行前面应该留出多少的水平空间。
  • text-overflow: 定义如何向用户表示存在被隐藏的溢出内容。
  • white-space: 定义如何处理元素内部的空白和换行。
  • word-break: 指定是否能在单词内部换行。
  • direction: 定义文本的方向 (这取决于语言,并且通常最好让 HTML 来处理这部分,因为它是和文本内容相关联的。)
  • hyphens: 为支持的语言开启或关闭连字符。
  • line-break: 对东亚语言采用更强或更弱的换行规则。
  • text-align-last: 定义一个块或行的最后一行,恰好位于一个强制换行前时,如何对齐。
  • text-orientation: 定义行内文本的方向。
  • word-wrap: 指定浏览器是否可以在单词内换行以避免超出范围。
  • writing-mode: 定义文本行布局为水平还是垂直,以及后继文本流的方向。

Font简写

许多字体的属性可以通过font的方式简写,但需要按照以下顺序来写:

font-style, font-variant, font-weight, font-stretch, font-size, line-height, and font-family.

其中只有font-sizefont-family是必要的

1
font: italic normal bold normal 3em/1.5 Helvetica, Arial, sans-serif;

Web字体

Web字体是一种CSS特性,可以允许指定在访问时随网站一起下载的字体文件,使用一个@font-face块指定要下载的字体文件:

1
2
3
4
@font-face {
font-family: "myFont";
src: url("myFont.ttf");
}

然后可以使用@font-face种指定的字体种类名称将定制字体应用到页面上:

1
2
3
html {
font-family: "myFont", "Bitstream Vera Serif", serif;
}

总结

字体属性

属性 表示 注意
font-size 字号 单位通常为px
font-family 字体 按团队字体来
font-weight 字体粗细 加粗是700/bold不加粗是400/normal,无单位
font-style 字体样式 倾斜式italic不倾斜式normal
font 字体连写 1. 有顺序。2. 字体字号不能同时出现

文本属性

属性 表示 注意
color 文本颜色 常用十六进制
text-align 文本对齐 可设置文字水平对齐方式
text-indent 文本缩进 首行缩进,通常缩进2字符为text-indent:2em
text-decoration 文本修饰 添加下划线underline取消下划线none
line-height 行高 控制行间距

列表

列表间距

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
/* General styles */

html {
font-family: Helvetica, Arial, sans-serif;
font-size: 10px;
}

h2 {
font-size: 2rem;
}

ul,ol,dl,p {
font-size: 1.5rem;
}

li, p {
line-height: 1.5;
}

/* Description list styles */


dd, dt {
line-height: 1.5;
}

dt {
font-weight: bold;
}

dd {
margin-bottom: 1.5rem;
}
  • 首先设置网页根节点基准字体大小,以及字体样式
  • 规则集2和3为标题设置相对字体大小,这样每个段落和列表都将拥有相同的字体大小和上下间距,有助于保持垂直间距一致
  • 4号在段落在列表项目上设置相同的line-height,也有助于保持垂直间距一致
  • 5-7用来描述列表,描述列表的术语和其描述上设置与段落和列表项相同的行高,以及margin-bottom为1.5rem

列表特定样式

下面三个属性可以在<ul><ol>元素上设置:

  • list-style-type:设置用于列表的项目符号类型例如:
    • 方形
    • 圆形
    • 数字
    • 字母
    • 罗马数字
  • list-style-position:设置在每个项目开始之前,项目符号是出现在列表内还是列表外
  • list-style-image:设置自定义图片作为项目开始符号

符号样式

例如大写罗马字:

1
2
3
ol {
list-style-type: upper-roman;
}

项目符号位置

可以设为insiade让符号在列表以内

1
2
3
4
ol {
list-style-type: upper-roman;
list-style-position: inside;
}

image-20230618200613311

自定义图片

1
2
3
ul {
list-style-image: url(star.svg);
}

然而,这个属性在控制项目符号的位置,大小等方面是有限的。最好使用background 系列属性,可以在 Styling boxes 模块中了解更多信息。

1
2
3
4
5
6
7
8
9
10
11
12
ul {
padding-left: 2rem;
list-style-type: none;
}

ul li {
padding-left: 2rem;
background-image: url(star.svg);
background-position: 0 0;
background-size: 1.6rem 1.6rem;
background-repeat: no-repeat;
}
  • ul种的paddintg-left从默认的40px修改为20px,然后在列表上设置相同的数值。目的是让背景图像不与列表文本重叠
  • list-style-type设置为none,以便默认情况下不会显示项目符号
  • 为每无须列表项插入项目符号,对应属性如下:
    • background-image:充当项目符号的图片文件路径
    • background-position:图像位置0 0 表示左上角
    • background-size:图像大小
    • background-repeat:平铺方式,默认情况下是复制填充,因此需要禁用平铺

list-style

符号样式,符号图片以及符号位置可以用一个list-sytle来缩写,方式如下:

1
2
3
ul {
list-style: square url(example.png) inside;
}

属性值可以任意顺序排列,你可以设置一个,两个或者三个值(该属性的默认值为 disc, none, outside),如果指定了 type 和 image,如果由于某种原因导致图像无法加载,则 type 将用作回退。

管理列表计数

可以通过star属性来控制开始数字:

1
2
3
4
5
6
<ol start="4">
<li>Toast pitta, leave to cool, then slice down the edge.</li>
<li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li>
<li>Wash and chop the salad.</li>
<li>Fill pitta with salad, humous, and fried halloumi.</li>
</ol>

还可以通过reversed属性将序号倒置

1
2
3
4
5
6
<ol start="4" reversed>
<li>Toast pitta, leave to cool, then slice down the edge.</li>
<li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li>
<li>Wash and chop the salad.</li>
<li>Fill pitta with salad, humous, and fried halloumi.</li>
</ol>

并且还可以通过value属性设置自定义序号值

1
2
3
4
5
6
<ol>
<li value="2">Toast pitta, leave to cool, then slice down the edge.</li>
<li value="4">Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li>
<li value="6">Wash and chop the salad.</li>
<li value="8">Fill pitta with salad, humous, and fried halloumi.</li>
</ol>

CSS精灵图

为了有效地减小服务器接收和发送请求的次数,提高页面的加载速度,出现了CSS精灵技术CSS sprites

即将服务器中很多小的图片整合为一张大的图片

精灵图的使用

  1. 精灵图技术主要针对背景图片使用,即把多个小背景图片整合到一张大的图片中
  2. 前端实现精灵图的切割是使用background-position属性
  3. 移动的距离就是目标图片的x和y坐标

字体图标

可以方便的修改颜色、尺寸,且放大不失真

  • 轻量级
  • 灵活性
  • 兼容性——几乎支持所有浏览器

vertical-align属性

该属性用实现于行内元素或者行内块元素的垂直居中效果

描述
baseline 默认,元素放在父元素的基线上(即字母中的a,b等没有小尾巴的字符的底部
top 元素顶端与行中最高元素顶端对齐
middle 把元素放置在父元素中部
bottom 把元素的顶端与行中最低的元素的顶端对齐(即字母中的f,g等有小尾巴的字符的底部

文本溢出省略号

单行

1
2
3
4
5
6
7
8
one-line-text {
/* 1. 先将文本强制单行显示 */
white-space: nowrap; /* 默认为normal,自动换行 */
/* 2. 溢文本出部分隐藏 */
overflow: hidden;
/* 1. 超出部分使用省略号代替 */
text-overflow: ellipsis;
}

多行

多行文本显示有较大兼容性问题,目前只适用于WebKit浏览器或移动端

1
2
3
4
5
6
7
8
9
10
mul-line-text {
overflow: hidden;
text-overflow: ellipsis;
/* 弹性伸缩盒子模型显示 */
display: -webkit-box;
/* 限制在一个块元素显示的文本的行数 */
-webkit-line-clamp: 2;
/* 设置或检索伸缩盒对象的子元素的排列方式 */
-webkit-box-orient: vertical
}

CSS初始化

为了消除浏览器自带的样式,网页的最开始应该进行CSS初始化:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* 清除盒子内外边距 */
* {
margin: 0;
padding: 0;
}

/* 斜体文字不倾斜 */
em,
i {
font-style: normal;
}

/* 去除列表前的小圆点 */
li {
list-style: none;
}

/* 处理图片 */
img {
/* 照顾低版本浏览器中,如果图片外面包含了链接将会产生边框的问题 */
border: 0;
/* 取消图片由于基线对齐而底侧有空白间隙的问题 */
vertical-align: middle
}

/* 让鼠标经过button时鼠标变成小手 */
button {
cursor: pointer;
}

/* 链接颜色 */
a {
color: #666;
text-decoration: none
}

a:hover {
color: red;
}

/* 指定按钮以及输入子体 */
button,
input {
font-family: Microsoft YaHei;
}

/* 指定body字体,颜色,行高 */
body {
/* CSS3 文字抗锯齿效果 */
-webkit-font-smoothing: antialiased;
background-color: #fff;
font: 12px/1.5 Microsoft YaHei;
color: #666
}

/* 元素隐藏标准样式 */
.hiden,
.none {
display: none;
}

/* 清除浮动样式 */
.clearfix:after {
visibility: hidden;
clear: both;
display: block;
content: ".";
height: 0;
}

.clearfix {
*zoom: 1;
}

CSS布局

在不对页面进行任何布局控制时,浏览器默认的HEML布局方式为正常布局流(normal flow)

下面这些属性的设置可能会覆盖默认的布局行为:

  • display
  • 应用float
  • position属性
  • 表格布局
  • 多列布局

默认状态下:

  • 一个块级元素的内容宽度其父元素的100%
  • 块级元素高度与其内容高度一致
  • 行级元素的height width与内容一致
  • 块级元素按照基于其父元素的书写顺序的块流动方向放置

CSS传统网页布局

  • 标准流(文档流)
  • 浮动流
  • 定位流

标准流

标准流即:标签按照规定好默认方式排列

  1. 块级元素独占一行,从上到下依次排列
  2. 行内元素从左到右顺序排列,碰到父元素边缘自动换行

标准流是最基本的网页布局方式

浮动流

浮动可以让多个块级元素在一行显示,于是得到网页布局流第一准测:

网页布局流第一准则:多个块级元素纵向排列使用标准流,多个跨级元素横向排列使用浮动流

浮动流使用float创建浮动框,将其移动到一边, 直到左侧边缘或右侧边缘触及包含块或另一浮动框的边缘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
.left,
.right {
float: left;
width: 200px;
height: 200px;
background-color: red;
}
.right {
float: right;
}
</style>
<body>
<div class="left">
啊左
</div>
<div class="right">
啊右
</div>
</body>

浮动元素特性:

  1. 浮动元素会脱离标准流
    1. 脱离标准流的控制,移动到指定位置,俗称脱标
    2. 浮动的盒子不再保留原先的位置
    3. image-20230807105904240
  2. 如果多个盒子设置了浮动,则会按照属性值一行内显示并且顶端对齐排列
  3. 浮动元素具有行内块元素特性:
    1. 行内元素设置浮动后可以设置宽高
    2. 块级元素设置浮动后可以同行显示,且宽度变为默认等于内容宽度
    3. 浮动盒子直接没有margin,与行内元素同理

注意事项:

  1. 浮动流和标准流的父盒子搭配时:先用标准流的父元素排列上下位置,后内部子元素浮动排列左右位置
  2. 一个元素浮动,理论上其余兄弟元素也要浮动:浮动盒子只会影响浮动盒子之后的标准流,不会影响其前面的标准流
清除浮动

为什么要清除浮动?

由于父级盒子在很多情况下,不方便给高度,但子盒子浮动又不占有位置,最后父级盒子高度为0时,就会影响下面的标准流盒子

清除浮动的本质是什么?

  • 本质是清除浮动元素造成的影响
  • 如果父盒子本身有高度,就不需要清除浮动
  • 清除浮动后,父级就会根据浮动的子盒子自动检测高度。父级有了高度,就不会影响下面的标准流

清除浮动的语法:clear

属性值 描述
clear:left 不允许左侧有浮动元素
clear:right 不允许右侧有浮动元素
clear:both 同时清除左右两侧浮动的影响

实际应用中几乎只用clear:both

清除浮动策略:闭合浮动,即将浮动元素限制在父元素内

清除浮动的四种方法:

  1. 额外标签法(隔墙法),W3C推荐
  2. 父级添加overflow
  3. 父级添加after伪元素
  4. 父级添加双伪元素
额外标签法(不常用

在最后一个浮动盒子的后面添加一个额外的标签,然后设置其clear:both

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
37
38
39
<head>
<style>
.footer {
height: 200px;
background-color: black;
}
.box {
width: 800px;
border: 1px solid blue;
margin: 0 auto;
}
.one {
width: 300px;
height: 200px;
background-color: purple;
}
.two {
width: 200px;
height: 200px;
background-color: red;
}
.clear {
clear: both;
}
</style>
</head>
<body>
<div class="box">
<div class="one">
one
</div>
<div class="two">
two
</div>
<!-- 添加清除标签,这样box就能根据子盒子计算高度,且该标签必须是块级标签 -->
<div class="clear"></div>
</div>
<div class="footer"></div>
</body>

优点:简单,书写方便

缺点:添加许多无意义的标签,结构化较差

注意

添加的标签必须是块级标签

父亲添加overflow

为父节点添加overflow属性,并将其值设为hiddenautoscroll

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
<head>
<style>
.footer {
height: 200px;
background-color: black;
}
.box {
/* 为浮动元素的父元素添加该属性清除浮动 */
overflow: hidden;
width: 800px;
border: 1px solid blue;
margin: 0 auto;
}
.one {
width: 300px;
height: 200px;
background-color: purple;
}
.two {
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="box">
<div class="one">
one
</div>
<div class="two">
two
</div>
</div>
<div class="footer"></div>
</body>

优点:代码简洁

缺店:无法显示溢出的部分

父亲添加:after伪元

:after是额外标签法的升级版,利用伪元代替额外添加的标签

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
37
38
39
40
41
42
43
44
45
46
<head>
<style>
.clearFix:after {
/* 使用after清除浮动 */
content: "";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.clearFix {
/* IE6, 7 清除浮动兼容 */
*zoom: 1;
}
.footer {
height: 200px;
background-color: black;
}
.box {
width: 800px;
border: 1px solid blue;
margin: 0 auto;
}
.one {
width: 300px;
height: 200px;
background-color: purple;
}
.two {
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="box clearFix">
<div class="one">
one
</div>
<div class="two">
two
</div>
</div>
<div class="footer"></div>
</body>

优点:没有增加更多标签,解构更简单

缺点:需要对低版本浏览器做兼容

父亲添加双伪元素

同时给父元素添加:after:before伪元素

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
37
38
39
40
41
42
43
44
<head>
<style>
.clearFix:after,
.clearFox:before {
/* 使用after清除浮动 */
content: "";
display: table;
}
.clearFix {
/* IE6, 7 清除浮动兼容 */
*zoom: 1;
}
.footer {
height: 200px;
background-color: black;
}
.box {
width: 800px;
border: 1px solid blue;
margin: 0 auto;
}
.one {
width: 300px;
height: 200px;
background-color: purple;
}
.two {
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="box clearFix">
<div class="one">
one
</div>
<div class="two">
two
</div>
</div>
<div class="footer"></div>
</body>

优点:代码更简洁

缺点:需要兼容低版本浏览器

清除浮动总结

  1. 为什么要清除浮动
    • 父亲没高度
    • 子盒子浮动
    • 影响了之后的布局,需要清除浮动造成的影响
  2. 清除浮动的方法:
方法 优点 缺点
额外标签法 通俗易懂,书写方便 添加无意义标签,结构化较差
父亲添加overflow 书写简单 导致父元素溢出隐藏
父亲添加:after伪元 不引入额外标签,结构语义化正确 需要做兼容
父亲添加双伪元 不引入额外标签,结构语义化正确 需要做兼容

定位流

定位流可以实现:

  1. 让盒子自由地在某个盒子内部移动,并压住某个盒子
  2. 固定在屏幕的某个位置,并压住某个盒子

定位 = 定位模式 + 边偏移

定位模式用与指定一个元素在文档中的定位方式

边便宜则决定了该元素的最终位置

定位模式

通过position属性来设置

语义
static 静态定位
relative 相对定位
absolute 绝对定位
fixed 固定定位
边偏移

用于定位盒子的最终位置,有四个属性

属性 示例 描述
top top:80px 顶端偏移量,定义元素相对于其父元素上边线的距离
bottom bottom:80px 底端偏移量,定义元素相对于其父元素下边线的距离
left left:80px 左侧偏移量,定义元素相对于其父元素左线的距离
right right:80px 右侧偏移量,定义元素相对于其父元素右边线的距离
static静态定位(了解

默认定位,无定位

  • 静态定位按照标准流拜访位置,没有边偏移
  • 很少使用
realative相对定位(重要

元素移动时,相对于它原来的位置而定

相对定位的特点:

  1. 相对于自己原来的位置移动
  2. 原来在标准流的位置继续占有,后面的盒子仍然以标准流的方式对待它(不脱标,继续保留原有位置)

因此相对定位通常用来限制绝对定位

absolute绝对定位

元素移动时,相对于它祖先元素移动

绝对定位的特点:

  1. 如果祖先元素没有定位或没有祖先元素,则按照浏览器进行定位(Document文档)
  2. 如果祖先元素有定位(相对,绝对,固定定位),则以最近的有定位的祖先元素作为参考点移动
  3. 绝对定位不再占有原有的位置(脱标)
子绝父相

即子盒子如果使用绝对定位,那么父盒子使用相对定位

  1. 子盒子使用绝对定位不会占用空间,可以放在父盒子的任意位置,且不会影响其他兄弟盒子
  2. 父盒子需要加定位才能限制子盒子的显示范围
  3. 父盒子在布局时,需要占有位置,因此只能使用相对定位

即:父级需要占有位置,因此是相对定位,子盒子不需要占有位置,则是绝对定位

fixed固定定位

可以在浏览器页面滚动时仍然保持不变

固定定位的特点:

  1. 以浏览器可视窗口为参照点移动元素
    • 跟父元素没关系
    • 随着页面滚动而滚动
  2. 固定定位不占有原先位置(脱标)

此外固定定位还能根据版心进行定位:

  1. 设置固定定位的盒子left: 50%,移动到浏览器可视区(版心)的一半位置
  2. 设置固定定位的盒子margin-left: 版心宽度的一半
sticky粘性定位``

粘性定位可以被认为是relative相对定位和fixed固定定位的混合

该定位可以实现,当盒子在可是窗口以内时,以相对定位的方式固定在页面中,不随页面滚动而滚动

但当盒子即将被可视窗遮盖时,变为固定定位固定在可视窗的某个位置

固定定位的特点:

  1. 以浏览器的可视窗口为参照无来移动元素(固定定位特点
  2. 粘性定位占有原先的位置(相对定位特点
  3. 必须添加top, bottom, left, right其中的一个才能生效

通常和页面滚动搭配使用,但兼容性很差,IE不支持,通常该效果可以使用JS实现

定位叠放顺序z-index

z-index用于控制盒子的前后顺序

  • 数值可以为正数、负数、0,默认为auto,数值越大,盒子越靠上

  • 如果值相同,则按照书写顺序,后来者居上

  • 数字不能加单位``

  • 只有定位流具有该属性

定位流总结

定位模式 是否脱标 移动位置 是否常用
static 不能使用边偏移 很少
realative 相对于自身原位置偏移 常用
absolute 相对于祖先元素偏移 常用
fixed 相对于浏览器可视区偏移 常用
sticky 相对于浏览器可视区偏移 当前很少

定位流的特殊性质

  1. 行内元素添加绝对或者固定定位,可以直接设置宽高
  2. 块级元素添加绝对或者固定定位,如果不设置宽度,默认为内容大小
  3. 脱标的盒子不会触发外边距塌陷(即外边距合并
  4. 绝对定位(固定定位)会完全压住盒子
    • 需要注意的是与浮动流的区别:
    • 浮动元素只会压住下面标准流的盒子,但不会压住下面标准流盒子里的文字(图片
      • 原因是浮动最初的作用是为了实现文字环绕效果
    • 但是绝对(固定)定位会压住下面标准流所有的内容

水平居中

  1. 标准流下,可以通过margin: 0 auto实现水平居中
  2. 定位流下,绝对定位使用left: 50%; margin-left: -宽度的一半

Flex弹性盒子

通过修改display属性来控制元素是否为弹性盒子

1
2
3
section {
display:flex
}

当这只元素为flex盒子后,其子元素将变为flex项

flex模型

当元素表现为flex时,它沿着两个轴来布局:

  • 主轴,沿着flex元素放置方向延伸的轴
  • 交叉轴,垂直于flex元素放置方向的轴
  • 设置了display:flex的父元素,被称为flex容器
  • 在flex容器种的表选为弹性盒子的元素被称为flex项

换行

当子元素超出了其容器,可以通过限制宽高,后设置自动换行来解决:

在flex容器中设置

1
flex-wrap: wrap

在flex项中设置限宽:

1
flex: 200px;

来限制flex项的最小宽度为200px

flex-flow缩写

flex-flow允许将flex-directionflex-wrap缩写进去:

1
flex-flow: row wrap;

flex项的动态尺寸

对于每个flex项,可以设置flex属性来定义显示比例

1
2
3
div {
flex: 1;
}

这是一个无单位的比例值,表示每个 flex 项沿主轴的可用空间大小。

如果三个元素均设为1,那么三个元素将以1:1:1的形式呈现,如果是1:2则第一个元素占1/3,第二个元素占2/3

此外还可以同时设置比例值和单位值:

1
2
3
4
5
6
7
article {
flex: 1 200px;
}

article:nth-of-type(3) {
flex: 2 200px;
}

这表示每个flex项将首先给出200px的可用空间,剩余的可用空间则按比例分配

flex缩写和全写

flex 是一个可以指定最多三个不同值的缩写属性:

  • 第一个就是上面所讨论过的无单位比例。可以单独指定全写 flex-grow 属性的值。
  • 第二个无单位比例——flex-shrink——一般用于溢出容器的 flex 项。这指定了从每个 flex 项中取出多少溢出量,以阻止它们溢出它们的容器。
  • 第三个是上面讨论的最小值。可以单独指定全写 flex-basis 属性的值。

水平垂直对齐

如果想要flex容器中的元素垂直、水平方向吹则,可以使用下面的方式:

1
2
3
4
5
div {
display: flex;
align-items: center;
justify-content: space-around;
}

其中:

align-items控制flex项在交叉轴上的位置

  • 默认值为stretch,即所有flex项沿着交叉轴方向拉伸以填充父元素,如果交叉轴方向没有固定宽度,则所有flex项将变得与最长的flex项一样长
  • center会使得flex项保持原有高度,但会在交叉轴居中
  • flex-endflex-star使flex项在交叉轴的开始或结束处对齐所有值。

对于需要单独控制的flex项,可以使用align-self来覆盖父元素的align-items

1
2
3
button:first-child {
align-self: flex-end;
}

justify-countent可以用来控制flex项在主轴上的位置

  • 默认值为flex-start,让flex项位于主轴的开始处
  • flex-end,让flex项位于主轴的结尾处
  • center,让flex项在主轴居中
  • space-around,会使所有flex项沿着主轴均匀地分布,在任意一端都会留出一点空间。
  • space-betweenspace-around非常相似,只是它不会在两端留下空间

flex项排序

弹性盒子也有可以改变 flex 项的布局位置的功能,而不会影响到源顺序(即 dom 树里元素的顺序)。

1
2
3
button:first-child {
order: 1;
}
  • 所有 flex 项默认的 order 值是 0。
  • order 值大的 flex 项比 order 值小的在显示顺序中更靠后。
  • 相同 order 值的 flex 项按源顺序显示。所以假如你有四个元素,其 order 值分别是 2,1,1 和 0,那么它们的显示顺序就分别是第四,第二,第三,和第一。
  • 第三个元素显示在第二个后面是因为它们的 order 值一样,且第三个元素在源顺序中排在第二个后面。

也可以给 order 设置负值使它们比值为 0 的元素排得更前面。

Grid网格布局

网格是由一系列水平及垂直的线构成的一种布局模式。帮助我们设计一系列具有固定位置以及宽度的元素的页面,使我们的网站页面更加统一。

一个网格通常具有许多的列(column)行(row),以及行与行、列与列之间的间隙,这个间隙一般被称为沟槽(gutter)

创建一个网格布局:

1
2
3
.container {
display: grid;
}

在定义网格后,网页并不会马上发生变化。因为 display: grid 的声明只创建了一个只有一列的网格,所以子项还是会像正常布局流那样,自上而下、一个接一个的排布。

接着我们需要给更定义的网格加一些列:

1
2
3
4
.container {
display: grid;
grid-template-columns: 200px 200px 200px;
}

上述代码加入了三个宽度为200px的列,此处可以使用任何长度单位

fr单位

除了长度和百分比,我们也可以用 fr 这个单位来灵活地定义网格的行与列的大小。这个单位代表网格容器中可用空间的一份。

1
2
3
4
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}

fr 单位按比例划分了可用空间,类似flex布局中的flex

备注: fr单位分配的是可用空间而非所有空间,所以如果某一格包含的内容变多了,那么整个可用空间就会减少,可用空间是不包括那些已经确定被占用的空间的。

网格间隙

可以使用grid-column-gapgrid-row-gap来定义行间隙;也可以使用grid-gap来同时设定两者

1
2
3
4
5
.container {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
grid-gap: 20px;
}

间隙值可以使用百分比来设置,但不能使用fr

备注gap可以不加grid前缀使用,属于历史遗留问题,但为了代码健壮性,还是推荐加上

重复构建轨道组

当我们的列很多的时候,可以使用repeat来构建具有某些宽度的某些列:

1
2
3
4
5
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 20px;
}

第一个值表示重复次数,第二个值表示重复构建的配置,配置可以具体多个长度例如repeat(2, 2fr,1fr)这样就会创建4个列,宽度分别为2fr 1fr 2fr 1fr

显式网格和隐式网格

显式网格是用 grid-template-columnsgrid-template-rows 属性创建的

隐式网格则是当有内容被放到网格外时才会生成

显式网格与隐式网格的关系与弹性盒子的 main 和 cross 轴的关系有些类似。

隐式网格中生成的行/列大小是参数默认是 auto ,大小会根据放入的内容自动调整。也可以使用grid-auto-rowsgrid-auto-columns属性手动设定隐式网格轨道的大小

1
2
3
4
5
6
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
grid-gap: 20px;
}

上面的例子将grid-auto-rows设为了100px,隐式网格中的行(因为这个例子里没有设定grid-template-rows,因此,所有行都位于隐式网格内)现在都是 100 像素高了。

minmax函数

minmax 函数为一个行/列的尺寸设置了取值范围。比如设定为 minmax(100px, auto),那么尺寸就至少为 100 像素,并且如果内容尺寸大于 100 像素则会根据内容自动调整。

1
2
3
4
5
6
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto);
grid-gap: 20px;
}

自动使用多列填充

某些情况下,我们需要让网格自动创建很多列来填满整个容器。通过设置grid-template-columns属性,可以实现这个效果,但也可以用到 repeat 函数中的一个关键字auto-fill来替代确定的重复次数。而函数的第二个参数,使用minmax函数来设定一个行/列的最小值,以及最大值 1fr

1
2
3
4
5
6
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: minmax(100px, auto);
grid-gap: 20px;
}

基于线的元素放置

网格有许多分隔线,第一条线的起始点与文档书写模式相关。

在英文中,第一条列分隔线(即网格边缘线)在网格的最左边而第一条行分隔线在网格的最上面。

而对于阿拉伯语,第一条列分隔线在网格的最右边,因为阿拉伯文是从右往左书写的。

通过以下的属性来指定开始和结束位置

这些属性的值均为分隔线序号,也可以用以下缩写形式来同时指定开始与结束的线。

注意开始与结束的线的序号要使用/符号分开。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
header {
grid-column: 1 / 3;
grid-row: 1;
}

article {
grid-column: 2;
grid-row: 2;
}

aside {
grid-column: 1;
grid-row: 2;
}

footer {
grid-column: 1 / 3;
grid-row: 3;
}

使用grid-template-areas属性放置元素

还可以利用命名的方式,更直观的管理元素的排布:

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
.container {
display: grid;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
grid-template-columns: 1fr 3fr;
gap: 20px;
}

header {
grid-area: header;
}

article {
grid-area: content;
}

aside {
grid-area: sidebar;
}

footer {
grid-area: footer;
}

grid-template-areas属性的使用规则如下:

  • 你需要填满网格的每个格子
  • 对于某个横跨多个格子的元素,重复写上那个元素grid-area属性定义的区域名字
  • 所有名字只能出现在一个连续的区域,不能在不同的位置出现
  • 一个连续的区域必须是一个矩形
  • 使用.符号,让一个格子留空

CSS3新特性

新增的选择器

  1. 属性选择器
    1. input[attrname]
    2. input[attrname="val"]
    3. input[attrname^="val"]开头包含
    4. input[attrname$="val"]结尾包含
    5. input[attrname*="val"]包含
  2. 解构伪类选择器
    1. E:first-child
    2. E:last-child
    3. E:nth-child(n)n可以是数字、关键字、公式
      1. 关键字有:
        1. even偶数孩子
        2. odd奇数孩子
      2. 公式
        1. 公式中的变量n从0开始,每次加1
        2. 2n,选取偶数
        3. 2n+1,选取奇数
        4. 5n,选取5的倍数
        5. n+5,第5个到最后一个
        6. -n+5,前5个(包含第5个
      3. 该选择器在计算时会先计算后面的nth-child是第几个,然后看E是否和该元素匹配。计算时会将所有直系子标签全部计算顺序
    4. E:first-of-type第一个E
    5. E:last-of-type最后一个E
    6. E:nth-of-type(n)第n个E
  3. 伪元素选择器(CSS3中使用:,CSS2中使用:)
    1. ::before
    2. ::after
    3. 该方法用于创建一个元素,该元素属于行内元素
    4. 该元素在DOM中找不到
    5. 必须包含content属性
    6. 伪元素选择器和伪类选择器权重一样wei

Sass

嵌套规则

子选择器可以直接使用嵌套实现

1
2
3
4
5
6
7
#main {
width: 20px;
height: 20px;
a {
color: yellow;
}
}

父级选择器

sass增加了父级选择器&,可以在某个css块中访问它的父级

1
2
3
4
5
6
7
.block {
width: 20px;
height: 20px;
&:hover {
text-decoration: underline;
}
}

变量

使用$来定义变量

1
2
3
4
$width: 5em;
#main {
width: $width;
}

插值语句

通过#{}来实现类似JS中的格式化字符串的效果

1
2
3
4
5
$name: foo;
$attr: border;
p.#{$name} {
#{$attr}-color: blue;
}

将编译为

1
2
3
p.foo {
border-color: blue;
}

@at-root

在某个块中跳出父节点,直接在根节点上创建样式

1
2
3
4
5
6
.parent {
...
@at-root .child {
...
}
}

会被编译为

1
2
.parent{...}
.child{...}

.child将不会被视为.parent的子选择器

整合样式的写法

css中经常会出现border这样的可以同时设置border-color border-width border-style样式的整合样式,sass中优化了这一样式的写法,可以使用{}将他们独立开:

1
2
3
4
5
6
7
p {
border: {
color: blue;
width: 2px;
style: dashed;
}
}

编译结果为:

1
2
3
4
5
p {
border-color: blue;
border-width: 2px;
border-style: dashed;
}

混入

我们可以使用任何@mixin来定义一些非常常用的样式,然后当需要为其他样式添加这些样式时,使用@include插入即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}

.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}

将会编译为

1
2
3
4
5
6
7
8
.page-title {
font-family: Arial;
font-size: 20px;
font-weight: bold;
color: #ff0000;
padding: 4px;
margin-top: 10px;
}

此外混入块还可以接收参数

1
2
3
4
5
6
7
8
9
10
11
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
}

p {
@include sexy-border(blue, lin);
}

编译后结果为:

1
2
3
4
5
p {
border-color: blue;
border-width: lin;
border-style: dashed;
}

@content

在引用mixin块时,我们希望在其中增加一些东西,那么就可以使用如下形式:

1
2
3
4
5
p {
@inlcude sexy-border(blue, 1px) {
background-image: url(/logo.gif);
}
}

此时需要和vue中的slot类似的,在mixin块中预留占位符,因此需要将上述的sexy-border修改为如下形式:

1
2
3
4
5
6
7
8
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
@content
}

此时p就会被编译为:

1
2
3
4
5
6
p {
border-color: blue;
border-width: lin;
border-style: dashed;
background-image: url(/logo.gif);
}

使用Sass实现BEM

使用mixin可以方便的实现BEM架构的命名法则

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
37
38
39
40
41
$namespace: "ender" !default;
$block-sel: "-" !default;
$elem-sel: "__" !default;
$mod-sel: "--" !default;

// TODO: 定义block生成模板,$block为block名
@mixin b($block) {
// TODO: 拼接定义class名变量
$B: #{$namespace + $block-sel + $block};
// TODO: 初始化block
.#{$B} {
@content;
}
}

// TODO: 定义element生成模板,$el为element名
@mixin e($el) {
// TODO: 获取父节点类名
$selector:&;
// TODO: 生成时避免生成类似 .ender-block .ender-block__el 的情况需要跳出嵌套
@at-root {
// TODO: 拼接定义class名变量
// 此时生成的将直接为.ender-block__el
#{$selector + $elem-sel + $el} {
@content;
}
}
}

// TODO: 定义modifier生成模板,$mod为modifier名
@mixin m($mod) {
// TODO: 获取父节点类名
$selector:&;
// TODO: 生成时避免生成类似 .ender-block__el .ender-block__el--mod 的情况需要跳出嵌套
@at-root {
// TODO: 拼接定义class名变量
#{$selector + $mod-sel + $mod} {
@content;
}
}
}

将该sass文件在vite中配置为全局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],

// 配置sass
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "./src/styles/bem.scss";`
}
}
}
})

即可在项目中的任何style中进行这样的的元素创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="ender-block">
Ender
<div class="ender-block__el">description</div>
<div class="ender-block--mod">state</div>
</div>
</template>

<style scoped lang="sass">
@include b(block) {
color: purple;
@include e(el) {
color: blue;
}
@include m(mod) {
color: red;
}
}
</style>

那么这些样式在编译之后将会形成如下css

1
2
3
4
5
6
7
8
9
.ender-block {
color: purple;
}
.ender-block__el {
color: blue;
}
.ender-block--mod {
color: red;
}

评论