css全面复习之道

267 阅读21分钟

正言:刚开始我以为css不过如此,什么bfc、层叠上下文,浮动,定位,外加个flex 就够了。如果你也是这样的心态,请听题

打击提问

  1. 行内元素与行内块元素有什么区别? <div><span>xxxxxxxxxx</span>x</div>假设span中的文字占据一行半的空间,如果此时给span设置display为inline-block,布局会有改变吗?

  2. 行内元素的高度受什么控制?行内元素垂直方向的padding、margin有用吗?

  3. 等高布局实现方式?如下代码中,左右list中的内容高度是不确定的,左右两个list需要有不同的背景色,如何使左右两个list看起来高度一致?

<div>
   <div class="left-list">
      内容...
   </div>
   <div class="right-list">
     内容...
   </div>
</div>
  1. 行内元素、行内块元素(分有无文字两种情况)、替换元素的基线在什么位置?
  • line-height可以设置什么样的值?line-height设置不同类型值继承表现如何?如果div中有一行文字,div行高50px,那么div高度多少?添加条件,如果文字外有span标签,那么div高度多少?再添加条件,如果span的行高30px,那么div高度多少?再添加条件,如果span中有两行文字,那么div高度多少?
  1. 幽灵空白节点如何产生的?

  2. 在不设置宽度的前提下,元素什么时候会自动撑满父元素?元素什么情况下由内容撑开?

  3. 元素只设置设置position:absolute;有什么效果?父元素为行内元素、块级元素有区别吗?

  4. 元素背景可以由多个图片/渐变构成吗?如果可以,那么怎么写,书写排序的表现如何?

  5. +、~选择器的场景?:nth-child(n)和:nth-of-type(n)有什么区别?

  6. box-shadow的使用方式?创建阴影的原理步骤?如何做出只有单侧有模糊阴影效果?

  7. css函数 blur是模糊元素的,那它有啥缺点吗?

css的历史悠久,相关的知识也是非常多,下面正式开始正文。

浏览器渲染流水线流程

  1. html字节内容转成字符串,拆分成token,根据拆分出的token提取出标签,生成dom
  2. 样式表cssStylesheet,类似于dom树生成过程
  3. domTree + cssStylesheet 得到需要渲染的内容渲染树
  4. 然后,根据dom节点的信息生成布局树,(同时会将坐标信息更新到dom节点上)
  5. 分层,根据css 分出3d前后感觉的图层
  6. 生成绘制列表(形式类似于生成vue render函数的感觉;内容类似于canvas的绘制过程)
  7. 将绘制列表交给gpu绘制

元素模型

  • 块级元素的定义为一行显示,自动撑满,那么设置display: block || table;
  • 行内元素的尺寸有内容决定,display: inline || inline-block;
  • 但是行内块元素可以设置尺寸,阅读css世界一书,我们可以这么理解:
  • display: block;相当于display: block-block;
  • display: inline; 相当于display: inline-inline;
  • 以display:block-block举例,前面的控制元素是否一行显示,后面控制元素设置宽高等属性是否可以生效。

元素尺寸

由外部决定

  • 流式布局(取决于父元素的content盒子)
  • 格式化宽度(取决于相对元素的padding盒子)

由元素自身决定

  • inline-block
  • float
  • inline
  • 定位(!relative) 拥有上述属性的元素,可以称为具有包裹性(收缩+被包裹)。 具体特性:
  1. 宽度由自身决定
  2. 非定位元素宽度不会超过父元素的content盒子 (最小宽度、最大宽度除外)
  3. 定位元素的宽度不会超过参照元素的padding盒子(最小宽度、最大宽度除外)
  4. 定位元素的裁切效果(overflow),需要通过参照元素设置

最小宽度:即使width: 0;内部的文字也会撑开一个字符的宽度

最大宽度:例如连续的字母

如何是height: 100%;生效?

  • 设置父元素高度
  • 格式化高度

padding

  • 百分比 都是相对于父元素的width
  • 不是设置了box-sizing: border-box;就可以高枕无忧了,如果设置的padding尺寸大于width,那么width会失效
  • 行内元素的padding会换行

margin

  • 百分比 都是相对于父元素的width
  • 可以有负值,margin为负值可以理解为元素的落脚点变小了,但实际渲染的内容没少(但可能被遮挡)
  • 负值表现:块级盒子、格式化宽度高度,会向该方向增加元素的尺寸;会减少该元素对应方向占据的空间(不是尺寸),left、top:也就是元素向该方向偏移,同时会影响后面的布局,right、bottom:后面的兄弟元素会向此元素偏移
  • margin合并都是块级元素之间的事情,而且只有垂直方向上才有,计算规则:正正取大,正负相加,负负最负
  • 阻止margin合并,1 破坏必要条件 块级元素之间;2 增加border或padding、bfc

