CSS盒模型

中高级前端面试秘籍

 

引言

又是一年寒冬季,只身前往沿海工作,也是我第一次感受到沿海城市冬天的寒冷。刚过完金九银十,经过一场惨烈的江湖厮杀后,相信有很多小伙伴儿已经找到了自己心仪的工作,也有的正在找工作的途中。考虑到年后必定又是一场不可避免的厮杀,这里提前记录一下自己平时遇到和总结的一些知识点,自己巩固复习加强基础的同时也希望能在你的江湖路上对你有所帮助。笔者在入职最近这家公司之前也曾有过长达3个月的闭关修炼期,期间查阅资料无数,阅读过很多文章,但总结下来真正让你印象深刻的,不是那些前沿充满神秘感的新技术,也不是为了提升代码逼格的奇淫巧技,而是那些我们经常由于项目周期紧而容易忽略的基础知识。所谓万丈高楼平地起,只有你的地基打得足够牢固,你才有搭建万丈高楼的底气,你才能在你的前端人生路上越走越远

这篇主要是先总结一下CSS相关的知识点,可能某些部分不会涉及到太多具体的细节,主要是对知识点做一下汇总,如果有兴趣或者有疑惑的话可以自行百度查阅下相关资料或者在下方评论区留言讨论,后续文章再继续总结JS和其他方面相关的知识点,如有不对的地方还请指出。

1. CSS盒模型

CSS盒模型就是在网页设计中经常用到的CSS技术所使用的一种思维模型。CSS 假定所有的HTML 文档元素都生成了一个描述该元素在HTML文档布局中所占空间的矩形元素框,可以形象地将其看作是一个盒子。CSS 围绕这些盒子产生了一种“盒子模型”概念,通过定义一系列与盒子相关的属性,可以极大地丰富和促进各个盒子乃至整个HTML文档的表现效果和布局结构。

CSS盒模型可以看成是由从内到外的四个部分构成,即内容区(content)、内边距(padding)、边框(border)和外边距(margin)。内容区是盒子模型的中心,呈现盒子的主要信息内容;内边距是内容区和边框之间的空间;边框是环绕内容区和内边距的边界;外边距位于盒子的最外围,是添加在边框外周围的空间。
CSS盒模型
根据计算宽高的区域我们可以将其分为IE盒模型W3C标准盒模型,可以通过box-sizing来进行设置:

  • content-box:W3C标准盒模型
  • border-box:IE盒模型

区别:
W3C标准盒模型:width(宽度) = content(内容宽度)
IE盒模型:width(宽度) = content(内容宽度) + padding(内边距) + border(边框)

2. BFC

BFC即Block Fromatting Context(块级格式化上下文),它是页面中的一块独立的渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。具有BFC特性的元素可以看成是一个隔离的独立容器,让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。

IE浏览器下为hasLayout,一般可以通过zoom:(除normal外任意值)来触发,hasLayout是IE浏览器渲染引擎的一个内部组成部分。在IE浏览器中,一个元素要么自己对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和和组织内容。为了调节这两个不同的概念,渲染引擎采用了hasLayout的属性,属性值可以为true或false。当一个元素的hasLayout属性为true时,我们就说这个元素有一个布局(Layout)。当拥有布局后,它会负责对自己和可能的子孙元素进行尺寸计算和定位,而不是依赖于祖先元素来完成这些工作。

2.1 触发条件

  • 根元素(<html>)
  • 浮动元素(元素的float不是none)
  • 绝对定位元素(元素的positionabsolutefixed)
  • 行内块元素(元素的displayinline-block)
  • 表格单元格(元素的displaytable-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的displaytable-caption,HTML表格标题默认为该值)
  • display值为flow-root的元素
  • overflow属性的值不为visible
  • 弹性元素(displayflexinline-flex元素的直接子元素)
  • 网格元素(displaygrid或者inline-grid元素的直接子元素)

    2.2 布局规则

    普通文档流布局规则
  • 浮动的元素是不会被父级计算高度的
  • 非浮动元素会覆盖浮动元素的位置
  • margin会传递给父级
  • 两个相邻元素上下margin会发生重叠

