理解CSS

本文于字节跳动青训营期间创作。

CSS 是什么?

CSS (Cascading Style Sheets) 又称层叠样式表,主要与HTML一同使用,被用来定义页面元素的样式,是用来控制网页外观的一门技术。它可以为HTML页面设置字体和颜色、添加位置和大小、添加动画效果等。

CSS 的工作流程

工作原理

CSS 的使用

在页面中使用css的方式有三种。

外链式

1
<link rel="stylesheet" href="./css/style.css>

嵌入式

1
2
3
4
5
6
7
<style>
div{
width:100px;
height:100px;
border:3px soild red;
}
</style>

内联式

1
<div style="width:100px; height:100px; border:3px soild red;"></div>

选择器与属性

选择器 (Selector) 会找到并选择页面中的元素,以便给它们设置样式。

选择器可以使用多种方式选择元素:

  • 按照标签名、类名或id
  • 按照属性
  • 按照 DOM 树中的位置

选择器有多种类型:

通配选择器

在 CSS 中,一个星号 (*) 就是一个通配选择器。它可以匹配任意类型的 HTML 元素。在配合其他简单选择器的时候,省略掉通配选择器会有同样的效果。比如,*.warning 和.warning 的效果完全相同。

1
2
*.warning {color:red;}
*#maincontent {border: 1px solid blue;}

标签选择器

标签选择器主要针对的是页面中某个标签中的样式设置,它的作用范围是这个页面内所有写在该标签内的内容,标签选择器可以定义多个标签的样式

1
p {color: red;}

类选择器

类选择器在定义的时候需要 “.” 来做前缀,类名是自定义的,然后在括号内定义属性和属性值。它不是直接作用在该页面中,而是需要使用class方法去自定义要作用的标签

1
2
3
.MyClass {
color: red;
}

定义完类选择器的样式之后,使用class方法去设置要调用改样式的标签。使用class方法调用类选择器中的样式的时候,直接接类名即可,不需要输入”.”。

1
<p class="MyClass">Hello</p>

类选择器可以在页面中的多个标签内重复使用,也可以中定义多个类选择器。

id选择器

ID选择器使用”#”作前缀,标识名照样是自定义的。然后括号内输入要修改样式的属性和属性值。

1
2
3
#MyId {
color: blue;
}

内定义好ID选择器之后,在需要使用该样式的标签内使用ID方法即可。

1
<p id="MyId">Hello</p>

ID=”标识名” 需要注意的是ID选择器可以创建多个,但一个id选择器中的样式只能在页面中的一个标签内使用一次。

属性选择器

类选择器 和 ID 选择器都属于 属性选择器。 应为本质上 类选择器 是 匹配 HTML 中 class 的属性值, ID 选择器 是 匹配 HTML 中的 Id 属性值

但此处说的属性选择器则是可以根据元素的属性及属性值来选择元素,与类选择器、ID选择器略有不同。

属性值 直接匹配 选择器包括下面4 种:

简单属性选择

如果希望选择有某个属性的元素,而不论属性值是什么,可以使用简单属性选择器。

1
2
3
4
5
6
7
8
/*把包含标题(title)的所有元素变为红色*/
*[title] {color:red;}

/*对有 href 属性的锚(a 元素)应用样式*/
a[href] {color:red;}

/*将同时有 href 和 title 属性的 HTML 超链接的文本设置为红色*/
a[href][title] {color:red;}

根据具体属性值选择

除了选择拥有某些属性的元素,还可以进一步缩小选择范围,只选择有特定属性值的元素。

1
2
3
4
5
/*将指向 Web 服务器上某个指定文档的超链接变成红色*/
a[href="http://www.juejin.cn/about.html"] {color: red;}

/*与简单属性选择器类似,可以把多个属性-值选择器链接在一起来选择一个文档*/
a[href="http://www.juejin.cn/"][title="juejin"] {color: red;}

请注意,这种格式要求必须与属性值完全匹配。

如果属性值包含用空格分隔的值列表,匹配就可能出问题。

1
2
3
4
5
<p class="important warning">This paragraph is a very important warning.</p>

<style>
p[class="important warning"] {color: red;}
</style>

根据部分属性值选择

如果需要根据属性值中的词列表的某个词进行选择,则需要使用波浪号(~),它能用于任何属性。

1
2
3
4
5
/*选择 class 属性中包含 important 的元素*/
p[class~="important"] {color: red;}

/*这个规则会选择 title 文本包含 "Figure" 的所有图像。没有 title 属性或者 title 属性中不包含 "Figure" 的图像都不会匹配。*/
img[title~="Figure"] {border: 1px solid gray;}

如果忽略了波浪号,则说明需要完成完全值匹配。

特定属性选择类型

该类型需要使用竖杠(|)。

1
2
/*这个规则会选择 lang 属性等于 en 或以 en- 开头的所有元素*/
*[lang|="en"] {color: red;}

根据以上规则,以下示例标记中的前三个元素将被选中,而不会选择后两个元素:

1
2
3
4
5
6
7
8
/*会被选中*/
<p lang="en">Hello!</p>
<p lang="en-us">Greetings!</p>
<p lang="en-au">G'day!</p>