替换元素是啥?尺寸优先级?填充方式?

  • 什么是替换元素?拥有src属性或者content属性的元素。例如img标签,就是将图片文件的内容填充进去
  • 尺寸优先级:css尺寸 > html尺寸(多数默认为300 *150) > 文件的固定尺寸
  • 如果css属性设置的宽高比例和文件的比例不对,那么会变形的,主要是因为object-fit: fill;可以修改为obejct-fit: contain/cover;
  • 如果想要使用伪元素+content来达到替换元素的效果,此时设置宽高是无效的。因为img是浏览器封装好的组件,简单看相当于div + content div + 填充方式 实现的,真正的内容包在了里面。而如果使用content,此时你设置宽高,就相当于在修改图片文件的尺寸,文件尺寸 那玩意改不了改不了
  • content属性内容生成技术(结合伪元素)
  1. content属性值可以为字符串、图片、函数、函数+字符串、Unicode字符(例如\a \d换行字符)
  2. 生成的内容,只是视觉的效果,屏幕阅读设备读取不到,搜索引擎无法抓取相关内容。生成的文本无法复制、选中。所以一般用于装饰效果。
  3. 生成的内容,无法左右:empty,如果一个元素内容为空,你使用content添加了内容,:empty伪类还是生效的。
  4. 通过函数的方式生成的内容无法获取,即使通过window.getComputed(ele, '::before').content拿到的也只是函数的字符串,例如'attr(data-name)' 'connter(计数器name)'。

border

  • 先说下border、box-shadow、outline都是不支持百分比,为啥,因为没有场景需要;
  • border-width
  • border-image-resource
  • border-image-slice 左上角 、右上角 、下右角 、下左角的方式切割图片,然后切割后的角图片 应用在角上,切割后的边用在边上,这块不理解的可以看张鑫旭的博客

选择器(只记录常用的、重要的)

  • 选择器都是单独就可生效的,例如:hover,我以前以为很多选择器是必须要搭配使用

  • 基础选择器: #id .class tag *

  • 层次选择器: 后代 elemP elemC; 子代 elemP>elemC; 后面的一个兄弟elem1+elem2; 后面的所有兄弟elem1~elem1

  • 集合选择器: 并集elem1,elem2; 交集elem1.class

  • 状态选择器::hover鼠标悬浮的元素,链接交互选择器顺口溜l v h a,:focus输入聚焦的表单元素,:checked选项选中的表单元素,:required必须输入的表单元素,:valid输入合理的表单元素,:invalid输入不合理的表单元素,:disabled禁用的表单元素,:enabled事件启用的表单元素,表单元素的状态选择器还有很多

  • 结构选择器: :root根元素 也就是html,:empty无子元素的元素(匿名行内元素也算,不同状态的元素也算),所以它的最佳搭档为为元素

  • 结构选择器之 eleC:nth-child(n); 理解:先命中eleC的父元素中第n个子元素,且这个元素需要符合eleC选择器;还有:nth-last-child :first-child。里面的n也可以是一个表达式,例如只命中偶数 2n

  • 结构选择器之 eleC:nth-of-type(n) 1.先命中eleC选择器命中的元素 的父元素,2.父元素中的所有 子 元素,依据标签名进行分类。例如div一组,span一组,3.命中不同分组内第n个元素,且如果这个元素也符合eleC选择器,那么可以应用设置的样式;还有 :nth-last-of-type :first-of-type

  • 属性选择器 [attr]有某个属性的元素 [att=val]属性等于指定值的元素 对于属性值还有其他匹配条件的选择器:xx开头、结尾、包含等

  • 伪元素选择器 ::before ::after ::first-letter首字母 ::first-line首行

布局

absolute fixed

  • 定位必须要设置top、right、bottom、left吗?首先这两个属性是非常独立的属性,单独设置就可以达到布局的目的,不一定非要依靠top right bottom left
  • overflow特性:绝对定位元素、固定定位元素被裁剪,只有当overflow:hidden设置在 其定位元素上,或者设置在其定位元素的父元素上
  • 无依赖定位(没有对应方向);本质是不占据任何空间的相对定位;此时位置与不设置定位时的位置有关;
  • 位置表现流式布局中,元素和未设置定位时位置一样,只是不占据空间了;添加条件,流式布局下,块级元素中有一个absolute或fixed定位元素,此时如果设置了text-align,会结合幽灵空白节点居中,这个元素就会在父元素的中部,不是水平居中对齐;如果是flex布局中,跟上述text-align的效果类似,但是flex中可是没有幽灵空白节点的,而且flex可以设置多轴的对齐方式,所以如果在flex的子项目中设置无依赖定位,可以达到居中的效果,这块建议去试一下;
  • 题外话,absolute其实和float可以称为兄弟关系,很多特性一致,只不过absolute更厉害一点,如果布局中同时有absolute float 那么float无效;
  • fixed如果遇上父元素中使用transform filter等属性,参照的就是父元素而不是窗口
  • 开发规范:如果absolute就可以满足布局,不要给父元素relative;如果非要relative,自身包一层,看能否充当想要的relative