BFC布局规则

  • 浮动的元素会被父级计算高度(父级触发了BFC)
  • 非浮动元素不会覆盖浮动元素的位置(非浮动元素触发了BFC)
  • margin不会传递给父级(父级触发了BFC)
  • 两个相邻元素上下margin不会发生重叠(给其中一个元素增加一个父级,并让它的父级触发BFC)

    2.3 应用

  • 防止margin重叠
  • 清除内部浮动(原理是父级计算高度时,浮动的子元素也会参与计算)
  • 自适应两栏布局
  • 防止元素被浮动元素所覆盖

    3. 层叠上下文

    层叠上下文(stacking context),是HTML中一个三维的概念。在CSS2.1规范中,每个盒模型的位置都是三维的,分别是平面画布上的X轴Y轴以及表示层叠的Z轴。一般情况下,元素在页面上沿X轴Y轴平铺,我们察觉不到它们在Z轴上的层叠关系。而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖。

CSS盒模型
如果一个元素含有层叠上下文,我们就可以理解为这个元素在Z轴上就"高人一等",最终表现就是它离屏幕观察者更近。

你可以把层叠上下文理解为该元素当了官,而其他非层叠上下文元素则可以理解为普通群众。凡是"当了官的元素"就比普通元素等级要高,也就是说元素在Z轴上更靠上,更靠近观察者。

3.1 触发条件

  • 根层叠上下文(<html>)
  • position属性为非static值并设置z-index为具体数值
  • CSS3中的属性也可以产生层叠上下文
    • flex
    • transform
    • opacity
    • filter
    • will-change
    • -webkit-overflow-scrolling

      3.2 层叠等级

      层叠等级(stacking level),又叫"层叠级别"或者"层叠水平"。
  • 在同一个层叠上下文中,它描述定义的是该层叠上下文中的层叠上下文元素在Z轴上的上下顺序
  • 在其他普通元素中,它描述定义的是这些普通元素在Z轴上的上下顺序

    注意:
    1. 普通元素的层叠等级优先由其所在的层叠上下文决定。
    2. 层叠等级的比较只有在当前层叠上下文元素中才有意义,不同层叠上下文中比较层叠等级是没有意义的。

CSS盒模型
根据以上的层叠等级图,我们在比较层叠等级时可以按照以下的思路来顺序比较:

  • 首先判定两个要比较的元素是否处于同一个层叠上下文中
  • 如果处于同一个层叠上下文中,则谁的层叠等级大,谁最靠上
  • 如果处于不同的层叠上下文中,则先比较他们所处的层叠上下文的层叠等级
  • 当两个元素层叠等级相同,层叠顺序相同时,在DOM结构中后面的元素层叠等级在前面元素之上

4. CSS3中新增的选择器以及属性

  • 属性选择器:
属性选择器含义描述
E[attr^="val"]属性attr的值以"val"开头的元素
E[attr$="val"]属性attr的值以"val"结尾的元素
E[attr*="val"]属性attr的值包含"val"子字符串的元素
  • 结构伪类选择器
选择器含义描述
E:root匹配元素所在文档的根元素,对于HTML文档,根元素始终是<html>
E:nth-child(n)匹配其父元素的第n个子元素,第一个编号为1
E:nth-last-child(n)匹配其父元素的倒数第n个子元素,第一个编号为1
E:nth-of-type(n)与:nth-child()作用类似,但是仅匹配使用同种标签的元素
E:nth-last-of-type(n)与:nth-last-child() 作用类似,但是仅匹配使用同种标签的元素
E:last-child匹配父元素的最后一个子元素,等同于:nth-last-child(1)
E:first-of-type匹配父元素下使用同种标签的第一个子元素,等同于:nth-of-type(1)
E:last-of-type匹配父元素下使用同种标签的最后一个子元素,等同于:nth-last-of-type(1)
E:only-child匹配父元素下仅有的一个子元素,等同于:first-child:last-child或 :nth-child(1):nth-last-child(1)
E:only-of-type匹配父元素下使用同种标签的唯一一个子元素,等同于:first-of-type:last-of-type或 :nth-of-type(1):nth-last-of-type(1)
E:empty匹配一个不包含任何子元素的元素,文本节点也被看作子元素
E:not(selector)匹配不符合当前选择器的任何元素
  • CSS3新增属性