/*不会被选中*/
<p lang="fr">Bonjour!</p>
<p lang="cy-en">Jrooana!</p>

组合选择器

组合选择器可以让多个选择器公用同一个CSS样式代码。

后代组合 ( )

后代选择器用于选取某元素的后代元素,使用空格分隔。

1
2
/*选取所有<div>元素中的<p>元素应用样式*/
div p { background-color:red; }

亲子组合 (>)

子元素选择器只能选择作为某元素直接或一级子元素的元素,使用(>)连接。

1
2
/*选择<div>元素中所有直接子元素<p>*/
div>p { background-color:red; }

兄弟选择器 (~)

找到指定的元素后面的所有满足条件的兄弟元素,使用(~)连接。

1
2
/*选择<p>元素后的所有<h3>元素*/
p ~ h3 { color:red; }

相邻选择器 (+)

该选择器使用(+)连接,选择紧接在另一个元素后的元素,而且二者有相同的父元素,兄弟只会影响下面的兄弟的样式,不影响上面兄弟的样式。

1
2
/*选择与<h1>元素相邻的<p>元素*/
h1 + p { margin-top:50px; color:red; }

分组选择器 (,)

分组选择器使用逗号把同组内不同对象分隔,其本质上不是一种选择器类型,而是一种选择器使用方法。当多个对象定义了相同的样式时,就可以把它们分成一组,这样能够简化代码。

1
2
3
4
/*定义所有级别的标题和段落行高为22px*/
h1,h2,h3,h4,h5,h6,p{
line-height:22px;
}

伪类选择器

伪类通常用于标记一些特殊的样,用于控制一个元素在不同动作下有不同的样式。

伪类主要有两方面的用处,一方面是标记一些特殊的状态,另外还有一类伪类是有筛选的功能。

以下仅记录一些常用的伪类。

状态伪类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*选取未访问过的超链接元素。如果我们注意过搜索引擎的结果的话,它里面的链接只要点过的就会变色,从而标记哪个链接是访问过的*/
:link{}

/*选取访问过的超链接元素。和第一条相反,:visited 是用来标记哪个链接是已经访问过的,防止重复点击*/
:visited{}

/*选取鼠标悬停的元素,当鼠标放在一个元素上时显示的样式*/
:hover{}

/*选取点中的元素。这个伪类的作用在刚才提到过了,当我们希望按钮有操作反馈的时候,可以用它来标记操作反馈的样式。当然这个伪类也是可以通用的,并不是只能用在按钮上*/
:active{}

/*选取获得焦点的元素。这个伪类用来标识获得焦点的元素,比如搜索框在聚焦的时候有个比较明显的边框,方便用户知道当前在可输入的状态*/
:focus{}

筛选伪类

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
/*选取没有子元素的元素。比如选择空的 span,就可以用 span:empty 选择器来选择。这里要注意元素内有空格的话也不能算空,不会被这个伪类选中*/
:empty{}

/*选取勾选状态的 input 元素, 只对 radio 和 checkbox 生效*/
:checked{}

/*选取禁用的表单元素*/
:disabled{}

/*选取当前选择器下第一个元素*/
:first-child{}

/*和 first-child 相反,选取当前选择器下最后一个元素*/
:last-child{}

/*选取指定位置的元素。这个伪类是有参数的,参数可以支持 an+b 的形式,这里 a 和 b 都是可变的,n 从0起。使用这个伪类可以做到选择第几个,或者选择序号符合 an+b 的所有元素。比如使用 li:nth-child(2n+1),就可以选中 li 元素中序号是2的整数倍加1的所有元素,也就是第1、3、5、7、9、2n+1个 li 元素*/
:nth-child(an+b){}

/*这个伪类和 nth-child 相似,只不过在计数的时候,这个伪类是从后往前计数*/
:nth-last-child(an+b){}

/*选取唯一子元素。如果一个元素的父元素只有它一个子元素,这个伪类就会生效。如果一个元素还有兄弟元素,这个伪类就不会对它生效*/
:only-child{}

/*选取唯一的某个类型的元素。如果一个元素的父元素里只有它一个当前类型的元素,这个伪类就会生效。这个伪类允许父元素里有其他元素,只要不和自己一样就可以*/
:only-of-type{}

伪元素选择器

伪元素选择器是用于向某些元素设置特殊效果。伪元素选择器选中的并不是真实的 DOM 元素,所以叫伪元素选择器。常用的伪元素选择器有5个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*为某个元素的第一行文字使用样式*/
::first-line{}

/*为某个元素中的文字的首字母或第一个字使用样式*/
::first-letter{}

/*在某个元素之前插入一些内容*/
::before{}

/*在某个元素之后插入一些内容*/
::after{}