float + 原理

  • 浮动最初的目的:环绕文字
  1. 举例这样的结构
<p><img scr='xx' /></p><span>xxxxxx...</span>
  1. 首先浮动元素不占据高度,让父元素高度塌陷,文字就可以顶上去,与图片一行
  2. 其次,文字不碰到图片
  • 原理:行框盒子不会和浮动元素重叠

幽灵空白节点的产生 + 原理

  • 如何产生:前提:流式布局下,也就是块级元素内,普通行内元素(inline inline-block)外围都会包裹一层行框盒子,在行框盒子前面就会产生一个宽度为0的空白行内元素
  • 行框盒子是在行内元素的外围,紧贴着块级元素
  • 解决方法:通常可以设置块级元素上的字号为0,或者设置vertial-align,或者将行内元素转换,

BFC 块级格式化上下文

  • bfc全称 block formatting context,块级格式化上下文,它可以看成一种渲染规则、特性
  • 最直观的特性:如果一个元素具有bfc,内部的元素样式无法影响外面,外面的样式、布局也无法影响bfc内部
  • 其他特性:
  • bfc元素会自动填满浮动元素剩下的空间
  • bfc元素会计算内部浮动元素的高度
  • 生成方式:html、inline-block、float、!relative定位、overflow:!visible、flex布局的子元素

界面

background + 多背景

  • 缩写background: color image repeat attachment position/size ,注意position/size的格式, 缩写没有origin clip
  • background-image: 背景可以为0-n个图片、渐变
  • 多个背景用逗号间隔。例如background-image: url('a.jpg'),url('b.jpg');
  • 多个背景 子属性设置方式:逗号间隔。例如: background-position: top left, top right;
如果使用了多个背景内容,其他相关属性也要设置,否则会采用第一个背景的属性,例如:  
.bg {  
  background-image: url('a.jpg'), url('b.jpg');  
  background-position: left left;  
}  
  
如上设置,b.jpg的位置就和a.jpg一样;如果想单独设置:  
background-position: left left,  right right;  
background其他属性类似;
  • 多个背景的层叠顺序为先上到下。以background-image: url('a.jpg'), url('b.jpg'); 为例:a图片在其他背景内容的上层
  • background-position: x y相对于起始点的的偏移;可以是带单位的值/百分比/关键字;
  • background-size: 背景图片内容填充大小,可以为值、百分比、关键字
  • background-clip:裁切背景的显示区域 border-box/padding-box/content-box/text
  • background-origin: 背景图片的起始位置,默认padding-box;
  • background-color: 背景颜色,不受origin控制,作用到border-box

mask

  • 遮罩作用于元素(相当于ps里面的蒙版),如果说float和absolute是兄弟关系,只不过absolute厉害一点,那么mask和background就是双胞胎,除了作用不一样,其他书写方式都是一样的

这里总结下:border outline box-shadow 等很多border外的样式都是没有百分比值的,因为没有场景,例如一个元素的border,需要跟元素的尺寸关联吗,不会吧,通常都是固定值

outline边框

  • 在border的外围添加边框,不受border-radius影响,始终是矩形的
  • 不会增加元素的宽高
  • outline-offset: 1px;相对于border的偏移量,可以为负值,默认为0

border-radius + 椭圆border

  • 顺序:左上角开始
  • 圆角可以是圆形也可以是椭圆形。可以看成所在边的切线。分别设置水平和垂直的半径就是椭圆形;
  • border-radius: awR bwR cwR dwR / ahR bhR chR dhR;
  • 如果设置的很大,那么系统会等比缩小border设置的值。总不能让任意相邻border交叉重叠吧。所以一个正方形设置border-radius: 50%;和100%;的效果是一样的

