1. CSS选择器及其优先级
!important > 行内样式 > id选择器 > 类/伪类/属性选择器 > 标签/伪元素选择器 > 子/后台选择器 > *通配符
2. 重排和重绘是什么?浏览器的渲染机制是什么?
重排(回流):当增加或删除dom节点,或者给元素修改宽高时,会改变页面布局,那么就会重新构造dom树,然后再次渲染。
重绘:计算好盒模型的位置,大小和其他一些属性之后,浏览器就会根据每个盒模型的特性进行绘制。
浏览器的渲染机制:当dom的大小,位置发生改变时进行重排,当dom的样式如color、background-color
改变时进行重绘。
3. display有哪些属性值
属性值 | 作用 |
---|---|
none | 元素不显示,并且会从文档流中移除 |
block | 块类型,默认宽度为父元素宽度,可设置宽高,换行显示 |
inline | 行内元素类型,默认宽度为内容宽度,不可设置宽高,同行显示 |
inline-block | 默认宽度为内容宽度,可设置宽高,同行显示 |
table | 此元素会作为块级表格来显示,子元素可设置display:table-row、table-cell 等 |
flex | flex布局 |
grid | 网格布局 |
inherit | 规定应该从父元素继承display属性的值 |
网格布局笔记:网格布局
表格布局可以看下面代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
.table {
display: table; /* 表格 */
width: 800px;
height: 500px;
margin: 20px auto;
border: 3px solid #000;
}
.row {
display: table-row; /* 表格行 */
}
.cell {
display: table-cell; /* 表格单元 */
border: 1px solid #000;
}
</style>
</head>
<body>
<div class="table">
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
</div>
<div class="row">
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
</div>
</body>
</html>
结果如下:
4. display的block、inline和inline-block的区别
block
:独占一行,宽度继承至父盒子,多个元素会另起一行,可设置宽高以及margin
和padding
属性。
inline
:元素不会独占一行,宽度、高度由内容撑开,不可设置宽高,但可以设置水平方向的margin
和padding
。
inline-block
:行内块,将对象设置为inline对象,但对象的内容作为block对象呈现,也就是说内容排列在一行内显示,但是可以设置宽高。
5. 隐藏的元素的方法有哪些
- display: none
- visibility: hidden
- opacity: 0
- position: absolute 移到可视区之外
- z-index: 负值 定位的前提下,使其他元素盖住该元素,以此实现隐藏
- transform:scale(0, 0) 将元素缩放为0,来实现元素的隐藏,元素仍占据位置。
6. link和@import的区别
两者都是外部引用css的方式,他们的区别如下:
- 功能上:link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务,@import属于CSS范畴,只能加载CSS
- 效果上:link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载
- 兼容性上:link是XHTML标签,没有兼容性问题;@import是CSS2.1提出的,低版本浏览器不支持
- js支持上:link支持使用js控制dom去改变样式;而@import不支持
7. transition和animation的区别
- transition是过渡属性,强调过渡,它的实现需要触发一个事件(比如鼠标移动上去,焦点,点击等)才执行动画,类似于flash的补间动画,设置一个开始关键帧,一个结束关键帧
- animation是动画属性,它的实现不需要触发事件,设定好时间之后可以自己执行,且可以循环一个动画,它也类似于flash的补间动画,但是它可以设置多个关键帧(用@keyframe定义)完成动画。
8. display:none和visibility:hidden的区别
- 渲染树上:display:none会让元素从渲染树中消失,渲染时不会占据任何空间,visibility:hidden会占据空间,只是不可见
- 是否是继承属性:display是非继承属性,子孙节点会随父节点消失,修改显示子孙节点的属性也无法显示,而visibility是继承属性,子孙节点消失是因为子孙节点从父节点继承了hidden,通过设置子孙节点visibility:visible可以让子孙节点显示。
- 重排与重绘:修改常规文档流的display通常会造成文档的重排,但是修改visibility只会造成重绘
- 读屏器:如果使用读屏器,设置display:none的内容不会被读取,而visibility:hidden可以被读取
9. li与li之间有看不见的空白间隔是什么原因引起的?如何解决?
li原本是块级标签,如下图
但当li设置为行内块元素或行元素时,li标签与li标签之间会有看不见的空隙,如下图:
原因:当元素是行内元素/行内块元素排版时,浏览器会将元素之间的空白符,如空格,换行,tab等渲染成一个空格处理,上图的换行就被渲染成了空格,因此会有上面的结果。
解决方案:
- li设置为float:left,缺点:很多容器是不适合设置浮动,并且浮动会将display变为block。
- 将所有li写在一行,比较简单粗暴的方法,但是代码会不太美观
- ul内的字符尺寸设置为0,缺点:可能会影响到其他字符,其他字符需要额外重新设置font-size
- 设置ul的字符间隔letter-spacing: -8px,缺点跟上条一样
10. 什么是物理像素、逻辑像素、像素密度,为什么移动端开发要用到@2x、@3x的图片
物理像素(physical pixel):又叫设备像素,是显示屏幕上的实际物理点,它是显示设备的最小可控制单元,我们常说的1920×1080像素分辨率就是用的物理像素。
逻辑像素(device independent pixel):又叫设备独立像素,与设备无关的逻辑像素,代表可以通过程序控制使用的虚拟像素,是一个总体概念,包含了css像素。
逻辑像素就是在物理像素的基础上人为定义的一层逻辑像素,举个例子,一个屏幕的物理像素是2560×1440,但是我们可以人为的定义定义这个屏幕就是1280×720,所以1个逻辑像素就用4个设备像素显示。
传统的pc屏幕,1个逻辑像素就等于1个物理像素,但是市面上有很多高清屏幕,比如苹果的Retina屏幕,高清就是因为这种屏幕1个逻辑像素点使用多个物理像素显示,所以高清屏的画质就更加锐利,没有颗粒感,显示效果出众。
像素密度通常使用dpr(设备像素比device pixel ratio)来表示,dpr = 物理像素 / 逻辑像素,传统的pc屏幕dpr是1,像上面所的苹果Retina高清屏幕dpr是2。简单来说,设备像素比dpr的意义在于规定设备以多少个物理像素来显示1px的css像素。
@2x、@3x在移动端开发中,不同设备有不同的dpr,为了确保在不同设备上显示的图像保持一致的视觉效果,引入了倍图的概念,其中@2x和@3x是两个常见的倍图标识。
为什么Retina上使用@1x的图片会模糊?
举个例子,一张375px*200px
的一倍位图,其拥有375*200=75000
个位图像素,如果我们在常规pc屏(dpr=1)上看这张图,将会以375*200=75000
个物理像素来显示,因此在pc上显示的清晰度不变。那么,如果在Retina屏(dpr=2)上预览这张图片,将会以375*200*4=300000
个物理像素来显示这张图片,而实际上这张一倍位图转换成物理像素只有375*200=75000
个有效物理像素,不足以填充300000
个物理像素,因此剩下的300000-75000=225000
个物理像素将采用就近取色的填充的方法来显示图片,这也是造成图片模糊的原因,下面这张图片解释的十分形象:
因此使用375px*200px
的二倍图,在Retina(dpr=2)屏上会转换为375*200*4=300000
个物理像素来正常填充300000
个物理像素,才不会出现图片模糊的情况。
浏览器打开控制台,输入:devicePixelRatio
后回车,可以查看当前屏幕的dpr。
11. 谈谈你对CSSSprites的理解
CSSSprites精灵图,将一个页面涉及到的所有图片都包含到一张大图中去,然后利用CSS的background-image,background-repeat,background-position
属性进行背景定位。
优点:
- 性能方面:能够很好的减少网页的http请求,从而大大提高了页面的性能,这是最大的优点。
- 存储方面:能减少图片的字节,把3张图片合成1张图片的字节总是小于这3张图片的字节总和。
缺点:
- 设计方面:在图片合并时,要把多张图片有序、合理的合并成一张图片,还要留好足够的空间,防止板块内出现不必要的背景,相对麻烦
- 程序猿开发方面:雪碧图在开发的时候相对来说麻烦,需要借助photoshop或其他工具来对每个背景单元测量其准确的位置
- 维护方面:维护就更麻烦了,页面背景有少许改动就要改这整个合并的图片,很容易影响无需改动的地方,如果在原来的地方放不下,就只能往下加图片,这样图片的字节增加了,还要改动css。
12. CSS优化和提高性能的方法有哪些?
加载性能
- css单一样式:举个例子,当需要使用下边距和左边距的时候,推荐使用
margin-bottom:10px;margin-left:10px;
,而不是margin: 0 0 10px 10px
,因为前者执行效率会更高。 - 减少使用
@import
,建议使用link
标签,因为link标签引入css资源时,会在页面加载时一起加载,而@import
需要等待页面加载完成后再进行加载,也就是说link是并行加载的,而@import是串行加载的,因此使用link加载性能更好。 - css压缩:将写好的css进行打包压缩,可以减小文件体积。
选择器性能
- 如果规则拥有ID选择器作为其关键选择器(选择器的最后面的部分为关键选择器,即用来匹配目标元素的部分),则不要为规则增加其他标签,这样就能过滤掉无法规则,样式系统就不会浪费时间去匹配它们了
- 避免使用通配符*规则,因为
*{}
计算次数惊人,只对需要用到的元素进行选择就行 - 尽量少的去对标签进行选择,而是用class,使用标签计算量太大了
- 了解哪些属性是可以通过继承而来的,然后避免对这些属性重复指定规则
渲染性能
- 慎重使用高性能属性:浮动、定位
- 尽量减少页面的重排和重绘
- 去除空规则,减少css文档体积
- 不使用@import,它会影响css的加载速度
- 合理使用雪碧图
可维护性、健壮性
- 将具有相同属性的样式抽离出来,整合并通过class在页面中使用,提高css的可维护性
- 样式与内容分离,将css代码定义到外部css中
13. CSS预处理用过吗
如less,sass,它们为css增加了一些编程特性,可以在css中使用变量,简单的逻辑程序等。层级,混入mixin,变量,循环,函数等对编写以及开发ui组件都极为方便
优点:
- 结构清晰,便于扩展
- 可以轻松实现多重继承
- 完美兼容css代码,可以用在老项目中
- 可以很方便的屏蔽浏览器私有语法的差异
14. 谈谈你对媒体查询的理解
媒体查询(media queries)是一种css3的技术,用于根据设备的特性和属性来应用不同的样式规则,通过媒体查询,可以使网页在不同的设备上或不同的浏览器条件下采用不同的样式表,从而实现响应式设计,提供更好的用户体验。
link元素中使用css媒体查询
当视口宽度小于等于800px时应用的样式
<link ref="stylesheet" media="(max-width: 800px)" href="example.css"/>
样式表中使用css媒体查询
-
媒体类型(media type):指定样式规则适用的设备类型,如all:适用于所有设备,screen:适用于屏幕(电脑、平板、手机等),print:适用于打印机和打印机预览,speech:适用于语音设备(屏幕阅读器等),默认是all
@media screen { /* 样式规则适用于屏幕设备 */ /* ... */ }
-
媒体特性(media feature):包括视口宽度、设备宽度、分辨率等,用于根据设备属性应用样式。
@media screen and (max-width: 600px) { /* 当视口宽度小于等于600px时应用的样式 */ /* ... */ }
-
逻辑运算符:可以使用逻辑运算符如
and or not
来组合多个媒体查询条件@media (min-width: 600px) and (max-width: 1200px) { /* 当视口宽度在600px~1200px的范围内应用的样式 */ /* ... */ }
15. 常用页面布局的代码实现
1. 两栏布局
一般的两栏布局指的是左边一栏宽度固定,右边一栏宽度自适应。
实现方法1:利用浮动,左边盒子设置宽度,并设置向左浮动,右边盒子使用margin-left左边盒子宽度,宽度设不用设置,因为block盒子默认宽度为auto自动撑满父盒子
<style>
* {
margin: 0;
padding: 0;
}
.outer {
height: 100vh;
}
.left {
/* 核心代码 */
float: left;
width: 100px;
height: 100%;
background-color: tomato;
}
.right {
/* 核心代码 */
margin-left: 100px;
height: 100%;
background-color: gold;
}
</style>
<body>
<div class="outer">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
结果如下:
实现方法2:使用flex布局,左侧固定宽度,右侧设置flex:1
<style>
* {
margin: 0;
padding: 0;
}
.outer {
height: 100vh;
/* 核心代码 */
display: flex;
}
.left {
width: 100px;
height: 100%;
background-color: tomato;
}
.right {
/* 核心代码 */
flex: 1;
height: 100%;
background-color: gold;
}
</style>
实现方法3:利用浮动,左侧宽度固定,并左浮动,右侧设置overflow:hidden,这样右边就触发了BFC,BFC的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠
<style>
* {
margin: 0;
padding: 0;
}
.outer {
height: 100vh;
}
.left {
float: left;
width: 100px;
height: 100%;
background-color: tomato;
}
.right {
overflow: hidden;
height: 100%;
background-color: gold;
}
</style>
实现方法4:父盒子相对定位,左侧盒子绝对定位并固定宽度,右侧盒子margin-left左侧盒子宽度
或者左侧盒子固定宽度,右侧盒子绝对定位,并left:左侧盒子宽度。
<style>
* {
margin: 0;
padding: 0;
}
.outer {
height: 100vh;
position: relative;
}
.left {
position: absolute;
width: 100px;
height: 100%;
background-color: tomato;
}
.right {
margin-left: 100px;
height: 100%;
background-color: gold;
}
</style>
2. 三栏布局(圣杯布局)
三栏布局,又叫圣杯布局,一般指的是页面中一共有三栏,左右两栏宽度固定,中间自适应的布局。
方法1:flex布局
<style>
* {
margin: 0;
padding: 0;
}
.outer {
height: 100vh;
display: flex;
}
.left {
width: 100px;
height: 100%;
background-color: tomato;
}
.right {
width: 100px;
height: 100%;
background-color: gold;
}
.center {
flex: 1;
height: 100%;
background-color: black;
}
</style>
<body>
<div class="outer">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
</body>
方法2:定位,外部盒子设置左右盒子宽度的padding并设置相对定位,左右盒子设置绝对定位,左盒子定位在左,右盒子定位在右
或者外部盒子不设padding,中间盒子设置margin
<style>
* {
margin: 0;
padding: 0;
}
.outer {
height: 100vh;
padding: 0 100px;
position: relative;
}
.left {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100%;
background-color: tomato;
}
.right {
position: absolute;
top: 0;
right: 0;
width: 100px;
height: 100%;
background-color: gold;
}
.center {
width: 100%;
height: 100%;
background-color: black;
}
</style>
16. 谈谈你对BFC的理解,以及如何创建BFC
BFC容器通常是指“块级格式化上下文容器(Block Formatting Context Container)”,它是CSS中用来管理和控制元素在页面上布局和排列的一种机制,它会形成独立的渲染区域,从而使内部元素的渲染不会影响到外界。
下面我们通过例子来简单理解一下什么叫做内部元素不会影响到外界
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>bfc容器</title>
<style>
img {
/* float: left; */
}
/* .bfc {
overflow: hidden;
} */
</style>
</head>
<body>
<div class="outer bfc">
<img src="./img.png" alt="">
<p>这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本这是一段文本</p>
</div>
</body>
</html>
运行如上代码可以看到:
我们如何实现文字围绕图片渲染呢?
我们可以使用浮动来实现,浮动产生的目的最初就是为了做文字环绕效果,浮动的元素会压住标准流的盒子,和定位比较像,但是浮动和定位有区别,浮动的元素不会压住标准流的文字,图片,而固定定位、决定定位会压住标准流的所有内容,包括文字及图片
下面我们来试试浮动的效果:我们取消上述代码的浮动注释,得到下面效果:
但是我们打开开发者工具查看页面元素,会发现一个问题,父盒子的高度并没有被子元素img撑开,如下图:
也就是说子元素img高度已经在父盒子外面了,这就是上面所说的内部元素影响到外界,造成这种情况的原因是:对子元素设置浮动后,它脱离了父元素的文档流,因此父元素高度并不会受这个子元素的影响,这就是常说的高度塌陷问题,我们可以使用BFC容器来解决此问题,下面我们取消上面代码中bfc类的注释,再看看结果如下:
可以看到高度塌陷问题得到解决,内部元素将不会影响到父元素以外的元素,它只会影响父元素。
下面我们详细介绍BFC。
BFC除了拥有内部元素不会影响到外部元素特性,还有许多其他实用的特性,下面汇总了BFC的所有特性:
- BFC是独立的容器,容器内部的元素不会影响到外部元素
- BFC区域不会与浮动的容器发生重叠
- BFC和文档流的排列方式一致,垂直方向上,自上而下排列
形成BFC的条件:
-
元素设置overflow:overflow不是visible的值,如hidden,auto,scroll。上面代码的bfc类就是用的hidden
-
元素设置浮动:float除了none以外的值
-
元素设置定位:position设置absolute或者fixed
-
元素设置display:flex,inline-block,table-cell等
BFC的作用:
-
解决高度塌陷问题(也可以说是清除浮动):在对子元素设置浮动后,父元素会发生高度塌陷,也就是父元素的高度不会被这个设置了浮动的元素撑开。
-
解决margin的重叠问题:由于BFC是一个独立的区域,内部的元素和外部的元素互不影响,将两个元素变成两个BFC,就解决了margin重叠问题。
-
创建自适应的两栏布局:左边盒子宽度固定,右边盒子设置
overflow:hidden
使盒子变成bfc盒子,bfc的区域不会与浮动元素发生重叠,所以两侧不会发生重叠,实现了自适应两栏布局。.left { width: 100px; height: 200px; background: tomato; float: left; } .right { height: 300px; background: gold; overflow: hidden; } <div class="left"></div> <div class="right"></div>
17. 什么是margin重叠问题?以及如何解决margin重叠问题
两个块级元素的上外边距和下外边距可能会合并(重叠)为一个外边距,其大小会取其中外边距值大的那个(如果两个边距都为正值的话),这种结果就是外边距重叠。另外,margin重叠只会出现在垂直方向上。
需要注意的是:浮动和绝对定位这种脱离文档流的元素的外边距不会折叠。
计算原则:
-
如果两者都是正数,那么就取最大值
-
如果是一正一负,就会取正值减去负值的绝对值
-
两个都是负值时,用0减去两个中绝对值大的那个
解决办法:
对于折叠的情况,主要有两种:
-
兄弟盒子间重叠(经实测,下面方式只有在两个margin都为正值时才生效,存在负值不生效)
-
底部元素变成行内盒子:
display:inline-block
【也就是底部盒子变bfc】 -
底部元素设置浮动:
float: left
除了none
【也就是底部盒子变bfc】 -
底部元素设置绝对或固定定位:
position: absolute/fixed
【也就是底部盒子变成bfc】综上所述,只要把底部盒子变成bfc即可。
-
-
父子盒子间重叠
- 父盒子加入:
overflow: hidden
【即父盒子变bfc】 - 父盒子变成行内盒子:
display: inline-block
【即父盒子变bfc】 - 父盒子增加边框:
border: 1px solid transparent
- 子盒子变成行内盒子:
display: inline-block
【即子盒子变bfc】 - 子盒子设置定位:
position: absolute/fixed
【即子盒子变bfc】 - 子盒子设置浮动:
float: left
除none
均可【即子盒子变bfc】
- 父盒子加入:
18. absolute与fixed定位的共同点和区别有哪些
共同点:
-
都使文档脱离文档流不再占据文档物理空间
-
都改变行内元素的呈现方式,将
display
自动设置为inline-block
-
覆盖非定位文档元素
不同点:
- absolute与fixed的根元素不同,absolute的根元素可以设置,fixed根元素固定为浏览器。
- 在有滚动条的页面,absolute会跟着父元素进行移动,而fixed始终固定在页面的具体位置。
19. 谈谈你对sticky定位的理解
粘性定位通俗来说,它就是相对定位relative和固定定位fixed的结合体,在最近可滚动容器没有触发滑动之前,sticky盒子的表现为相对定位relative【第一阶段】,但当最近可滚动容器触发滚动,父元素出现在最近可滚动容器的可视区并且滚动距离达到粘性定位sticky的要求时(比如top: 100px),sticky盒子的表现为固定定位fixed【第二阶段】,接着滚动,当sticky盒子的父元素消失在最近可滚动容器的可视区时,sticky盒子会重新表现为相对定位relative【第三阶段】,也就是说它不再固定,会随着父元素消失在最近可滚动容器的可视区。
结合上面的描述,我们可以总结粘性定位的位置受两个东西的影响:
- 父元素:父盒子不在最近可滚动容器可视区时,sticky盒子始终表现为相对定位。
- 最近可滚动的容器:设置sticky时使用的top、left等属性是相对的就是可滚动的容器,只要容器的overflow不是visible【容器不设置overflow就默认是visible】那么容器就是可滚动容器,如果盒子的祖先们没找到可滚动容器,那么body就作为可滚动容器,因为body是默认可滚动的。
下面我们结合代码来理解:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>margin重叠问题</title>
<style>
* {
padding: 0;
margin: 0;
}
.parent {
width: 400px;
height: 600px;
background-color: tomato;
overflow: visible;
}
.sticky {
width: 200px;
height: 200px;
background-color: gold;
/* 粘性定位 */
position: sticky;
top: 0px;
}
.box-top,
.box-bot {
width: 400px;
background-color: pink;
}
.box-top {
height: 200px;
}
.box-bot {
height: 1000px;
}
</style>
</head>
<body>
<div class="box-top"></div>
<div class="parent">
<div class="sticky">吸顶盒子</div>
</div>
<div class="box-bot"></div>
</body>
</html>
sticky失效情况有:
- 未指定top、right、bottom或left其中的一个
- 父元素的高度小于sticky元素
- 没有找准sticky元素需要参考的最近可滚动元素
- 如果参考的可滚动元素是body,那么父元素的overflow必须是visible,不能是其他任意值
参考博客:position:sticky失效问题剖析
参考视频:[粘性定位](