属性含义描述
transition过渡效果
transform变换效果(移动(translate)、缩放(scale)、旋转(rotate)、倾斜(skew))
transform-origin设置旋转元素的基点位置
animation动画效果
border-color为边框设置多种颜色
border-radius圆角边框
box-shadow边框阴影
border-image边框图片
background-size规定背景图片的尺寸
background-origin规定背景图片的定位区域
background-clip规定背景图片从什么位置开始裁切
text-shadow文本阴影
text-overflow文本截断
word-wrap对长单词进行拆分,并换行到下一行
opacity不透明度
box-sizing控制盒模型的组成模式
rgba基于r,g,b三个颜色通道来设置颜色值,通过a来设置透明度

5. CSS3中transition和animation的属性

1) transition(过渡动画)

用法:transition: property duration timing-function delay
| 属性 | 含义描述 |
| ---- | ---- |
| transition-property | 指定哪个CSS属性需要应用到transition效果 |
| transition-duration | 指定transition效果的持续时间 |
| transition-timing-function | 指定transition效果的速度曲线 |
| transition-delay | 指定transition效果的延迟时间 |

2) animation(关键帧动画)

用法:animation: name duration timing-function delay iteration-count direction fill-mode play-state
| 属性 | 含义描述 |
| ---- | ---- |
| animation-name | 指定要绑定到选择器的关键帧的名称 |
| animation-duration | 指定动画的持续时间 |
| animation-timing-function | 指定动画的速度曲线 |
| animation-delay | 指定动画的延迟时间 |
| animation-iteration-count | 指定动画的播放次数 |
| animation-direction | 指定是否应该轮流反向播放动画 |
| animation-fill-mode | 规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式 |
| animation-play-state | 指定动画是否正在运行或已暂停 |

6. 清除浮动的方式以及各自的优缺点

  • 额外标签法(在最后一个浮动元素的后面新加一个标签如<div class="clear"></div>,并在其CSS样式中设置clear: both;)

    优点:简单,通俗易懂,写少量代码,兼容性好
    缺点:额外增加无语义html元素,代码语义化差,后期维护成本大

  • 给父级设置高度

    优点:简单,写少量代码,容易掌握
    缺点:不够灵活,只适用于高度固定的布局

  • 触发父级BFC(如给父元素设置overflow:hidden,特别注意的是:在IE6中还需要触发hasLayout,例如给父元素设置zoom:1。原理是触发父级BFC后,父元素在计算高度时,浮动的子元素也会参与计算)

    优点:简单,代码简洁
    缺点:设置overflow:hidden容易造成不会自动换行导致超出的尺寸被隐藏掉,无法显示要溢出的元素

  • 使用after伪元素,常见的写法如下:
.clearfix::after {
    content: ".";
    display: block;
    height: 0;
    line-height: 0;
    clear: both;
    visibility:hidden;
    font-size: 0;
 }
 
 .clearfix {
    // 注意此处是为了兼容IE6和IE7浏览器,即触发hasLayout
    zoom: 1;
 }

优点:符合闭合浮动思想,结构语义化正确
缺点:代码量多,因为IE6-7下不支持after伪元素,需要额外写zoom:1来触发hasLayout

7. 居中布局的方式

水平居中

  • 若是行内元素,则直接给其父元素设置text-align: center即可
  • 若是块级元素,则直接给该元素设置margin: 0 auto即可
  • 若子元素包含浮动元素,则给父元素设置width:fit-content并且配合margin
.parent {
    width: -webkit-fit-content;
    width: -moz-fit-content;
    width: fit-content;
    margin: 0 auto;
}
  • 使用flex布局的方式,可以轻松实现水平居中,即使子元素中存在浮动元素也同样适用
// flex 2012年版本写法
.parent {
    display: flex;
    flex-direction: row;
    justify-content: center;
}

// flex 2009年版本写法
.parent {
    display: box;
    box-orient: horizontal;
    box-pack: center;
}
  • 使用绝对定位的方式,再配合CSS3新增的transform属性
.child {
    position: absolute;
    left: 50%;
    transform: translate(-50%, 0);
}
  • 使用绝对定位的方式,再配合负值的margin-left(此方法需要固定宽度)