/*对光标选中的元素添加样式*/
::selection{}
  1. 伪元素选择器构造的元素是虚拟的,所以不能用 JS 去操作它。
  2. 如果同时使用了 before 和 first-letter 两个伪类,第一个字是要从 before 里的内容开始算起的,如果 before里面的内容是一个非文本元素,那 first-letter 也会作用在这个非文本元素上,但是不一定能生效。
  3. first-line 和 first-letter 不适用于内联元素,在内联元素中这两个选择器都会失效。
  4. 在 CSS3 中,规定了伪类用一个冒号(:)表示,伪元素用两个冒号表示(::)。但除了 selection,其余四个伪元素选择器已经在 CSS2 中存在且和伪类用的是一样的单冒号表示的。为了向下兼容,现在的浏览器中伪元素选择器用单冒号和双冒号都可以。在没有兼容问题的情况下,还是建议大家按着新的 CSS3 标准来开发。

选择器的特异度

选择器的特异度由选择器本身的组件确定。

如果一个元素有两个或多个冲突的属性声明,那么有最特异度高的声明就会胜出。

特异度表述为4个部分,如:(0, 0, 0, 0),从左到右的权重由高到低。

权重排行(高到低):

  1. 行内样式
    1
    (!important)
  2. ID选择器
    1
    #id
  3. class、属性、伪类选择器
    1
    2
    3
    .title
    input[type="text"]
    :hover
  4. 类型和伪元素选择器
    1
    2
    div
    ::before

权重向量

(0, 0, 0, 0)
(行内样式,ID选择器,class/属性/伪类选择器/,类型/伪元素)

若权重相同,则定义靠后优先。

实例

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
<div id="container">
<ul class="menu">
<li id="item1" class="item1">item1</li>
<li class="item2">item2</li>
<li class="item3">item3</li>
</ul>
</div>

<style>
/* (0, 1, 3, 1) */
#container .menu li.item2 {
color: #ff4757;
}

/* (0, 1, 2, 1) */
#container li:nth-child(2).item2 {
color: #7bed9f;
}

/* (0, 1, 1, 1) */
#container li.item2 {
color: #ffa502;
}


/* (0, 0, 1, 1) */
li.item2 {
color: #5352ed;
}

/* (0, 0, 1, 0) */
.item2 {
color: #ff6b81
}
</style>

继承

无继承性的属性

  1. display:元素布局类型
  2. 文本属性:
    • vertical-align:垂直文本对齐
    • text-decration:规定添加到文本的装饰
    • text-shadow:文本阴影效果
    • white-space:空白符的处理
    • unicode-bidi:设置文本的方向
  3. 盒子模型的属性:
    • width
    • height
    • margin
    • border
    • padding
  4. 背景属性:
    • background
    • background-color
    • background-image
    • background-repeat
    • background-position
    • background-attachment
  5. 定位属性:
    • float
    • clear
    • position
    • top
    • right
    • bottom
    • left
    • min-width
    • min-height
    • max-width
    • max-height
    • overflow
    • clip
    • z-index
  6. 生成内容属性:
    • content
    • counter-reset
    • counter-increment
  7. 轮廓样式属性:
    • outline-style
    • outline-width
    • outline-color
    • outline
  8. 页面样式属性:
    • size
    • page-break-before
    • page-break-after
  9. 声音样式属性:
    • pause-before
    • pause-after
    • pause
    • cue-before
    • cue-after
    • cue
    • play-during

有继承性的属性

  1. 字体系列属性:
    • font-family:字体系列
    • font-weight:字体的粗细
    • font-size:字体的大小
    • font-style:字体的风格
  2. 文本系列属性
    • text-indent:文本缩进
    • text-align:文本水平对齐
    • line-height:行高
    • word-spacing:单词之间的间距
    • letter-spacing:中文或者字母之间的间距
    • text-transform:控制文本大小写(就是uppercase、lowercase、capitalize这三个)
    • color:文本颜色
  3. 元素可见性:
    • visibility:控制元素显示隐藏
  4. 列表布局属性:
    • list-style:列表风格,包括list-style-type、list-style-image等
  5. 光标属性:
    • cursor:光标显示为何种形态

布局

内容主要来源:一篇全面的CSS布局学习指南(译)

布局(layout)即确定内容的大小和位置的算法,其根据元素、容器、兄弟节点和内容等信息来计算。

css中的布局有多种。

常规流布局(normal flow)

在正常流中,元素盒子(boxes)会基于文档的写作模式(writing mode)一个接一个地排列。这就意味着,如果你的写作模式是水平方向的(句子是从左到右或从右到左书写),正常流会垂直地一个接一个排列页面的块级元素。

当然,如果你是在一个垂直方向的写作模式下,句子是垂直方向书写的,所以块级元素会水平方法排列。

normal

  • 根元素、浮动和绝对定位的元素会脱离常规流
  • 其他元素都在常规流之内(in-flow)
  • 常规流中的盒子,在某种 排版上下文 中参与布局

浮动布局 (float)

浮动布局被用来将盒子(box)置于左侧或右侧,同时让内容环绕其展示。

如果要让一个元素进行浮动,需要为该元素设置一个值为leftright等的float属性。默认值为none

1
2
3
4
5
6
7
8
.item { float: left }

