概述
css相关的知识点很多,可以参考这篇,本文主要选择部分比较常见的做一下梳理,顺序参考css2.2。
长度单位
又分为相对长度单位和绝对长度单位。
相对长度
相对长度单位分为相对字体的长度
- em 当前元素计算值的倍数
- ex 当前元素x的高度
- ch 当前元素数字0的高度或宽度,一般是0的宽度,即0.5em
- rem 根元素(在html文档中是html元素)font-size属性计算值的倍数
相对视口长度单位
- vw
- vh
- vmin和vmax
vw和rem
rem和vw实现的思路类似,都是一个基准值的比例,但后者是浏览器是原生支持的,前者需要设置对应的html font-size。
保持元素宽高比
- 对于一种图片这种自带宽高比的,或者通过aspect-ratio设置的宽高比,宽和高设置一个,另一个auto即可
- 设置高度单位vw
- 第三种是设置::before和::after的padding为百分比,这两个伪元素会生成当前元素的第一个和最后一个子元素,百分比基数是包含块(即当前元素)的宽度。
//设置一个带有padding-top且宽度为0的子元素撑起父元素的高度
.aspect-ratio-box::before {
float: left;
padding-top: calc(9 / 16 * 100%);
content: '';//为空所以宽度为0
}
//清浮动,为了满足其左右两边没有浮动元素的这个条件,只能自身下移,从而带动了父元素高度的撑开。
.aspect-ratio-box::after {
display: block;
content: '';
clear: both;
}
.aspect-ratio-box {
max-width: 500px;
background: red;
}
绝对长度
绝对长度大部分不是用于显示器的,这里只提一下px。
不太重要的历史
起初像素和其他物理单位的换算并不固定,物理单位以实际测量尺寸为准,像素会不断变化以匹配reference pixel,后者指的是一个96dpi的设备的1px距离一胳膊的距离时的视角,一个胳膊长度通常71cm,这个视角也就是大约0.0213度。因此当距离为1胳膊时1px为为1/96 inch,其他距离时1px对应其他长度。
但是由于历史原因,大量内容中的px是基于1胳膊的距离与96dpi的假设换算的,因此就把这种换算固定了下来,即
1in = 96px
dpi和ppi
dpi和ppi两个比较类似的概念,分别表示打印设备和屏幕设备最小显示单位的密度,ppi也可以用来表示数码图片或视频的像素密度。
- dpi,即dots per inch ,每英寸墨点的数量
- ppi,即 pixels per inch,每英寸像素的数量
我们平时说的屏幕分辨率指的是总的像素数,1080p的屏幕通常有1920*1080个像素,也是屏幕可以调整的最大分辨率。如果硬件不变,调小分辨率,画面被放大。
设备像素和css像素
ppi中的像素指的是设备像素,是设备的属性,css像素是我们通过代码指定的像素,window.devicePixelRatio可以获得当前设备每个css像素可以由几个设备像素组成。
因此理论上我们可以在dpr大于1的情况下设置小于1px的长度,也就是1px边框问题。
1px边框问题
具体解决方式可以参考这篇。
思路包括
- 利用伪元素模拟边框,然后scale放大两倍后再缩小2倍,放大时边框宽度不变。
- 动态viewport,通过修改缩放比例为1/dpr,可以将viewport宽度放大dpr倍,例如一个宽度375px,dpr为2的屏幕放大后宽度是750px,但屏幕实际的宽度不变,因此一个css像素就相当于一个设备像素。
函数符号
这里只介绍两种,calc()都很熟了,attr()用法为
//css
p:before {
content:attr(data-foo);
}
//html
<p data-foo="hello">world</p>
选择器
选择器是一种模式匹配规则,决定当前样式应用到dom树中的哪些元素。
选择器分为一下几种
简单选择器
- 类型选择器,比如div
- 通用选择器 *
- 属性选择器,比如[attr]表示有attr属性的元素
- class选择器 .className
- id选择器 #id
伪类
用来指定元素的特定状态,由冒号(:)+伪类名组成
- 动态伪类
- 链接伪类,比如:link
- user action伪类,比如:focus
- target伪类,:target,点击锚点表示的链接时匹配到的元素(锚点匹配对应id)
- 语言伪类, :lang(C)相当于属性选择器的[lang|=C]
- ui状态伪类
- :enabled和:disabled
- :checked
- 结构伪类,比哦如表示第几个子元素,第几个牟总类型的元素,或取非
伪元素
用来指定选择元素的一部分,由两个冒号(::)+伪元素名组成。
- ::first-line 第一行,用于block-level element
- ::first-letter 第一个字母,也是应用于block-level element
- ::before和::after 用于在元素内生成第一个和最后一个子元素
组合
- 后代 E F
- 父子 E > F
- 兄弟,包括math + p 下一个兄弟,h1 ~ pre后面的所有兄弟
权重
计算权重如下
- 将id选择器记为a
- 将class选择器、属性选择器和伪类选择器记为b
- 将类型选择器和伪元素记为c
- 忽略通用选择器
然后将三个数字按照a-b-c组合成一个数字计算权重
其中not不被计入权重
元素属性值的处理过程
当用户代理解析并构建dom树时需要对其中的每个元素的每个属性赋值,以提供给最后的显示。
这个过程一共分为6步
Filtering
第一步是收集,首先找到所有应用到每个元素的声明,因为每个元素的某个属性可能会声明0次或多次,因此,每个元素的每个属性会有一个declared values列表
Cascading
第二步处理那些不为空的列表,并根据优先级最终选择出一个cascaded value。
优先级规则分为三类,这三类依次排序
第一类按照声明的来源和是否带有!important,降序如下
- Transition declarations
- Important user agent declarations
- Important user declarations
- Important author declarations
- Animation declarations
- Normal author declarations
- Normal user declarations
- Normal user agent declarations
第二类是权重,其中行内样式最高,其他按照选择器权重排序
第三类是按出现的顺序,后出现的为准。
Defaulting
前面两步后,每个声明过的样式会有一个值,第三步处理后为每个元素的每个属性都会保证有一个specified value。
这里可分为显式和隐式两种情况
显式处理时可以对一个属性赋值以下关键字
- initial 初始值,css spec会给每个属性指定一个初始值
- inherit 继承父级样式的computed value
- unset 如果对应的是一个可继承属性,则为inherit,否则为initial,用于清除声明值
如果没有显式处理,则首先对可继承属性继承父级的计算值,其中根元素的继承值是initial值。
如果是不可继承属性则为initial。
Computing
这一步将每个specified value绝对化为一个Computed Values,包括
- 将相对长度与参考值相乘
- 特定的keywords,比如small要根据定义算出结果
- 百分比
- 相对路径
Using
这一步继续绝对化上一步无法处理的属性,比如width:auto
需要经过上一步计算出祖先元素的值。
这步会生成一个used value,如果某个属性没有应用到元素上,则不会有used value,比如一个非flex布局的元素,没有flex used value。
Adjusting
上一步生成的value原则上可以用了,但是用户代理可能会进一步处理,比如对于不支持小数点长度的浏览器会进行取整。
例子
以上就是完整的六步,案例可以参考这里
媒体查询
媒体查询是一个测试方法,根据指定的媒体类型和媒体特征来判断当前设备是否适用对应样式。
如果匹配到多个样式,会被上一节的Cascade处理。
应用场景
媒体查询可以用在
- 样式表中某个或几个具体样式
- @import或link元素引入样式表
具体语法
媒体查询的语法可以理解为一个返回boolean的表达式,多个单独的表达式可以通过组合形成最终的表达式。
判断的依据是指定的媒体类型和媒体特性和当前使用的设备是否匹配。
媒体类型包括all,print,screen三种。
媒体特性用来更细的验证一个设备的各种特性,比如视口的宽高值是某个值或某个范围。
连接符优先级从高到低是
- and 与
- not 非
- , 或
only用于兼容,很少使用
例子
在第一个场景使用是,以@media开头,比如
@media (400px <= width <= 700px) { … }
在视口为指定范围时才应用对应样式
第二个场景
@import "print-styles.css" print;
<link media="screen and (color), projection and (color)"
rel="stylesheet" href="example.css">
只有符合条件才引入对应样式表
盒模型
box model用来描述元素在文档中生成的矩形盒子。
padding和margin
padding不可为负。
margin可以为负,且行内非可替换元素的上下margin无效。
Collapsing margins
css中两个或多个boxs(可以是同级也可以不是)的相邻margin可以合并成一个margin,这个被称作collapse,合并后的margin被称为collapsed margin。
当两个或多个margin折叠时,最终的margin宽度是折叠的margin中最大的一个;如果是有负margin则是最大正margin减去最大负margin绝对值的宽度;如果没有正的margin则从0中减去绝对值最大的margin。
为什么会折叠
关于这个问题在css1的Section 4.1.1提过,即通过折叠垂直方向的margin可以视觉上更好,且更符合设计的预期。在css1发布时的1996年,网站大部分主要是一块块文本,如果不存在margin折叠,以下文档会不齐
headings, with margin: 10px paragraphs, with margin: 5px figures, with margin: 10px
两个相邻盒子合并的条件
- 都是参与同一个bfc的in-flow块级盒子
- 没有行内盒子、clearance、paading或border讲它们分开
- 两个都属于垂直相邻的盒子,比如以下的情况
- 一个盒子的上margin和第一个流内子元素的上margin
- 一个盒子的下margin和下一个流内的相邻元素的上margin
- 一个margin为auto的元素的下margin和流内最后一个子元素的下margin
- 一个没有建立起新的bfc的盒子的上margin和下margin,并且这个盒子有一个min-height的0计算值,或height为auto或没有流内元素
如果阻止合并,只需要破坏以上条件即可。
box-sizing
用来指定length等作用域content-box还是border-box,默认content-box
视觉格式化模型
在visual formatting model中,每个元素都会都会按照box model生成0个或多个boxs
这一节细节很多,只讲几个常见概念。
formatting context
格式化上下文是一组盒子用来布局的环境,常见的包括bfc和ifc。
bfc
以下几种情况会为他们的内容生成新的bfc
- 浮动元素
- absolutely positioned elements,即position属性为'absolute' or 'fixed'
- 非块盒的块容器盒(比如inline-blocks, table-cells)
- overflow属性不是visible的块盒(除非这个值已经传递到viewport)
另外还有根元素,也可以使用display:flow-root创建bfc
在一个bfc中,盒子从containing block的上面一个一个的垂直排列(其中的行内元素会组成匿名块盒子),两个盒子之间的垂直距离取决于margin属性,
应用:
- 清浮动
- 避免margin折叠
ifc
一个不包含块级盒子的块容器盒子创建一个ifc(inline formatting context),在一个ifc中盒子从容器盒嘴上面一个接一个平行放置,这些盒子在垂直方向可能以不同方式对齐。
浮动
在一个float model,一个盒子首先要根据normal flow布局,然后脱离文档流,然后尽可能向左或右移动。
浮动元素的父元素中的其他内容会被放置在浮动元素后面,比如使文字环绕浮动元素。
浮动元素后面的块级元素(inline或inline-block无效)可以设置clear,避免和浮动元素在同一行。
父元素塌陷
因为脱离了文档流,如果父元素高度不如浮动子元素,就会出现塌陷的情况,这也是清浮动问题。
这时候有两个解决方式
- 第一个是在浮动元素后面添加一个块级子元素(比如使用::after伪元素),并设置clear:both,撑起父元素
- 第二个是使父元素创建bfc,bfc会将浮动子元素计入高度
position
position属性确定定位方案
- static 默认值,按照normal flow布局,四个方向属性没用
- relative 相对于normal flow来计算,相对于normal position计算位置
- absolute 相对于containing block布局。
- fixed 相对于containing block布局。
- sticky 会根据最近的可滚动(overflow不是visible)祖先定位,使用四个方向进行偏移。
自定义属性
:root {
--main-color: #06c;
--accent-color: #006;
}
/* The rest of the CSS file */
#foo h1 {
color: var(--main-color);
}
Flexible Box
flex布局是一个一维的布局,其中包含一个主轴(main),flex item沿主轴排列,并弹性填充主轴位置。
与主轴垂直的轴被称为cross
flex item有几个要注意的
- 绝对定位的子元素不参与flex layout,这里就不考虑用了
- flex item的margin不合并
- 即使position为static,z-index也有效
- float和vertical-align无效
顺序和方向
在flex元素上
- flex-direction 按行排序还是列排序,正序还是倒序
- flex-wrap 是否可换行,当wrap-reverse时和wrap正好相反,第一行变最后一行,每行反向。
- flex-flow <‘flex-direction’> || <‘flex-wrap’>
在子元素 order 取值整数,默认0,越小越靠前
弹性
即flex属性,用于flex-item,使其弹性填充容器主轴,建议使用缩写,因为会正确重置以满足一些常见使用
缩写
可取值 none | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’> ]
- flex-grow 指定对应item怎么伸展以分配空闲空间,省略时设为1
- flex-shrink 当item总宽超过父元素宽度时,指定对应item怎么压缩,省略时设为1
- flex-basis 决定怎么分配初始宽度,省略时设为0,即主轴所有控件都是空闲空间
- auto 会获取main size(即main 轴方向的尺寸)作为该属性值,如果后者也为auto,则取值content
- content
- <‘width’>
- none 即0 0 auto
几种常见的取值
- initial,相当于不指定,等效于0 1 auto,初始值,默认压缩但不伸展
- auto,等效于1 1 auto,会根据剩余空间伸缩
- none 等效于0 0 auto,完全没弹性
- 等效于positive-number 1 0,按比例分配剩余空间
对齐
不同对齐的图示看这里
Aligning with auto margins
如果主轴还有剩余空间,margin-left:auto会被分配所有空间
main轴的对齐
justify-content
- flex-start 默认
- flex-end
- center
- space-around 端点边的距离是元素之间距离的一半
- space-between 端点贴边,每个中间距离一样
- space-evenly 端点边和元素之间距离一样
cross轴的对齐
align-items
- flex-start 默认
- flex-end
- center
- baseline
- stretch 拉伸
align-self 比前一个多一个
- auto 默认,由align-items决定
主轴多行时,cross方向的对齐
align-content
- flex-start
- flex-end
- center
- space-between
- space-around
- stretch
在cross方向不能充满时的所有行作为整体的对齐,类似于使用justify-content在主轴方向的对齐
Grid Layout
flex布局只能在主轴一个方向弹,grid在两个方向实现了弹性布局,水平方向的轴叫inline,垂直方向叫block。
上一节谈到的item需要注意的方面在这里同样适用。当使用margin时是指的item在对应方格内的外边框,对方格没影响。
定义方格
方格的定义分为显式和隐式两种。
显式定义会明确对对应的行和列指定宽度
- grid-template-rows 方格每行的宽度
- grid-template-columns 方格每列的宽度
- grid-template-areas为行和列交错成的方块和边线命名
- grid-template 是以上三个属性的简写
如果还有一些方格没显式定义,则需要隐式定义
- grid-auto-rows
- grid-auto-columns
还有个类似flex-direction的属性
-
grid-auto-flow 可取值 [ row | column ] || dense
-
grid 是以上属性的简写
放置grid item
前面定义好了一个个格子,现在把grid container中的元素放置进去。
用来表示被放置位置的方式可以是命名area,也可以是四个起始线围成的区域,也可以指定起始线和跨行数。
单独指定每条线
- grid-row-start
- grid-column-start
- grid-row-end
- grid-column-end
线的简写
- grid-row
- grid-column
指定区域
- grid-area 可以是命名的区域,也可以是斜线分割的四条线grid-row-start, grid-column-start, grid-row-end and grid-column-end
gap
每个item之间可以指定间隔
- row-gap
- column-gap
- gap
对齐
以下参考这里
grid布局比flex布局的对齐粒度更细。
flex布局提供了flex内容整体的,main轴对齐justify-content,cross轴对齐align-content,和主轴范围内每个item的cross方向的对齐align-items以及对应的单个item的align-self
在此基础上,grid布局还提供了整体的inline方向的对齐justify-items和对应的单个item的justify-self
transition
一般当元素的属性发生改变会立刻更新,过渡使属性在一个特定的duration发生改变。
缩写为[ none | ] || <time> || || <time>
分别对应
- transition-property 指定应用过渡的css属性,可以取值all、none、或逗号分隔的各个属性值,默认all
- transition-duration 带单位的过渡时间,默认0
- transition-timing-function 过渡期间的值怎么计算,用于修改过渡期间的速度
- transition-delay 延迟的时间,带单位,默认0
比如
.test{
height: 100px;
width: 100px;
background-color: pink;
transition;2s;
}
.test:hover{
width: 500px;
}
Animations
通过关键帧讲css的属性值产生动画,这些关键帧持续时间、重复次数或重复行为可以进行控制
缩写为<time> || || <time> || || || || || [ none | ]
分别对应
- animation-duration 动画时长,带单位,默认0s
- animation-timing-function
- animation-delay
- animation-iteration-count 动画运行次数,默认1
- animation-direction 是否反向播放
- normal 每次都是正向
- alternate 正反交替
- reverse
- alternate-reverse
- animation-fill-mode 在执行之前和之后如何将样式应用于其目标
- none 动画未执行时,动画不会修改元素样式
- forwards 动画结束后,将保留最后一帧
- backwards 在动画delay期间,动画将应用首帧
- both 同时应用上面两个属性
- single-animation-play-state 一个动画是否运行或者暂停
- running 正在运行
- paused 已被停止
- keyframes-name 应用的动画,由@keyframes定义
@keyframes <keyframes-name> { <keyframe-block-list>}
其中的时间点可以取值百分数,from,to,其中from代表0,to代表100%
比如
@keyframes slidein {
from {
transform: translateX(0%);
}
to {
transform: translateX(100%);
}
}
transform
转换,下为y轴正方向,右为x轴正方向
- transform-box 所有的变换都是相对于这个属性代表的reference box来进行的,在非svg的环境里只需要关心border-box和content-box
- transform-origin 指定变换的坐标系原点,其中0 0代表reference box的左上角,默认值50% 50%
transform可取值 none | 其中是逗号分隔的转换函数,比如
- translate() 移动位置
- scale() 缩放
- rotate() 旋转
- skew() 倾斜
CSSOM
这里指的是css有关的浏览器提供的api,参考这里
window上扩展的api
screen
屏幕有关的信息,挂载到screen上
- availWidth
- availHeight
- width
- height
- colorDepth
- pixelDepth
browsing context
移动和缩放浏览上下文,直接挂载到window上
- moveTo(long x, long y);
- moveBy(long x, long y);
- resizeTo(long width, long height);
- resizeBy(long x, long y);
viewport
视口的宽高,挂载到windos上
- innerWidth
- innerHeight
viewport scrolling
滚动相关,挂载在window上
- scrollX/scrollY 返回相对于视图滚动的像素值
- pageXOffset/pageYOffset 相当于第一项
- scroll(x-coord, y-coord)/scroll(options) 滚动到指定位置
- scrollTo
- scrollBy
client
client窗口有关的,挂载到window上
- screenX/screenY 窗口相对于屏幕的坐标
- screenLeft/screenRight
- outerWidth/outerHight
- devicePixelRatio
Document
挂载到document上的
- elementFromPoint(double x, double y) 返回指定坐标最前面的元素
- elementsFromPoint(double x, double y) 指定坐标的元素数组
- caretPositionFromPoint(double x, double y) 返回一个CaretPosition对象
- scrollingElement 返回滚动文档元素的引用,通常是html元素
Element接口上的
- getClientRects() 返回一个DOMRect对象的集合,DOMRect对象表示每个css border box的bounding rectangles,大部分元素各含有一个border box each,但是多行的行内元素每行都有一个。
DOMRect对象表示矩形的尺寸和位置,包含属性
- x/y 左上角坐标
- width
- height
- top 如果height是负的为y+height,否则和y一样
- bottom 如果height是负的为y,否则为y+height
- right 如果height是负的为x,负责为x+width
- left 如果height是负的,为x+width.否则为x
- getBoundingClientRect() 返回一个对应的DOMRect对象
- scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg = {}); 滚动至可见
- scroll();
- scrollTo()
- scrollBy()
- scrollTop/scrollLeft 卷起来的内容顶部到可见内容的距离
- scrollWidth/scrollHeight; 包含被滚动部分的宽高
- clientTop/clientLeft
- clientWidth/clientHeight
HTMLElement接口上的扩展
- offsetParent
- offsetTop/offsetLeft
- offsetWidth/offsetHeight
MouseEvent上的接口
当前鼠标的位置
- screenX/screenY 相对于屏幕的坐标
- pageX/pageY 相对于文档的坐标
- clientX/clientY 相对于视口的坐标
- x/y 等效于clientX/clientY
- offsetX/offsetY 相对于target元素padding edge的坐标