.child {
    position: absolute;
    left: 50%;
    width: 200px; // 假定宽度为200px
    margin-left: -100px; // 负值的绝对值为宽度的一半
}
  • 使用绝对定位的方式,再配合left:0;right:0;margin:0 auto;(此方法需要固定宽度)
.child {
    position: absolute;
    left: 0;
    right: 0;
    margin: 0 auto;
    width: 200px; // 假定宽度为200px
}

垂直居中

  • 若元素是单行文本,则直接给该元素设置line-height等于其父元素的高度
  • 若元素是行内块级元素,可以配合使用display:inline-block;vertical-align:middle和一个伪元素来让内容块居中
.parent::after, .child {
    display: inline-block;
    vertical-align: middle;
}

.parent::after {
    content: "";
    height: 100%;
}
  • 使用vertical-align属性并且配合使用display:tabledisplay:table-cell来让内容块居中
.parent {
    display: table;
}

.child {
    display: table-cell;
    vertical-align: middle;
}
  • 使用flex布局的方式,可以轻松实现垂直居中,即使子元素中存在浮动元素也同样适用
// flex 2012年版本写法
.parent {
    display: flex;
    align-items: center;
}

// flex 2009年版本写法
.parent {
    display: box;
    box-orient: vertical;
    box-pack: center;
}
  • 使用绝对定位的方式,再配合CSS3新增的transform属性
.child {
    position: absolute;
    top: 50%;
    transform: translate(0, -50%);
}
  • 使用绝对定位的方式,再配合负值的margin-top(此方法需要固定高度)
.child {
    position: absolute;
    top: 50%;
    height: 200px; // 假定高度为200px
    margin-top: -100px; // 负值的绝对值为高度的一半
}
  • 使用绝对定位的方式,再配合top:0;bottom:0;margin:auto 0;(此方法需要固定高度)
.child {
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto 0;
    height: 200px; // 假定高度为200px
}

水平垂直居中

  • 使用flex布局的方式同样可以轻松实现水平垂直居中
// flex 2012年版本写法
.parent {
    display: flex;
    justify-content: center;
    align-items: center;
}

// flex 2009年版本写法
.parent {
    display: box;
    box-pack: center;
    box-align: center;
}
  • 使用绝对定位的方式,再配合CSS3新增的transform属性
.child {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}
  • 使用绝对定位的方式,再配合使用负值的margin-top和负值的margin-left(此方法需要同时固定宽度和高度)
.child {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-top: -50px; // 负值的绝对值为高度的一半
    margin-left: -100px; // 负值的绝对值为宽度的一半
    width: 200px; // 假定宽度为200px
    height: 100px; // 假定高度为100px
}

8. CSS的优先级和权重

选择器(优先级从高到低)示例特殊性值
!important(重要性标识)div { color: #fff !important; }无,但为了方便记忆,可将其表示为1,0,0,0,0
行内样式<div style="color: #fff;"></div>1,0,0,0
id选择器#id0,1,0,0
类,伪类和属性选择器.content, :first-child, [type="text"]0,0,1,0
标签和伪元素选择器h1, ::after0,0,0,1
通配符、子选择器、相邻选择器*, div > p, p + p0,0,0,0
继承span { color: inherit; }
浏览器默认值浏览器开发者工具右侧的Styles面板中会显示user agent stylesheet字样

9. 移动端1px物理像素边框

我们知道,在移动端存在物理像素(physical pixel)设备独立像素(density-independent pixel)的概念。物理像素也称为设备像素,它是显示设备中一个最微小的物理部件,每个像素可以根据操作系统设置自己的颜色和亮度。设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如CSS像素),然后由相关系统转换为物理像素。根据物理像素和设备独立像素也衍生出了设备像素比(device pixel ratio)的概念,简称为dpr,其定义了物理像素和设备独立像素的对应关系,其计算公式为设备像素比 = 物理像素 / 设备独立像素。因为视网膜(Retina)屏幕的出现,使得一个物理像素并不能和一个设备独立像素完全对等,如下图所示:
CSS盒模型
在上图中,在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素却对应4个物理像素,即在Retina屏幕下会有不同的dpr值。为了追求在移动端网页中更好的显示质量,因此我们需要做各种各样的适配处理,最经典的莫过于1px物理像素边框问题,我们需要根据移动端不同的dpr值来对边框进行处理。在JavaScript中,可以通过window.devicePixelRatio来获取当前设备的dpr,在CSS中,可以通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio和-webkit-max-device-pixel-ratio来进行媒体查询,从而针对不同的设备,来做一些样式适配。这里对于1px像素的边框问题,给出一种最常见的写法:

.border-1px {
    position: relative;
}

.border-1px::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    background-color: #000;
    -webkit-transform: scaleY(.5);
    transform: scaleY(.5);
}

@media only screen and (-webkit-min-device-pixel-ratio: 2.0), (min-device-pixel-ratio: 2.0) {
    .border-1px::after {
        -webkit-transform: scaleY(.5);
        transform: scaleY(.5);
    }
}

@media only screen and (-webkit-min-device-pixel-ratio: 3.0), (min-device-pixel-ratio: 3.0) {
    .border-1px::after {
        -webkit-transform: scaleY(.33);
        transform: scaleY(.33);
    }
}

10. 实现三栏布局的方式有哪些

三栏布局,顾名思义就是分为左中右三个模块进行布局,并且左右两边固定,中间模块根据浏览器的窗口变化进行自适应,效果图如下:
CSS盒模型
这里给出四种实现三栏布局的方式:

  • 使用绝对定位的方式
.container {
    position: relative;
    height: 200px;
    line-height: 200px;
    text-align: center;
    font-size: 20px;
    color: #fff;
}

.left {
    position: absolute;
    left: 0;
    top: 0;
    width: 150px;
    background: red;
}

.main {
    margin-left: 160px;
    margin-right: 110px;
    background: green;
}

.right {
    position: absolute;
    right: 0;
    top: 0;
    width: 100px;
    background: blue;
}

<div class="container">
    <div class="left">左</div>
    <div class="main">中</div>
    <div class="right">右</div>
</div>

优点:方便快捷,简单实用,不容易出现问题,而且还可以将<div class="main"></div>元素放到最前面,使得主要内容被优先加载。
缺点:元素脱离了文档流,可能会造成元素的重叠。

  • 使用flex布局的方式
.container {
    display: flex;      
    height: 200px;
    line-height: 200px;
    text-align: center;
    font-size: 20px;
    color: #fff;
}

.left {
    width: 150px;
    background: red;
}

.main {
    margin: 0 10px;
    flex: 1;
    background: green;
}

.right {
    width: 100px;
    background: blue;
}

<div class="container">
    <div class="left">左</div>
    <div class="main">中</div>
    <div class="right">右</div>
</div>

优点:简单实用,是现在比较流行的方案,特别是在移动端,大多数布局都采用的这种方式,是目前比较完美的一个。
缺点:需要考虑到浏览器的兼容性,根据不同的浏览器厂商需要添加相应的前缀。

  • 双飞翼布局
.content {
    float: left;
    width: 100%;
}

.main,
.left,
.right {
    height: 200px;
    line-height: 200px;
    text-align: center;
    font-size: 20px;
    color: #fff;
}

.main {
    margin-left: 160px;
    margin-right: 110px;
    background: green;
}

.left {
    float: left;
    margin-left: -100%;
    width: 150px;
    background: red;
}

.right {
    float: right;
    margin-left: -100px;
    width: 100px;
    background: blue;
}

<div class="content">
    <div class="main">中</div>
</div>
<div class="left">左</div>
<div class="right">右</div>

优点:比较经典的一种方式,通用性强,没有兼容性问题,而且支持主要内容优先加载。
缺点:元素脱离了文档流,要注意清除浮动,防止高度塌陷,同时额外增加了一层DOM结构,即增加了渲染树生成的计算量。

  • 圣杯布局
.container {
    margin-left: 160px;
    margin-right: 110px;
}

.left,
.main,
.right {
    height: 200px;
    line-height: 200px;
    text-align: center;
    font-size: 20px;
    color: #fff;    
}

.main {
    float: left;
    width: 100%;
    background: green;      
}