/* 其他常见的float的值 */
.item {float: left; } /*表明元素必须浮动在其所在的块容器左侧的关键字。*/
.item {float: right; } /*表明元素必须浮动在其所在的块容器右侧的关键字。*/
.item {float: none; } /*表明元素不进行浮动的关键字。*/
.item {float: inline-start; } /*关键字,表明元素必须浮动在其所在块容器的开始一侧,在 `ltr` 脚本中是左侧,在 `rtl` 脚本中是右侧。*/
.item {float: inline-end; } /*关键字,表明元素必须浮动在其所在块容器的结束一侧,在 `ltr` 脚本中是右侧,在 `rtl` 脚本中是左侧。*/

清除浮动

一旦你对一个元素应用了浮动,所有接下来的元素都会环绕它直到内容处于它下方且开始应用正常文档流。如果你想要避免这种情况,可以手动去清除浮动。

当你不想要某个元素受到其之前的浮动元素影响时,为其添加clear属性即可。使用left值可以清除左浮动效果,right值为右浮动,both则会清除左右浮动。

1
2
3
4
5
6
7
8
9
.clear { clear: both; }

/*其他常见的clear的值*/
.clear { clear: none; } /*元素不会被向下移动以清除浮动。*/
.clear { clear: left; } /*元素被向下移动以清除左浮动。*/
.clear { clear: right; } /*元素被向下移动以清除右浮动。*/
.clear { clear: both; } /*元素被向下移动以清除左右浮动。*/
.clear { clear: inline-start; } /*元素被向下移动以清除其包含块的起始侧浮动,即 ltr 时清除左浮动,rtl 时清除右浮动。*/
.clear { clear: inline-end; } /*元素被向下移动以清除其包含块的结束侧浮动,即 ltr 时清除右浮动,rtl 时清除左浮动。*/

定位 (Positioning)

position 属性用于指定一个元素在文档中的定位方式。

想要把一个元素从正常流中移除,或者改变其在正常文档流中的位置,可以使用CSS中的position属性。当处于正常文档流时,元素的position属性为static。在块级维度上元素会一个接一个排列下去,当你滚动页面时元素也会随着滚动。

当你改变元素的position属性时,通常情况下你也会设置一些偏移量来使元素相对于参照点进行一定的移动。不同的position值会产生不同的参照点。

静态定位(STATIC POSTIONING)

该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 toprightbottomleft 和 z-index 属性无效。

1
.item { position: static; }

相对定位(RELATIVE POSTIONING)

在绝对定位中,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。

如果一个元素具有属性position: relative,那么它偏移的参照位是其原先在正常文档流中的位置。你可以使用topleftbottomright属性来相对其正常流位置进行移动。

1
.item { position: relative; bottom: 50px; }

相对定位是不脱离标准流的, 会继续在标准流中占用一份空间
在相对定位中同一个方向上的定位属性只能使用一个
由于相对定位是不脱离标准流的, 所以在相对定位中是区分块级元素/行内元素/行内块级元素
由于相对定位是不脱离标准流的, 并且相对定位的元素会占用标准流中的位置, 所以当给相对定位 的元素设置margin/padding等属性的时会影响到标准流的布局

绝对定位(ABSOLUTE POSTIONING)

给一个元素设置 position: absolute ,其元素会被移出正常文档流,并不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。

因此,当你为某个元素设置 position: absolute 时,首先发生的变化是该元素会定位在视口的左上角。你可以通过设置 topleftbottomright 偏移量属性来将元素移动到你想要的位置。

1
.item { position: absolute; top: 20px; right: 20px; }
  • 绝对定位参考点:
    1. 规律:默认情况下所有的绝对定位的元素, 无论有没有祖先元素, 都会以 body 作为参考点。
    2. 如果一个绝对定位的元素有祖先元素, 并且祖先元素也是定位流, 那么这个绝对定位的元素就会以定位流的那个祖先元素作为参考点。
      1. 只要是这个绝对定位元素的祖先元素都可以 。
      2. 指的定位流是指绝对定位/相对定位/固定定位 。
      3. 定位流中只有静态定位不行。
    3. 如果一个绝对定位的元素有祖先元素, 并且祖先元素也是定位流, 而且祖先元素中有多个元素都是定位流, 那么这个绝对定位的元素会以离它最近的那个定位流的祖先元素为参考点。
  • 绝对定位注意点:
    1. 绝对定位的元素是脱离标准流的 。
    2. 绝对定位的元素是不区分块级元素/行内元素/行内块级元素 。
    3. 如果一个绝对定位的元素是以 body 作为参考点, 那么其实是以网页首屏的宽度和高度作为参考点, 而不是以整个网页的宽度和高度作为参考点 。
    4. 一个绝对定位的元素会忽略祖先元素的 padding
  • 绝对定位-子绝父相:
    • 相对定位弊端:相对定位不会脱离标准流, 会继续在标准流中占用一份空间, 所以不利于布局界面。
    • 绝对定位弊端:默认情况下绝对定位的元素会以 body 作为参考点, 所以会随着浏览器的宽度高度的变化而变化。
    • 子绝父相:子元素用绝对定位, 父元素用相对定位。(如果不这么做,子元素就会相对 body 或浏览器定位产生不好的效果。)

