CSS
CSS 层叠样式表,是一种描述 HTML 文档样式的语言。
盒子模型
- 标准盒子模型: 盒子宽度 = 内容的宽度 height(content)+ border + padding + margin [
box-sizing:content-box
] - 怪异(IE)盒子模型:盒子宽度 = 内容宽度 height(content + border + padding)+ margin [
box-sizing:border-box
]
选择器
- 常用选择器
1
2
3
4
5
6
7通配符:*
ID选择器:#ID
类选择器:.class
元素选择器:p、a 等
后代选择器:p span、div a 等
伪类选择器:a:hover 等
属性选择器:input[type="text"] 等 - 选择器权重
1
!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认
初始化
因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。当然,初始化样式会对SEO有一定的影响,但鱼和熊掌不可兼得,但力求影响最小的情况下初始化。
BFC
BFC 是 Block Formatting Context 的缩写,即块格式化上下文。BFC是CSS布局的一个概念,是一个环境,里面的元素不会影响外面的元素。
触发条件:
- 根元素
- position: absolute/fixed
- display: inline-block / table
- float
- ovevflow !== visible
规则:
- 属于同一个 BFC 的两个相邻 Box 垂直排列
- 属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠
- BFC 中子元素的 margin box 的左边, 与包含块 (BFC) border box的左边相接触 (子元素 absolute 除外)
- BFC 的区域不会与 float 的元素区域重叠
- 计算 BFC 的高度时,浮动子元素也参与计算
- 文字层不会被浮动层覆盖,环绕于周围
应用:
- 阻止margin重叠
- 可以包含浮动元素 —— 清除内部浮动(清除浮动的原理是两个div都位于同一个 BFC 区域之中)
- 自适应两栏布局
- 可以阻止元素被浮动元素覆盖
居中布局
左右居中
- 行内元素: text-align: center
- 定宽块状元素: 左右 margin 值为 auto
- 不定宽块状元素: table布局,position + transform
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23/* 方案1 */
.wrap {
text-align: center
}
.center {
display: inline;
/* or */
/* display: inline-block; */
}
/* 方案2 */
.center {
width: 100px;
margin: 0 auto;
}
/* 方案2 */
.wrap {
position: relative;
}
.center {
position: absulote;
left: 50%;
transform: translateX(-50%);
}
上下垂直居中
- 定高:margin,position + margin(负值)
- 不定高:position + transform,flex,IFC + vertical-align:middle
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/* 定高方案1 */
.center {
height: 100px;
margin: 50px 0;
}
/* 定高方案2 */
.center {
height: 100px;
position: absolute;
top: 50%;
margin-top: -25px;
}
/* 不定高方案1 */
.center {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
/* 不定高方案2 */
.wrap {
display: flex;
align-items: center;
}
.center {
width: 100%;
}
/* 不定高方案3 */
/* 设置 inline-block 则会在外层产生 IFC,高度设为 100% 撑开 wrap 的高度 */
.wrap::before {
content: '';
height: 100%;
display: inline-block;
vertical-align: middle;
}
.wrap {
text-align: center;
}
.center {
display: inline-block;
vertical-align: middle;
}
清除浮动
- 在浮动元素后面添加 clear:both 的空 div 元素
1
2
3
4
5<div class="container">
<div class="left"></div>
<div class="right"></div>
<div style="clear:both"></div>
</div> - 给父元素添加 overflow:hidden 或者 auto 样式,触发BFC
1
2
3
4<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>1
2
3
4
5
6.container{
width: 300px;
background-color: #aaa;
overflow:hidden;
zoom:1; /*IE6*/
} - 使用伪元素,也是在元素末尾添加一个点并带有 clear: both 属性的元素实现的。
推荐使用,不会在页面新增div,文档结构更加清晰
1
2
3
4<div class="container clearfix">
<div class="left"></div>
<div class="right"></div>
</div>1
2
3
4
5
6
7
8
9
10.clearfix{
zoom: 1; /*IE6*/
}
.clearfix:after{
content: ".";
height: 0;
clear: both;
display: block;
visibility: hidden;
}
link 与 @import 的区别
- link功能较多,可以定义 RSS,定义 Rel 等作用,而@import只能用于加载 css
- 当解析到link时,页面会同步加载所引的 css,而@import所引用的 css 会等到页面加载完才被加载
- @import需要 IE5 以上才能使用
- link可以使用 js 动态引入,@import不行
CSS3的新特性
transition和animation的区别
Animation和transition大部分属性是相同的,他们都是随时间改变元素的属性值,他们的主要区别是transition需要触发一个事件才能改变属性,而animation不需要触发任何事件的情况下才会随时间改变属性值,并且transition为2帧,从from … to,而animation可以一帧一帧的
- transition:过渡
- transform: 旋转、缩放、移动或倾斜
- animation: 动画
- gradient: 渐变
- box-shadow: 阴影
- border-radius: 圆角
- word-break: normal|break-all|keep-all; 文字换行(默认规则|单词也可以换行|只在半角空格或连字符换行)
- text-overflow: 文字超出部分处理
- text-shadow: 水平阴影,垂直阴影,模糊的距离,以及阴影的颜色。
- box-sizing: content-box|border-box 盒模型
- 媒体查询 @media screen and (max-width: 960px) {}还有打印print
动画和过渡
animation / keyframes
- animation-name: 动画名称,对应@keyframes
- animation-duration: 间隔
- animation-timing-function: 曲线
- animation-delay: 延迟
- animation-iteration-count: 次数
- infinite: 循环动画
- animation-direction: 方向
- alternate: 反向播放
- animation-fill-mode: 静止模式
- forwards: 停止时,保留最后一帧
- backwards: 停止时,回到第一帧
- both: 同时运用 forwards / backwards
- 常用钩子: animationend
transform
- 位移属性 translate( x , y )
- 旋转属性 rotate()
- 缩放属性 scale()
- 倾斜属性 skew()
transition
- transition-property(过渡的属性的名称)。
- transition-duration(定义过渡效果花费的时间,默认是 0)。
- transition-timing-function:linear(匀速) ease(慢速开始,然后变快,然后慢速结束)(规定过渡效果的时间曲线,最常用的是这两个)。
- transition-delay(规定过渡效果何时开始。默认是 0)
隐藏元素
opacity:0
:本质上是将元素的透明度将为0,就看起来隐藏了,但是依然占据空间且可以交互visibility:hidden
: 与上一个方法类似的效果,占据空间,但是不可以交互了overflow:hidden
: 这个只隐藏元素溢出的部分,但是占据空间且不可交互display:none
: 这个是彻底隐藏了元素,元素从文档流中消失,既不占据空间也不交互,也不影响布局z-index:-9999
: 原理是将层级放到底部,这样就被覆盖了,看起来隐藏了transform: scale(0,0)
: 平面变换,将元素缩放为0,但是依然占据空间,但不可交互
em/px/rem
- px:绝对单位,页面按精确像素展示。
- em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px),整个页面内1em不是一个固定的值。
- rem:相对单位,可理解为”root em”, 相对根节点html的字体大小来计算,CSS3新加属性,chrome/firefox/IE9+支持
Flex布局
Flex是Flexible Box的缩写,意味"弹性布局",任何一个容器都可以指定为Flex布局。Flex布局元素,称为Flex容器,简称"容器"。容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的排列方式:从左到右;交叉轴的排列方式:从上到下
容器的属性
- flex-direction
- flex-wrap
- flex-flow
- justify-content
- align-items
- align-content
- flex-direction 属性决定主轴的方向 (即项目的排列方式)
父元素属性
用来定义一个 flex 容器。如果设置为 flex 则容器呈现为块状元素,设置为inline-flex 则容器呈现为行内元素。它为所有直接子元素提供了 flex 上下文
1 | .container { |
1. flex-direction 建立了主轴,置在水平行或垂直列中
1 | .container { |
row
(默认值) :行排布。在 ltr (left to right, 从左到右)排版方式下,flex 项从左到右排列,在 rtl (right to left, 从右到左)排版方式下,flex 项从右到左排列。row-reverse
: 反向行排布,即 row 的反方向,在 ltr 中从右向左,在 rtl 中从左到右。column
: 列排布,与 row 相似,但是 flex 项从上到下排布。column-reverse
: 反向列排布,即 column 反方向,与 row-reverse 相似,只是 flex 项从上到下排布。
2. flex-wrap 排在同一行上(行或列)
1 | .container { |
nowrap
(默认值) : 所有的 flex 项都会在同一行上排布,也就是我们常说的单行,或不换行。wrap
: flex 项将从上到下根据实际情况排布再多行上,也就是我们常说的多行,或会换行。wrap-reverse
: flex 项将 从下到上 根据实际情况排布再多行上折行。
3. flex-flow (适用于父级 flex 容器)
这是flex-direction
和flex-wrap
属性的缩写形式。同时定义 flex 容器的主轴和交叉轴。默认是 row nowrap。
1 | flex-flow: <flex-direction> || <flex-wrap> |
4. justify-content 主轴方向的对齐方式
1 | .container { |
flex-start
(默认值) : flex 项从主轴的开始位置(main-start)开始排布。flex-end
: flex 项从主轴的结束位置(main-end)开始排布center: flex
项沿主轴居中排布。space-between
: flex 项沿主轴均匀排布,即我们常说的沿主轴 两端对齐 ,第一个flex 项在主轴开始位置,最后一个flex 项在主轴结束位置。space-around
: flex 项沿主轴均匀排布。要注意的是 flex 项看起来间隙是不均匀的,因为所有 flex 项两边的空间是相等的。第一项在容器边缘有一个单位的空间,但是在两个 flex 项之间有两个单位的间隙,因为每个 flex 项的两侧都有一个单位的间隙。space-evenly
: 任何两个 flex 项之间的间距(以及到 flex 容器边缘的空间)相等。(注:该属性以前很少看到,原因是以前浏览器不支持,chrome 也是 60 版本之后才支持。延伸一下,align-content: space-evenly 也是这个逻辑,大家可以查看下面的demo。 )
5. align-items 交叉轴(垂直于主轴)对齐方式
1 | .container { |
flex-start
: flex 项按照交叉轴的开始位置(cross-start)对齐。flex-end
: flex 项按照交叉轴的结束位置(cross-end)对齐。center
: flex 项以交叉轴为中心,居中对齐。baseline
: flex 项按照他们的文字基线对齐。stretch
(默认值) : 拉伸 flex 项以填充整个容器(这里特别要注意:如果 flex 项有尺寸属性(min-width / max-width / width / min-height / max-height / height),那么首先应用这些尺寸属性。例如下面的示例:)
6. align-content 交叉轴(垂直于主轴)分配剩余空间[注意:当只有一行 flex 项时,此属性不起作用]
1 | .container { |
flex-start
:多行在容器的开始位置排布flex-end
:多行在容器的结束位置排布center
:多行在容器的总结位置排布space-between
:多行均匀分布;第一行分布在容器的开始位置,最后一行分布在容器的结束位置space-around
: 多行均匀分布,并且每行的间距(包括离容器边缘的间距)相同;strech
(默认值):多行拉伸以填充满整个剩余空间
flex 项属性 (flex items)
1. align-self 单独的 flex 项覆交叉轴上的对齐方式(注:float,clear和vertical-align 对 flex 项没有任何作用。)
1 | .item { |
2. order 容器中的显示顺序
1 | .item { |
3. flex-grow 可用剩余空间时拉伸比例
1 | .item { |
4. flex-shrink 项的收缩的能力(注:与
flex-grow拉伸正好相反,
flex-shrink决定 flex 项允许收缩多少比例。负值对于
flex-shrink无效)
1 | .item { |
5. flex-basisflex-basis
定义了在分配剩余空间之前 flex
项默认的大小。可以设置为某个长度值(e.g. 20%, 5rem,等)或者关键字。关键字 auto
意味着 flex
项会按照其本来的大小显示(暂时由 main-size
关键字完成,直到弃用)。关键字 content
意味着根据内容来确定大小——这个关键字到目前没有被很好地支持,所以测试起来比较困难,与content
的类似的关键字还有max-content
, min-content
, fit-content
。
1 | .item { |
6. flex
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
1 | .item { |
伪类
LVHA
a标签有四种状态:链接访问前、链接访问后、鼠标滑过、激活,分别对应四种伪类:link、:visited、:hover、:active;
当链接未访问过时:
- 当鼠标滑过a链接时,满足:link和:hover两种状态,要改变a标签的颜色,就必须将:hover伪类在:link伪 类后面声明;
- 当鼠标点击激活a链接时,同时满足:link、:hover、:active三种状态,要显示a标签激活时的样式(:active), 必须将:active声明放到:link和:hover之后。因此得出LVHA这个顺序。
- 当链接访问过时,情况基本同上,只不过需要将:link换成:visited。
伪类和伪元素
css引入伪类和伪元素概念是为了格式化文档树以外的信息。也就是说,伪类和伪元素都是用来修饰不在文档树中的部分
1. 伪类
伪类存在的意义是为了通过选择器找到那些不存在DOM树中的信息以及不能被常规CSS选择器获取到的信息
- 获取不存在与DOM树中的信息。比如a标签的:link、visited等,这些信息不存在与DOM树结构中,只能通过CSS选择器来获取;
- 获取不能被常规CSS选择器获取的信息。比如:要获取第一个子元素,我们无法用常规的CSS选择器获取,但可以通过 :first-child 来获取到。
2. 伪元素
伪元素用于创建一些不在文档树中的元素,并为其添加样式。比如说,我们可以通过:before来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。常见的伪元素有:::before,::after,::first-line,::first-letter,::selection、::placeholder等
因此,伪类与伪元素的区别在于:有没有创建一个文档树之外的元素
3. ::after和:after的区别
- 在实际的开发工作中,我们会看到有人把伪元素写成:after,这实际是 CSS2 与CSS3新旧标准的规定不同而导致的。
- CSS2 中的伪元素使用1个冒号,在 CSS3 中,为了区分伪类和伪元素,规定伪元素使用2个冒号。所以,对于 CSS2 标准的老伪元素,比如:first-line,:first-letter,:before,:after,写一个冒号浏览器也能识别,但对于 CSS3 标准的新伪元素,比如::selection,就必须写2个冒号了
4. CSS3新增伪类 p:first-of-type
选择属于其父元素的首个<p>
元素的每个<p>
元素。p:last-of-type
选择属于其父元素的最后<p>
元素的每个<p>
元素。p:only-of-type
选择属于其父元素唯一的<p>
元素的每个<p>
元素。p:only-child
选择属于其父元素的唯一子元素的每个<p>
元素。p:nth-child(2)
选择属于其父元素的第二个子元素的每个<p>
元素。:after
在元素之前添加内容,也可以用来做清除浮动。:before
在元素之后添加内容:enabled
:disabled
控制表单控件的禁用状态。:checked
单选框或复选框被选中
calc函数
calc函数是css3新增的功能,可以使用calc()计算border、margin、pading、font-size和width等属性设置动态值
1 | #div { |
注意点:
- 需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% - 10px);
- calc()函数支持 “+”, “-”, “*”, “/” 运算;
- 对于不支持 calc()的浏览器,整个属性值表达式将被忽略。不过我们可以对那些不支持calc()的浏览器,使用一个固定值作为回退。
CSS加载
根据页面渲染流程可得知:
- css加载不会阻塞DOM树的解析;
- css加载会阻塞DOM树的渲染;
- css加载会阻塞后面js语句的执行
文字单超出显示省略号
1 | div { |
滤镜
页面变灰
1 | body { |
继承属性
可继承的只有:颜色、文字、字体间距、行高对齐方式,列表样式
所有元素可继承:visibility
和cursor
- 内联元素可继承:
- letter-spacing
- word-spacing
- white-space
- line-height
- color
- font
- font-family
- font-size
- font-style
- font-variant
- font-weight
- text-decoration
- text-transform
- direction
- 块状:
text-indent
和text-align
。 - 列表元素可继承:
list-style
、list-style-type
、list-style-position
、list-style-image
文档流
将窗体自上而下分成一行一行,并在每行中按从左至右的挨次排放元素。
inline-block
使用场景
- 要设置某些子元素在一行或者多行内显示,尤其是排列方向一致的情况下,应尽量用inline-block。
- 希望若干个元素平行排列,且在父元素中居中排列,此时可以用inline-block,且给父元素设text-align: center。
- inline-block可以用一排a {display: inline-block}实现横向导航栏,无论是居左的导航栏还是居右的都适用。
对于第一种和第三种情况虽然都可以使用float来实现,不过inline-block会比它好一些,原因如下:
- 浮动会脱离文档流,导致父元素高度塌陷
回流重绘
回流:
触发条件:当我们对 DOM 结构的修改引发 DOM 几何尺寸变化的时候,会发生回流的过程。
触发回流:
- 一个 DOM 元素的几何属性变化,常见的几何属性有width、height、padding、margin、left、top、border 等等, 这个很好理解。
- 使 DOM 节点发生增减或者移动。
- 读写 offset族、scroll族和client族属性的时候,浏览器为了获取这些值,需要进行回流操作。
- 调用 window.getComputedStyle 方法。
重绘:
触发条件:
- 当 DOM 的修改导致了样式的变化,并且没有影响几何属性的时候,会导致重绘(repaint)。
- 重绘过程:由于没有导致 DOM 几何属性的变化,因此元素的位置信息不需要更新,所以当发生重绘的时候,会跳过生存布局树和建立图层树的阶段,直接到生成绘制列表,然后继续进行分块、生成位图等后面一系列操作。
避免触发回流和重绘:
- 避免频繁使用 style,而是采用修改class的方式。
- 将动画效果应用到position属性为absolute或fixed的元素上。
- 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘
- 使用createDocumentFragment进行批量的 DOM 操作。
- 对于 resize、scroll 等进行防抖/节流处理。
- 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 利用 CSS3 的transform、opacity、filter这些属性可以实现合成的效果,也就是CPU加速。
GPU加速
在合成的情况下,会直接跳过布局和绘制流程,直接进入非主线程处理的部分,即直接交给合成线程处理。交给它处理有两大好处:
- 能够充分发挥GPU的优势。合成线程生成位图的过程中会调用线程池,并在其中使用GPU进行加速生成,而 GPU 是擅长处理位图数据的。
- 没有占用主线程的资源,即使主线程卡住了,效果依然能够流畅地展示。
will-change
will-change
是CSS3
新增的标准属性,它的作用很单纯,就是"增强页面渲染性能",当我们在通过某些行为触发页面进行大面积绘制的时候,浏览器往往是没有准备,只能被动的使用CUP去计算和重绘,由于事先没有准备,对于一些复杂的渲染可能会出现掉帧、卡顿等情况。而will-change
则是在真正的行为触发之前告诉浏览器可能要进行重绘了,相当于浏览器把CUP拉上了,能从容的面对接下来的变形。
常用的语法主要有:
whil-change
:scroll-position
; 即将开始滚动will-change
:contents
; 内容要动画或者变化了will-transform
;transform
相关的属性要变化了(常用)
注意:
will-change
虽然可以开启加速,但是一定要适度使用- 开启加速的代价为手机的耗电量会增加
- 使用时遵循最小化影响原则,可以对伪元素开启加速,独立渲染
- 可以写在伪类中,例如hover中,这样移出元素的时候就会自动remove掉
will-change
了 - 如果使用JS添加了
will-change
,注意要及时remove掉,方式就是style.willChange = ‘auto’
CSS单位
比较常用的:
em
:定义字体大小时以父级的字体大小为基准;定义长度单位时以当前字体大小为基准。例父级font-size: 14px
,则子级font-size: 1em
;为font-size: 14px
;;若定义长度时,子级的字体大小如果为14px
,则子级width: 2em
;为width: 24px
。rem
:以根元素的字体大小为基准。例如html的font-size: 14px
,则子级1rem = 14px
。
%:以父级的宽度为基准。例父级width: 200px
,则子级width: 50%
;height:50%
;为width: 100px
;height: 100px
;vw
和vh
:基于视口的宽度和高度(视口不包括浏览器的地址栏工具栏和状态栏)。例如视口宽度为1000px
,则60vw = 600px
;vmin
和vmax
:vmin为当前vw 和vh中较小的一个值;vmax为较大的一个值。例如视口宽度375px
,视口高度812px
,则100vmin = 375px
;,100vmax = 812px
;
不常用的:ex
和ch
:ex
以字符"x"的高度为基准;例如1ex
表示和字符"x"一样长。ch以数字"0"的宽度为基准;例如2ch表示和2个数字"0"一样长。
移动端布局总结:- 移动端布局的方式主要使用rem和flex,可以结合各自的优点,比如flex布局很灵活,但是字体的大小不好控制,我们可以使用rem和媒体查询控制字体的大小,媒体查询视口的大小,然后不同的上视口大小下设置设置html的font-size。
- 可单独制作移动端页面也可响应式pc端移动端共用一个页面。没有好坏,视情况而定,因势利导
移动端
一个简易版的初始化根元素字体大小。页面开头处引入下面这段代码,用于动态计算font-size:(假设你需要的1rem = 20px)
1 | (function () { |
document.documentElement
:获取document的根元素html.getBoundingClientRect().width
:获取html的宽度(窗口的宽度)- 监听
window
的resize
事件
一般还需要配合一个meta头:
1 | <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-sacle=1.0, maximum-scale=1.0, user-scalable=no" /> |
如果没有人为取改变根元素字体大小的话,默认是1rem = 16px;根元素默认的字体大小是16px。
编程题
- 画一条 0.5px 的线
- 采用 meta viewport 的方式
1
2<!-- 缩放到原来的0.5倍,如果是1px那么就会变成0.5px -->
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5" /> - 采用 border-image 的方式
1
2
3
4
5
6
7
8
9
10.border-id5 {
content: '',
position: absolute;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 1px;
background-images: linear-gradient(0deg, #808080, transparent 50%)
} - 采用 transform: scale() 的方式
1
transform: scale(.5, .5);
- 采用 meta viewport 的方式
- 画一个三角形 (三角形原理:边框的均分原理)
1 | div { |
- 圆/半圆/椭圆
1 | .round1 { /* 圆 */ |