.left {
    position: relative;
    left: -160px;
    margin-left:  -100%;
    float: left;
    width: 150px;
    background: red;
}

.right {
    position: relative;
    right: -110px;
    margin-left:  -100px;
    float: left;
    width: 100px;
    background: blue;
}

<div class="container">
    <div class="main">中</div>
    <div class="left">左</div>
    <div class="right">右</div>
</div>

优点:相比于双飞翼布局,结构更加简单,没有多余的DOM结构层,同样支持主要内容优先加载。
缺点:元素同样脱离了文档流,要注意清除浮动,防止高度塌陷。

11. 实现等高布局的方式有哪些

等高布局,顾名思义就是在同一个父容器中,子元素高度相等的布局。从等高布局的实现方式来说,可以分为两种,分别是伪等高真等高伪等高是指子元素的高度差依然存在,只是视觉上给人的感觉就是等高,真等高是指子元素的高度真实相等。效果图如下:
CSS盒模型
这里给出五种实现等高布局的方式:

伪等高

  • 使用padding-bottom和负的margin-bottom来实现
.container {
    position: relative;
    overflow: hidden;
}
    
.left,
.main,
.right {
    padding-bottom: 100%;
    margin-bottom: -100%;
    float: left;
    color: #fff;
}

.left {
    width: 20%;
    background: red;
}

.main {
    width: 60%;
    background: green;
}

.right {
    width: 20%;
    background: blue;
}

<div class="container">
    <div class="left">左侧内容</div>
    <div class="main">
        <p>中间内容</p>
        <p>中间内容</p>
        <p>中间内容</p>
    </div>
    <div class="right">右侧内容</div>
</div>

真等高

  • 使用flex布局的方式
.container {
    display: flex;
}

.left,
.main,
.right {
    flex: 1;
    color: #fff;
}

.left {
    background: red;
}

.main {
    background: green;
}

.right {
    background: blue;
}

<div class="container">
    <div class="left">左侧内容</div>
    <div class="main">
        <p>中间内容</p>
        <p>中间内容</p>
        <p>中间内容</p>
    </div>
    <div class="right">右侧内容</div>
</div>
  • 使用绝对定位的方式
.container {
  position: relative;
  height: 200px;
}

.left,
.main,
.right {
    position: absolute;
    top: 0;
    bottom: 0;
    color: #fff;
}

.left {
    left: 0;
    width: 20%;
    background: red;
}

.main {
    left: 20%;
    right: 20%;
    background: green;
}

.right {
    right: 0;
    width: 20%;
    background: blue;
}

<div class="container">
    <div class="left">左侧内容</div>
    <div class="main">
        <p>中间内容</p>
        <p>中间内容</p>
        <p>中间内容</p>
    </div>
    <div class="right">右侧内容</div>
</div>
  • 使用table布局的方式
.container {
    width: 100%;
    display: table;
}

.left,
.main,
.right {
    display: table-cell;
    color: #fff;
}

.left {
    width: 20%;
    background: red;
}

.main {
    width: 60%;
    background: green;
}

.right {
    width: 20%;
    background: blue;
}

<div class="container">
    <div class="left">左侧内容</div>
    <div class="main">
        <p>中间内容</p>
        <p>中间内容</p>
        <p>中间内容</p>
    </div>
    <div class="right">右侧内容</div>
</div>
  • 使用grid网格布局的方式
.container {
    display: grid;
    width: 100%;
    grid-template-columns: 1fr 1fr 1fr;
    color: #fff;
}

.left {
    background: red;
}

.main {
    background: green;
}

.right {
    background: blue;
}

<div class="container">
    <div class="left">左侧内容</div>
    <div class="main">
        <p>中间内容</p>
        <p>中间内容</p>
        <p>中间内容</p>
    </div>
    <div class="right">右侧内容</div>
</div>

12. CSS实现三角形的原理

工作中我们经常会遇到需要三角形图标的应用场景,例如内容展开收起、左右箭头点击切换轮播,点击某条列表数据查看详情等。三角形图标的应用范围之广,使得我们有必要了解一下它的实现原理。
1) 首先我们来实现一个最基础的边框效果

.content {
    width: 50px;
    height: 50px;
    border: 2px solid;
    border-color:#ff9600 #3366ff #12ad2a #f0eb7a;
}