固定定位(FIXED POSTIONING)

position: fixed 的元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform , perspective 或 filter 属性非 none 时,容器由视口改为该祖先。

1
.item { position: fixed; top: 20px; left: 100px; }

当你想要一个固定导航栏一直停留在屏幕上时这会非常有效。

STICKY 定位

设置 position: sticky 会让元素在页面滚动时如同在正常流中,但当其滚动到相对于视口的某个特定位置时就会固定在屏幕上,如同fixed一般。

1
.item { position: sticky; top: 0; }

弹性布局(Flex Layout)

弹性盒子(Flexbox)布局是一种为一维布局而设计的布局方法。一维的意思是你希望内容是按行或者列来布局。你可以使用 display: flex 来将元素变为弹性布局。

1
.container { display: flex; }

Flex的主轴与交叉轴

当使用 flex 布局时,首先想到的是两根轴线 — 主轴和交叉轴。主轴由 flex-direction 定义,另一根轴垂直于它。我们使用 flexbox 的所有属性都跟这两根轴线有关,所以有必要在一开始首先理解它。

主轴

主轴由 flex-direction 定义,可以取 4 个值(默认为 row ):

  • row
  • row-reverse
  • column
  • column-reverse

如果你选择了 row 或者 row-reverse,你的主轴将沿着 inline 方向延伸。

1
2
3
4
.itme { 
display: flex;
flex-direction: row;
}

选择 column 或者 column-reverse 时,你的主轴会沿着上下方向延伸 — 也就是 block 排列的方向。

交叉轴

交叉轴垂直于主轴,所以如果你的flex-direction (主轴) 设成了 row 或者 row-reverse 的话,交叉轴的方向就是沿着列向下的。

如果主轴方向设成了 column 或者 column-reverse,交叉轴就是水平方向。

理解主轴和交叉轴的概念对于对齐 flexbox 里面的元素是很重要的;flexbox 的特性是沿着主轴或者交叉轴对齐之中的元素。

flex-wrap

虽然flexbox是一维模型,但可以使我们的flex项目应用到多行中。在这样做的时候,您应该把每一行看作一个新的flex容器。任何空间分布都将在该行上发生,而不影响该空间分布的其他行。

为了实现多行效果,请为属性 flex-wrap 添加一个属性值 wrap 。现在,如果您的项目太大而无法全部显示在一行中,则会换行显示。下面的实时例子包含已给出宽度的项目,对于 flex 容器,项目的子元素总宽度大于容器最大宽度。由于 flex-wrap 的值设置为 wrap ,所以项目的子元素换行显示。若将其设置为 nowrap ,这也是初始值,它们将会缩小以适应容器,因为它们使用的是允许缩小的初始 Flexbox 值。如果项目的子元素无法缩小,使用 nowrap 会导致溢出,或者缩小程度还不够小。

1
2
3
4
5
.item { 
display: flex;
flex-wrap: wrap;
/*flex-wrap: nowrap;*/
}

一些Flex的属性

这些flex的属性是用来控制弹性项在主轴上空间大小的。这三个属性是:

  • flex-grow
  • flex-shrink
  • flex-basis

通常可以使用它们的简写形式:flex 。第一个值代表 flex-grow ,第二个是 flex-shrink ,而第三个则是 flex-basis

1
.item { flex: 1 1 200px; }

flex-basis 会为弹性项设置未拉伸和压缩时的初始大小。在上面的例子中,大小是200px,因此我们会给每个项200px的空间大小。但是大多数情况下容器元素大小不会正好被分为许多200px大小的项,而是可能有一些不足或剩余空间。 flex-growflow-shrink 属性允许我们在容器大小不足或有空余时控制各个弹性项的大小。

如果 flex-grow 的值是任意的正数,那么弹性项会被允许拉伸来占据更多的空间。因此,在上面的例子中,当各项被设为200px后,所有多余的空间会被每个弹性项平分并填满。

如果 flex-shrink 的值为任意的正数,那么当弹性项被设置了 flex-basis 后,元素溢出容器时会进行收缩。在上面这个CSS的例子中,如果容器空间不足,每个弹性项会等比例缩放以适应容器的大小。

flex-growflex-shrink 的值可以是任意的正数。一个具有较大 flex-grow 值的弹性项会在容器有剩余空间时拉伸更大的比例;而一个具有更大 flex-shrink 值的项则会在容器空间不足时被压缩的更多。

大多数情况下可以用预定义的简写形式。在这个教程中你可能经常会看到这种写法,许多情况下你都可以这么使用。下面是几种预定义的值:

  • flex: initial
  • flex: auto
  • flex: none
  • flex: <positive-number>

flex: initial 是把 flex 元素重置为 Flexbox 的初始值,它相当于 flex: 0 1 auto。在这里 flex-grow 的值为 0,所以 flex 元素不会超过它们 flex-basis 的尺寸。flex-shrink 的值为 1, 所以可以缩小 flex 元素来防止它们溢出。flex-basis 的值为 auto. Flex 元素尺寸可以是在主维度上设置的,也可以是根据内容自动得到的。