box-shadow

  • 沿着border轮廓添加投影,不会影响元素的布局,不会响应鼠标事件
  • box-shadow: x轴偏移量 y轴偏移量 模糊距离? 扩张半径? 颜色? 位置(在外面还是内部,默认在元素外部);
  • 扩张半径可以用来实现border的作用,而且还不影响布局。很大的投影还可以当作dialog、引导步骤元素的效果;还可以为负值
  • 阴影的生成原理,举例 box-shadow : 2px 3px 4px 1px rgba(0,0,0,.5);(下面理解主要摘自css揭秘)
  1. 以该元素border盒子尺寸结合扩张半径的尺寸,画一个 rgba(0,0,0,.5) 的矩形。(box-shadow和drop-shadow的主要区别就在box-shadow使用border盒子生成内容,后者用实际显示内容来生成投影)
  2. 把它向右移 2px ,向下移 3px 。
  3. 使用高斯模糊算法(或类似算法)将它进行 4px 的模糊处理。这在本质上表示在阴影边缘发生阴影色和纯透明色之间的颜色过渡长度近似于模糊半径的两倍(实际你可以这么理解,将投影往内收4px的尺寸后,渐变一圈8px的尺寸。也就是投影本来的尺寸会被用掉部分尺寸 + 添加部分尺寸用来呈现模糊的效果)。
  4. 裁切掉与元素重叠的部分。所以元素的正下方是没有阴影的,这个和文字不一样,文字的阴影不会被裁切。
  • 可以以逗号分隔创建多个阴影,层叠顺序跟背景图片一样,先上后下。
  • 利用好这个扩张半径,可以非常简单的不占位做出border效果、单侧模糊效果、彩虹、引导页面、网上甚至可以用用box-shadow来画画。

text-shadow

  • 轴偏移量 y轴偏移量 模糊距离? 颜色?
  • 可用逗号间隔设置多个投影。
  • 文字阴影不会被裁切

filter:滤镜

  • 多个滤镜函数,以空格分隔,依次生效
  • drop-shadow函数,实际内容的投影,例如png图片的投影。格式,drop-shadow(轴偏移量 y轴偏移量 模糊距离? 颜色)
  • brightness函数,元素明暗暗,默认1
  • blur函数:模糊,值可以为数字或长度 不可以是百分比,默认0;box-shadow的模糊是周围放大了一圈模糊的内容,blur函数的模糊在元素的四周向内有一个所设置值 的透明渐变,所以在实现毛玻璃效果的时候需要将区域放大,再缩小视口才更完美。它还有一个缺点,就是模糊算法缘故,blur函数的开销比较大
  • 色相、透明度、灰度、饱和度、对比度

transform

  • 注意 rotate、scale 改变了坐标轴
  • 可以使用多个函数,以空格间隔
  • translate函数:偏移
  • rotate函数:旋转
  • scale函数:缩放
  • skew函数:扭曲
  • perspective函数,透视, 近大远小。还有一个同名属性,区别:函数是设置在需要透视的子元素上,属性是设置在父元素上

linear-gradient线性渐变函数

  • linear-gradient( 方向关键字/角度, 颜色 位置,颜色 位置..)
  • 位置:这个颜色距离起始位置的距离。例如 linear-gradient(to bottom, blue 50%, yellow 0, yellow)如果后面的位置值比前面小,那么就会使用前面的位置值;此时0 = 50%, yellow 0这个技巧需要记得,通常用来做非渐变用的
  • 如果多个色标具有相同的位置,它们会产生一个无限小的过渡区域,也就是没有过渡。
  • 过渡的起止色分别是第一个和最后一个指定值。
  • 如果起始/结束未设置颜色,那么将向内取色

radial-gradient锥形渐变函数

  • 跟linear-gradient使用方法类似。
  • 结合在dom元素上设置 变量,可实现饼图

层叠上下文

很多人认为position: absolute;就可以创建层叠上下文

  • 层叠上下文是一种层叠顺序的渲染规则
  • 因为html就有层叠上下文特性,所以所有元素都有排列层叠的顺序,但是层叠上下文不是所有元素都有
  • 层叠顺序:层叠上下文那个元素的背景、负z-index、block float 内联 z-index: 0 +;
  • 如果层叠上下文中的两个元素层叠等级一样,那么dom在后的在上面(后来居上)
  • 创建层叠上下, html、定位(非static)+ z-index: !auto、flex的子元素、filter、transform、will-change

变量(css自定义属性)

  • 变量又叫css自定义属性(注意区别于标签上的自定义属性,它类似于display等这样的属性)
  • 使用方式 --css自定义属性名: 字符串| 数值 | var(其他变量) | 函数返回值(attr calc url等);
  • 如果变量值是一个字符串,可以与其他字符串拼接。--css自定义属性名: 字符串var(--xx返回字符串的变量);
  • 如果变量值是数值,不能与数值单位直接连用,需要使用calc连接。--css自定义属性名: calc(var(--xx返回数值的变量) * 1px);
  • 如果变量值带有单位,就不能写成字符串。--xx: 20px;
  • 作用域:定义的变量或者说自定义css属性和css属性是一样的,在当前节点和子节点中有效