效果如下:

CSS盒模型

2) 然后我们尝试将border值放大10倍

.content {
    width: 50px;
    height: 50px;
    border: 20px solid;
    border-color: #ff9600 #3366ff #12ad2a #f0eb7a;
}

效果如下:
CSS盒模型
上图中我们可以很清楚地看到,在绘制border的时候并不是矩形区域,而是梯形区域,那么此时如果我们将widthheight值设置为0,看会发生什么:

.content {
    width: 0;
    height: 0;
    border: 20px solid;
    border-color: #ff9600 #3366ff #12ad2a #f0eb7a;
}

效果如下:
CSS盒模型
此时会看到一个由四个三角形拼装而成的矩形区域,即由上下左右四个边框组合而成。因此不难想象,如果我们想得到某一个方向的三角形,我们只需要让其他方向的边框不可见就行了,例如我们想得到一个朝左的三角形:

.content {
    width: 0;
    height: 0;
    border: 20px solid;
    border-color: transparent #3366ff transparent transparent;
}

效果如下:
CSS盒模型
这样就得到了一个很完美的三角形图标,是不是很简单?

13. link与@import的区别

  • 从属关系区别

    @import是CSS提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS,Rel连接属性,设置浏览器资源提示符preload、prefetch等。

  • 加载顺序区别

    HTML文档在解析的过程当中,如果遇到link标签,则会立即发起获取CSS文件资源的请求;@import引入的CSS将在页面加载完毕后才会被加载。

  • 兼容性区别

    @import是CSS2.1才有的语法,因此需要IE5以上才能识别;link标签作为HTML元素,不存在兼容性问题。

  • DOM可控性区别

    link标签可以通过JS来动态引入,而@import无法通过JS来插入样式

const loadStyle = (url) => {
    const link = document.createElement(‘link‘);
    link.setAttribute(‘type‘, ‘text/css‘);
    link.setAttribute(‘rel‘, ‘stylesheet‘);
    link.setAttribute(‘href‘, url);
    
    document.head.appendChild(link);
}

14. 浏览器是怎样解析CSS选择器的

CSS选择器的解析是从右向左解析的。若从左向右地匹配,发现不符合规则,需要进行回溯,会损失很多性能。若从右向左匹配,先找到所有的最右节点,对于每一个节点,向上寻找其父节点直到找到根元素或满足条件的匹配规则,则结束这个分支的遍历。两种匹配规则的性能差别很大,是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点),而从左向右的匹配规则的性能都浪费在了失败的查找上面。而在CSS解析完毕后,需要将解析的结果与DOM Tree的内容一起进行分析建立一棵 Render Tree,最终用来进行绘图。在建立Render Tree时浏览器就要为每个DOM Tree中的元素根据CSS的解析结果(Style Rules)来确定生成怎样的Render Tree。

15. CSS的性能优化方案

  • 层级尽量扁平,避免嵌套过多层级的选择器;
  • 使用特定的选择器,避免解析器过多层级的查找;
  • 减少使用通配符与属性选择器;
  • 减少不必要的多余属性;
  • 避免使用!important标识,可以选择其他选择器;
  • 实现动画时优先使用CSS3的动画属性,动画时脱离文档流,开启硬件加速;
  • 使用link标签代替@import;
  • 将渲染首屏内容所需的关键CSS内联到HTML中;
  • 使用资源预加载指令preload让浏览器提前加载CSS资源并缓存;
  • 使用Gulp,Webpack等构建工具对CSS文件进行压缩处理;

推荐阅读

记一次大厂的面试过程
装饰你的敲门砖,离大厂更近一步

交流

终于接近尾声了,居然花费掉了我一整个周末的时间,不过这篇主要是先总结一下CSS相关的知识点,当然还有很多地方没有总结到,只是列出了个人觉得比较容易考察的点,如果你有其他补充的,欢迎在下方留言区讨论哦,也欢迎关注我的公众号[前端之境],关注后我可以拉你加入微信前端交流群,我们一起互相交流学习,共同进步。
后续会陆续总结出JS方面、浏览器视角、算法基础和框架方面的内容,希望你能够喜欢!

css

相关推荐