flex: auto 等同于 flex: 1 1 auto;和上面的 flex:initial 基本相同,但是这种情况下,flex 元素在需要的时候既可以拉伸也可以收缩。

flex: none 可以把 flex 元素设置为不可伸缩。它和设置为 flex: 0 0 auto 是一样的。元素既不能拉伸或者收缩,但是元素会按具有 flex-basis: auto 属性的 flexbox 进行布局。

你在教程中常看到的 flex: 1 或者 flex: 2 等等。它相当于flex: 1 1 0。元素可以在flex-basis为 0 的基础上伸缩。

网格布局(grid layout)

内容主要来源:最强大的 CSS 布局 —— Grid 布局

CSS网格布局(grid layout)是一种用来进行二维布局的技术。二维(two-dimesional)意味着你希望按照行和列来排布你的内容。和弹性盒子类似,网格布局也需要设置一个 display 值。你可以为容器元素设置 display: grid ,并且使用 grid-template-columnsgrid-template-rows 属性来控制网格中的行与列。

Grid 布局是将容器划分成了“行”和“列”,产生了一个个的网格,我们可以将网格元素放在与这些行和列相关的位置上,从而达到我们布局的目的。

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

grid-template-columns 属性和 grid-template-rows 属性

grid-template-columns 属性设置列宽,grid-template-rows 属性设置行高,这两个属性在 Grid 布局中尤为重要,它们的值是有多种多样的,而且它们的设置是比较相似的。

1
2
3
4
5
6
7
8
9
10
11
.wrapper { 
display: grid;

/* 声明了三列,宽度分别为 200px 100px 200px */
grid-template-columns: 200px 100px 200px;

/* 声明了两行,行高分别为 50px 50px */
grid-template-rows: 50px 50px;

grid-gap: 5px;
}

以上表示固定列宽为 200px 100px 200px,行高为 50px 50px 。

repeat() 函数

repeat() 函数可以简化重复的值。该函数接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。比如上面行高都是一样的,我们可以这么去实现,实际效果是一模一样的。

1
2
3
4
5
6
7
8
.wrapper { 
display: grid;
grid-template-columns: 200px 100px 200px;
grid-gap: 5px;

/* 2行,而且行高都为 50px */
grid-template-rows: repeat(2, 50px);
}
auto-fill 关键字

auto-fill 关键字表示自动填充,让一行(或者一列)中尽可能的容纳更多的单元格。grid-template-columns: repeat(auto-fill, 200px) 表示列宽是 200 px,但列的数量是不固定的,只要浏览器能够容纳得下,就可以放置元素

1
2
3
4
5
6
.wrapper { 
display: grid;
grid-template-columns: repeat(auto-fill, 200px);
grid-gap: 5px;
grid-auto-rows: 50px;
}

fr 关键字

Grid 布局还引入了一个另外的长度单位来帮助我们创建灵活的网格轨道。fr 单位代表网格容器中可用空间的一等份。grid-template-columns: 200px 1fr 2fr 表示第一个列宽设置为 200px,后面剩余的宽度分为两部分,宽度分别为剩余宽度的 1/3 和 2/3。

1
2
3
4
5
6
.wrapper { 
display: grid;
grid-template-columns: 200px 1fr 2fr;
grid-gap: 5px;
grid-auto-rows: 50px;
}

minmax() 函数

minmax() 函数:我们有时候想给网格元素一个最小和最大的尺寸,minmax() 函数产生一个长度范围,表示长度就在这个范围之中都可以应用到网格项目中。它接受两个参数,分别为最小值和最大值。grid-template-columns: 1fr 1fr minmax(300px, 2fr) 的意思是,第三个列宽最少也是要 300px,但是最大不能大于第一第二列宽的两倍。

1
2
3
4
5
6
.wrapper-4 { 
display: grid;
grid-template-columns: 1fr 1fr minmax(300px, 2fr);
grid-gap: 5px;
grid-auto-rows: 50px;
}

grid-row-gap 属性、grid-column-gap 属性以及 grid-gap 属性

grid-row-gap 属性、grid-column-gap 属性分别设置行间距和列间距。grid-gap 属性是两者的简写形式。

grid-row-gap: 10px 表示行间距是 10px,grid-column-gap: 20px 表示列间距是 20px。grid-gap: 10px 20px 实现的效果是一样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.wrapper { 
display: grid;
grid-template-columns: 200px 100px 100px;
grid-gap: 10px 20px;
grid-auto-rows: 50px;
}

.wrapper-1 {
display: grid;
grid-template-columns: 200px 100px 100px;
grid-auto-rows: 50px;
grid-row-gap: 10px;
grid-column-gap: 20px;
}

基于行/列的基本定位方法

定位网格元素最简单的方式是使用基于行/列(line)的定位方法,只需告诉浏览器从哪一排到哪一排来进行合并。例如,如果你需要一个2*2的网格区域,你可以将指定元素从第一行开始到第三行、从第一列开始到第三列,这样就可以覆盖到四个单元格。

1
2
3
4
5
6
.item { 
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 3;
}