很简单的计数器

  • 名字比较唬人,使用起来其实很简单,远比行高、浮动的细节简单,有些特定的场景用它会很省事,例如序列号
  • 用于定义。counter-rest: name1 name1初始值 name2 name2初始值;首先计数器的name是可以重复定义,因为它以元素进行划分的,例如可以在父元素上定义name1,然后在子元素内也定义name1的计数器
  • 用于取。counter(name),通常的用法是content: counter(name1);先从自身元素有没有设置这个计数器属性,如果没有就一直往父元素上找,如果没找到返回0;也可以结合calc来使用
  • counters(name, string),它与counter的区别是,counter找到就停止,counters可以理解为是由内而外找到 组成数组,然后倒序,然后join(string)
  • 用于计算。counter-increment: name 需要与之相加的值可以为负值

文字

复杂的line-height

  • 实际上用于设置两行文字基线间的距离,因为两行文字间的高度完全受行高控制,不受padding、margin等其他属性影响,所以一行文字所占的布局高度,也可以看作字面意思的行高
  • 行高的值可以为数字、长度值例如1px、百分比;数字、百分比都是相较于字号来计算的;
  • 行高具有继承性,但是设置不同的值,继承的值是不一样的;设置为数字例如2,继承的就是2;设置长度值、百分比,继承的是计算后的值
  • 行高作用于行框盒子,行框盒子因为行内元素生成,每一个行框盒子前面都有一个幽灵空白节点,还要注意行框盒子与块级盒子与行内元素的位置关系,因为行框盒子紧贴块级盒子,所以如果块级元素中设置了比行内元素中更大的行高,那行框盒子的高度就是大的值
  • 通常设置行高,要么是为了尺寸,可能还要顾及到文字垂直居中,要涉及到文字的基线,基线的位置取决于字体和字号; middle线位于基线以上一半ex的位置,并不是对半分的位置,所以这时候就需要对齐方式出场了

vertical-align 上面的好基友

  • 用于设置行内元素的对齐方式,默认基线
  • 值可以为关键字、百分比、数值、长度值;百分比和数值是乘以行高 来计算的。感觉一环套一环,行高相较于字号计算,对齐方式相较于行高计算

单位

  • ex是当前字体、当前字号下 x的高度,这个单位使用场景不多,但有一种场景适合:文字旁有一个正好和文字高度一致的图标/图片,那么就可以使用1ex作为高度,同时因为行内元素的基线对齐特性,就会达到居中的效果
  • em只与字号有关,且不是当前字体、当前字号下m的高度,它是字模的高度,可以想象下一个印章的宽高(里面有字)。因为字母中m的形状比较方方正正的,所以叫em
  • rem 参照根元素

word-wrap

  • normal只允许在断字点换行;break-word可在单词内部进行换行

white-space:定义文本是否可以换行

交互

cursor

锚点

  • 通过访问锚点链接,非表单元素,页面会滚动至 锚点元素在窗口顶部;表单元素,页面会让表单元素在窗口中,具体如何看各家浏览器的方案
  • 如果通过tab 回车键,让表单元素处于focus状态,或者通过访问锚点链接,如果锚点元素正好是表单元素 且这个元素正好在页面中,此时就算此时被包裹overflow:hidden;对应元素也会呈现出来(这个了解即可)

transition过渡 相当于隐性动画

  • transition:name duration delay? timing-function;
  • 如果设置了两个时间,前面的时间会被当作duration 后面的会被当作delay
  • time-function只能是贝塞尔曲线

animation动画

  • animation:name duration timing-function delay iteration-count direction;
  • 可以使用多个动画,以逗号间隔
  • animation-timing-function:连续动画 | 逐帧动画;连续动画可以使用贝塞尔曲线函数cubic-bezier()定义,x轴为时间,y轴为位置。匀速为对角线,如果凸出来的,举例 一半的时间内它跑的更多,因为时间相同,所以是先快后慢的,凹进去是逐渐加速的,还可以做回滚效果的贝塞尔曲线。也有一些定义好的关键字 如ease ease-in ease-out ease-in-out; 逐帧动画steps(number, start/end) 默认end

css的复习暂告一段落,文章的内容、心得部分来自于css世界、css揭秘、掘金小册玩转css的艺术之美,也推荐大家去支持、学习