这些属性可以用缩写来表示:grid-columngrid-row,其中起一个值代表起始值,第二个值代表结束值。

1
2
3
4
.item { 
grid-column: 1 / 3;
grid-row: 1 / 3;
}

你也可以让网格项(grid item)占据同一个单元格。支持一些内容间会覆盖的设计。网格项会像通常网页中的元素那样叠起来,在html源码中下面的网格项会叠在其他元素上面。你仍然可以用z-index来控制它的堆叠顺序。

实例:

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
<div class="container">
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="four">4</div>
<div class="five">5</div>
</div>

<style>
body {
padding: 20px;
font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {
box-sizing: border-box;
}

p {
margin: 0 0 1em 0;
}

.container {
width: 500px;
border: 5px solid rgb(111,41,97);
border-radius: .5em;
padding: 10px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 20px;
}

.container > div {
padding: 10px;
}

.one {
grid-column: 1 / 4;
grid-row: 1;
background-color: rgba(111,41,97,.3);
border: 2px solid rgba(111,41,97,.5);
}

.two {
grid-column: 1 / 3;
grid-row: 2;
background-color: rgba(111,41,97,.3);
border: 2px solid rgba(111,41,97,.5);
}

.three {
grid-column: 2 / 4;
grid-row: 2 / 5;
background-color: rgba(193,225,237,.3);
border: 2px solid rgba(193,225,237,.5);
}

.four {
grid-column: 1;
grid-row: 4 ;
background-color: rgba(193,225,237,.3);
border: 2px solid rgba(193,225,237,.5);
}

.five {
grid-column: 3 ;
grid-row: 4 / 5;
background-color: rgba(111,41,97,.3);
border: 2px solid rgba(111,41,97,.5);
}
</style>

通过命名区域来定位元素

你可以通过命名区域(named areas)来定位网格中的元素。要是用这种方式,你需要给每个元素一个名字,然后通过grid-template-areas属性的值来描述布局方式。

1
2
3
4
5
6
7
8
9
10
.item1 { grid-area: a; } 
.item2 { grid-area: b; }
.item3 { grid-area: c; }

.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-areas: "a a b b"
"a a c c";
}

使用这种方式有几个需要注意的点。如果你想要合并一些单元格作为你的网格项,你需要重复元素的名字。网格区域需要能形成一个完整的矩形 —— 每个单元格都需要被填入一个值。如果你想要空出某些单元格,那就需要使用 . 这个值。

1
2
3
4
5
6
.container { 
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-areas: "a a b b"
"a a c .";
}

实例:

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
<div class="container">
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="four">4</div>
<div class="five">5</div>
</div>

<style>
body {
padding: 20px;
font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {
box-sizing: border-box;
}

p {
margin: 0 0 1em 0;
}

.container {
width: 500px;
border: 5px solid rgb(111,41,97);
border-radius: .5em;
padding: 10px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: minmax(50px, auto);
grid-gap: 20px;
grid-template-areas: "a a a"
"b c c"
". . d"
"e e d";
}

.container > div {
padding: 10px;
background-color: rgba(111,41,97,.3);
border: 2px solid rgba(111,41,97,.5);
}

.one {
grid-area: a;
}

.two {
grid-area: b;
}

.three {
grid-area: c;
}

.four {
grid-area: d;
}

.five {
grid-area: e;
}
</style>

排版上下文

行级排版上下文

  • Inline Formatting Context (IFC)
  • 只包含行级盒子 的容器会创建一个IFC
  • IFC 内的排版规则:
    • 盒子在同一行水平摆放
    • 一行放不下时,换行显示
    • text-align 决定一行内盒子的水平对齐
    • vertical-align 决定一个盒子的水平对其
    • 避开浮动(float)元素*

块级排版上下文

  • Block Formatting Context (BFC)
  • 某些元素会创建一个BFC:
    • 根元素
    • 浮动、绝对定位、inline-block
    • Flex子项和Gird子项
    • overflow 值不是 visible 的块盒
    • display:flow-root;

网格布局格式化上下文

  • Grid Formatting Context (GFC)
  • 声明display:grid/inline-grid能创建一个网格容器,网格容器会为其内容产生GFC。
  • 网格布局引入了二维网格布局系统,通过一组相交的水平线和垂直线来定义网格的列和行,网格元素被布局到这些行和列相关的位置上。

弹性格式化上下文

  • Flex Formatting Context (FFC)
  • 声明display:flex/inline-flex能创建一个弹性容器,弹性容器会为其内容产生FFC。

颜色

RGB

1
2
3
rgb(#fff, #fff, #fff);

/* rgba(#fff, #fff, #fff, 1); */

HSL

1
2
3
hsl(120, 66%, 50%);

/* hsla(120, 66%, 50%, 1); */

字体

font-family

font-family 可以把多个字体名称作为一个“回退”系统来保存。如果浏览器不支持第一个字体,则会尝试下一个。也就是说,font-family 属性的值是用于某个元素的字体族名称或/及类族名称的一个优先表。

1
font-family:"Times New Roman",Georgia,Serif;

font-size

用于设置 字体大小,辅以单位控制,实质上是控制 字符框 的高度。

font-style

font-style属性指定文本的字体样式。

1
2
3
4
font-style:normal; /*默认值。浏览器显示一个标准的字体样式。*/
//font-style:italic; /*浏览器会显示一个斜体的字体样式。*/
//font-style:oblique; /*浏览器会显示一个倾斜的字体样式。*/
//font-style: inherit ; /*规定应该从父元素继承字体样式。*/

font-weight

font-weight 属性设置文本的粗细。

1
2
3
font-weight:normal; /*默认值,标准。*/
//font-weight:bold; /*加粗*/
//font-weight:900; /*自定义数值*/

font-variant

font-variant 属性设置小型大写字母的字体显示文本,这意味着所有的小写字母均会被转换为大写,但是所有使用小型大写字体的字母与其余文本相比,其字体尺寸更小

font-variant 属性主要用于定义小型大写字母文本

1
2
3
font-variant:normal; /*默认值。浏览器会显示一个标准的字体。*/
//font-variant:normal; /*浏览器会显示小型大写字母的字体。*/
//font-variant:normal; /*规定应该从父元素继承 font-variant 属性的值。*/

font

font 简写属性在一个声明中设置所有字体属性。

可设置的属性是(按顺序): “font-style font-variant font-weight font-size/line-height font-family”

font-size和font-family的值是必需的。如果缺少了其他值,默认值将被插入,如果有默认值的话。

1
2
font:15px arial,sans-serif;
//font:italic bold 12px/30px Georgia, serif;

文本格式

line-height

设置以百分比计的行高。

1
2
line-height:90%
//line-height:200%

注意: 负值是不允许的

white-space

指定元素内的空白怎样处理。

1
2
3
4
5
6
white-space:normal; /*默认。空白会被浏览器忽略。*/
//white-space:pre; /*空白会被浏览器保留。其行为方式类似 HTML 中的 <pre> 标签。*/
//white-space:nowrap; /*文本不会换行,文本会在在同一行上继续,直到遇到 <br> 标签为止。*/
//white-space:pre-wrap; /*保留空白符序列,但是正常地进行换行。*/
//white-space:pre-line; /*合并空白符序列,但是保留换行符。*/
//white-space:inherit; /*规定应该从父元素继承 white-space 属性的值。*/

盒子模型

块级

Block Level Box 不和其他盒子并列摆放,适用所有的盒模型属性。

块级元素生成块级盒子:body、article、div、main、section、h1-6、p、ul、li 等。

1
display:block;

行级

Inline Level Box 和其他行级盒子一起放在一行或拆开成多行,盒模型中的width、height不适用。

行级元素生成行级盒子,内容分散在多个行盒(line box)中:span、em、strong、cite、code 等。

1
display:inline;

Flex Box

Flex Box 是一种新的排版上下文,它可以控制子级盒子的:

  • 摆放的流向(→ ↑ ↓ ←)
  • 摆放顺序
  • 盒子宽度和高度
  • 水平和垂直方向的对齐
  • 是否允许折行
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
display:flex;

/* 项目在主轴上的对齐方式 */
justify-content: center;     /* 居中排列 */
//justify-content: start;      /* 从行首开始排列 */
//justify-content: end;        /* 从行尾开始排列 */
//justify-content: flex-start; /* 从行首起始位置开始排列 */
//justify-content: flex-end;   /* 从行尾位置开始排列 */
//justify-content: left;       /* 一个挨一个在对齐容器得左边缘 */
//justify-content: right;      /* 元素以容器右边缘为基准,一个挨着一个对齐, */

/* 基线对齐 */
//justify-content: baseline;
//justify-content: first baseline;
//justify-content: last baseline;

/* 分配弹性元素方式 */
//justify-content: space-between;  /* 均匀排列每个元素,首个元素放置于起点,末尾元素放置于终点 */
//justify-content: space-around;  /* 均匀排列每个元素,每个元素周围分配相同的空间 */
//justify-content: space-evenly;  /* 均匀排列每个元素,每个元素之间的间隔相等 */
//justify-content: stretch;       /* 均匀排列每个元素,auto-sized 的元素会被拉伸以适应容器的大小 */

/* 溢出对齐方式 */
//justify-content: safe center;
//justify-content: unsafe center;

/* 全局值 */
//justify-content: inherit;
//justify-content: initial;
//justify-content: unset;


/* 项目在交叉轴上的对齐方式 */
//align-items:...;

/* 多行项目的排列方式 */
//align-content:...;

display 属性

1
2
3
4
5
6
7
8
9
display:block; /*块级盒子*/

//display:linine; /*行级盒子*/

//display:inline-block; /*本身是行级,可以放在行盒中;可以设置宽高;作为一个整体不会被拆散成多行*/

//display:flex; /*浮动布局*/

//display:none; /*排版时完全被忽略*/

调试 CSS

  • 在chrome浏览器中,可以通过F12或菜单,打开“开发者工具”。
  • ctrl + shift + i

理解CSS
https://asuka24601.github.io/2022/07/25/理解CSS/
作者
Asuka24601
发布于
2022年7月25日
许可协议