- 一、CSS 基础
- 1. CSS 选择器及其优先级
- 2. CSS 中可继承与不可继承属性有哪些
- 3. display 的属性值及其作用
- 4. display 的 block、inline 和 inline-block 的区别
- 5. 隐藏元素的方法有哪些
- 6. link 和@import 的区别
- 7. transition 和 animation 的区别
- 8. display:none 与 visibility:hidden 的区别
- 9. 伪元素和伪类的区别和作用?
- 10. 对 requestAnimationframe 的理解
- 11. 对盒模型的理解
- 12. 为什么有时候⽤ translate 来改变位置⽽不是定位?
- 13. li 与 li 之间有看不见的空白间隔是什么原因引起的?如何解决?
- 14. CSS3 中有哪些新特性
- 15. 替换元素的概念及计算规则
- 16. 常见的图片格式及使用场景
- 17. 对 CSSSprites 的理解
- 18. 什么是物理像素,逻辑像素和像素密度,为什么在移动端开发时需要用到@3x, @2x 这种图片?
- 19. margin 和 padding 的使用场景
- 20. 对 line-height 的理解及其赋值方式
- 21. CSS 优化和提高性能的方法有哪些?
- 22. CSS 预处理器/后处理器是什么?为什么要使用它们?
- 23. ::before 和 :after 的双冒号和单冒号有什么区别?
- 24. display:inline-block 什么时候会显示间隙?
- 25. 单行、多行文本溢出隐藏
- 26. Sass、Less 是什么?为什么要使用他们?
- 27. 对媒体查询的理解?
- 28. 对 CSS 工程化的理解
- (1)预处理器:为什么要用预处理器?它的出现是为了解决什么问题?
- (2)PostCss:PostCss 是如何工作的?我们在什么场景下会使用 PostCss?
- (3)Webpack 能处理 CSS 吗?如何实现? Webpack 能处理 CSS 吗:
- 29. 如何判断元素是否到达可视区域
- 30. z-index 属性在什么情况下会失效
- 31. CSS3 中的 transform 有哪些属性
- 二、页面布局
- 1. 常见的 CSS 布局单位
- 2. px、em、rem 的区别及使用场景
- 3. 两栏布局的实现
- 4. 三栏布局的实现
- 5. 水平垂直居中的实现
- 6. 如何根据设计稿进行移动端适配?
- 7. 对 Flex 布局的理解及其使用场景
- 8. 响应式设计的概念及基本原理
- 三、定位与浮动
- 1. 为什么需要清除浮动?清除浮动的方式
- 2. 使用 clear 属性清除浮动的原理?
- 3. 对 BFC 的理解,如何创建 BFC
- 4. 什么是 margin 重叠问题?如何解决?
- 5. 元素的层叠顺序
- 6. position 的属性有哪些,区别是什么
- 7. display、float、position 的关系
- 8. absolute 与 fixed 共同点与不同点
- 9. 对 sticky 定位的理解
- 四、场景应用
整理了一下高频的前端面试题,分享给大家一起来学习。面试前看看还是有些帮助的,也可以当做前端复习,让大家查漏补缺,如有问题,欢迎留言指正!
一、CSS 基础
1. CSS 选择器及其优先级
选择器 | 格式 | 优先级权重 |
---|---|---|
id 选择器 | #id | 100 |
类选择器 | #classname | 10 |
属性选择器 | a[ref=“eee”] | 10 |
伪类选择器 | li:last-child | 10 |
标签选择器 | div | 1 |
伪元素选择器 | li:after | 1 |
相邻兄弟选择器 | h1+p | 0 |
子选择器 | ul>li | 0 |
后代选择器 | li a | 0 |
通配符选择器 | * | 0 |
对于选择器的优先级:
- 标签选择器、伪元素选择器:1
- 类选择器、伪类选择器、属性选择器:10
- id 选择器:100
- 内联样式:1000
注意事项:
!important
声明的样式的优先级最高;- 如果优先级相同,则最后出现的样式生效;
- 继承得到的样式的优先级最低;
- 通用选择器(*)、子选择器(>)和相邻同胞选择器(+)并不在这四个等级中,所以它们的权值都为 0 ;
- 样式表的来源不同时,优先级顺序为:内联样式 > 内部样式 > 外部样式 > 浏览器用户自定义样式 > 浏览器默认样式。
2. CSS 中可继承与不可继承属性有哪些
一、无继承性的属性
- display:规定元素应该生成的框的类型
- 文本属性:
vertical-align
:垂直文本对齐text-decoration
:规定添加到文本的装饰text-shadow
:文本阴影效果white-space
:空白符的处理unicode-bidi
:设置文本的方向
- 盒子模型的属性:
width
、height
、margin
、border
、padding
- 背景属性:
background
、background-color
、background-image
、background-repeat
、background-position
、background-attachment
- 定位属性:
float
、clear
、position
、top
、right
、bottom
、left
、min-width
、min-height
、max-width
、max-height
、overflow
、clip
、z-index
- 生成内容属性:
content
、counter-reset
、counter-increment
- 轮廓样式属性:
outline-style
、outline-width
、outline-color
、outline
- 页面样式属性:
size
、page-break-before
、page-break-after
- 声音样式属性:
pause-before
、pause-after
、pause
、cue-before
、cue-after
、cue
、play-during
二、有继承性的属性
- 字体系列属性
font-family
:字体系列font-weight
:字体的粗细font-size
:字体的大小font-style
:字体的风格
- 文本系列属性
text-indent
:文本缩进text-align
:文本水平对齐line-height
:行高word-spacing
:单词之间的间距letter-spacing
:中文或者字母之间的间距text-transform
:控制文本大小写(就是 uppercase、lowercase、capitalize 这三个)color
:文本颜色
- 元素可见性
visibility
:控制元素显示隐藏
- 列表布局属性
list-style
:列表风格,包括 list-style-type、list-style-image 等
- 光标属性
cursor
:光标显示为何种形态
3. display 的属性值及其作用
属性值 | 作用 |
---|---|
none | 元素不显示,并且会从文档流中移除。 |
block | 块类型。默认宽度为父元素宽度,可设置宽高,换行显示。 |
inline | 行内元素类型。默认宽度为内容宽度,不可设置宽高,同行显示。 |
inline-block | 默认宽度为内容宽度,可以设置宽高,同行显示。 |
list-item | 像块类型元素一样显示,并添加样式列表标记。 |
table | 此元素会作为块级表格来显示。 |
inherit | 规定应该从父元素继承 display 属性的值。 |
4. display 的 block、inline 和 inline-block 的区别
(1)block: 会独占一行,多个元素会另起一行,可以设置width
、height
、margin
和padding
属性;
(2)inline: 元素不会独占一行,设置width
、height
属性无效。但可以设置水平方向的margin
和padding
属性,不能设置垂直方向的padding
和margin
;
(3)inline-block: 将对象设置为inline
对象,但对象的内容作为block
对象呈现,之后的内联对象会被排列在同一行内。
对于行内元素和块级元素,其特点如下:
(1)行内元素
- 设置宽高无效;
- 可以设置水平方向的
margin
和padding
属性,不能设置垂直方向的padding
和margin
; - 不会自动换行;
(2)块级元素
- 可以设置宽高;
- 设置
margin
和padding
都有效; - 可以自动换行;
- 多个块状,默认排列从上到下。
5. 隐藏元素的方法有哪些
- display: none:渲染树不会包含该渲染对象,因此该元素不会在页面中占据位置,也不会响应绑定的监听事件。
- visibility: hidden:元素在页面中仍占据空间,但是不会响应绑定的监听事件。
- opacity: 0:将元素的透明度设置为 0,以此来实现元素的隐藏。元素在页面中仍然占据空间,并且能够响应元素绑定的监听事件。
- position: absolute:通过使用绝对定位将元素移除可视区域内,以此来实现元素的隐藏。
- z-index: 负值:来使其他元素遮盖住该元素,以此来实现隐藏。
- clip/clip-path :使用元素裁剪的方法来实现元素的隐藏,这种方法下,元素仍在页面中占据位置,但是不会响应绑定的监听事件。
- transform: scale(0,0):将元素缩放为 0,来实现元素的隐藏。这种方法下,元素仍在页面中占据位置,但是不会响应绑定的监听事件。
6. link 和@import 的区别
两者都是外部引用 CSS 的方式,它们的区别如下:
link
是 XHTML 标签,除了加载 CSS 外,还可以定义 RSS 等其他事务;@import
属于 CSS 范畴,只能加载 CSS。link
引用 CSS 时,在页面载入时同时加载;@import
需要页面网页完全载入以后加载。link
是 XHTML 标签,无兼容问题;@import
是在 CSS2.1 提出的,低版本的浏览器不支持。link
支持使用 Javascript 控制 DOM 去改变样式;而@import
不支持。
7. transition 和 animation 的区别
- transition 是过度属性,强调过度,它的实现需要触发一个事件(比如鼠标移动上去,焦点,点击等)才执行动画。它类似于 flash 的补间动画,设置一个开始关键帧,一个结束关键帧。
- animation 是动画属性,它的实现不需要触发事件,设定好时间之后可以自己执行,且可以循环一个动画。它也类似于 flash 的补间动画,但是它可以设置多个关键帧(用@keyframe 定义)完成动画。
8. display:none 与 visibility:hidden 的区别
这两个属性都是让元素隐藏,不可见。两者区别如下:
(1)在渲染树中
display:none
会让元素完全从渲染树中消失,渲染时不会占据任何空间;visibility:hidden
不会让元素从渲染树中消失,渲染的元素还会占据相应的空间,只是内容不可见。
(2)是否是继承属性
display:none
是非继承属性,子孙节点会随着父节点从渲染树消失,通过修改子孙节点的属性也无法显示;visibility:hidden
是继承属性,子孙节点消失是由于继承了hidden
,通过设置visibility:visible
可以让子孙节点显示;
(3)修改常规文档流中元素的 display
通常会造成文档的重排,但是修改visibility
属性只会造成本元素的重绘;
(4)如果使用读屏器,设置为display:none
的内容不会被读取,设置为visibility:hidden
的内容会被读取。
9. 伪元素和伪类的区别和作用?
- 伪元素:在内容元素的前后插入额外的元素或样式,但是这些元素实际上并不在文档中生成。它们只在外部显示可见,但不会在文档的源代码中找到它们,因此,称为“伪”元素。例如:
p::before {content:"第一章:";} p::after {content:"Hot!";} p::first-line {background:red;} p::first-letter {font-size:30px;}
- 伪类:将特殊的效果添加到特定选择器上。它是已有元素上添加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF} p:first-child {color: red}
总结: 伪类是通过在元素选择器上加⼊伪类改变元素状态,⽽伪元素通过对元素的操作进⾏对元素的改变。
10. 对 requestAnimationframe 的理解
实现动画效果的方法比较多,Javascript 中可以通过定时器 setTimeout
来实现,CSS3 中可以使用 transition
和 animation
来实现,HTML5 中的 canvas 也可以实现。除此之外,HTML5 提供一个专门用于请求动画的 API,那就是 requestAnimationFrame
,顾名思义就是请求动画帧。
MDN 对该方法的描述:
window.requestAnimationFrame()
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
语法: window.requestAnimationFrame(callback);
其中,callback 是下一次重绘之前更新动画帧所调用的函数(即上面所说的回调函数)。该回调函数会被传入 DOMHighResTimeStamp 参数,它表示requestAnimationFrame()
开始去执行回调函数的时刻。该方法属于宏任务,所以会在执行完微任务之后再去执行。
取消动画: 使用cancelAnimationFrame()
来取消执行动画,该方法接收一个参数——requestAnimationFrame
默认返回的 id,只需要传入这个 id 就可以取消动画了。
优势:
- CPU 节能:使用
SetTinterval
实现的动画,当页面被隐藏或最小化时,SetTinterval
仍然在后台执行动画任务,由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,完全是浪费 CPU 资源。而RequestAnimationFrame
则完全不同,当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统走的RequestAnimationFrame
也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了 CPU 开销。 - 函数节流:在高频率事件( resize, scroll 等)中,为了防止在一个刷新间隔内发生多次函数执行,
RequestAnimationFrame
可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销,一个刷新间隔内函数执行多次时没有意义的,因为多数显示器每 16.7ms 刷新一次,多次绘制并不会在屏幕上体现出来。 - 减少 DOM 操作:
requestAnimationFrame
会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒 60 帧。
setTimeout 执行动画的缺点:它通过设定间隔时间来不断改变图像位置,达到动画效果。但是容易出现卡顿、抖动的现象;原因是:
settimeout
任务被放入异步队列,只有当主线程任务执行完后才会执行队列中的任务,因此实际执行时间总是比设定时间要晚;settimeout
的固定时间间隔不一定与屏幕刷新间隔时间相同,会引起丢帧。
11. 对盒模型的理解
CSS3 中的盒模型有以下两种:标准盒子模型、IE 盒子模型。
这就意味着设置的 1px CSS 像素,在这个设备上实际会用 2 个物理像素单元来进行渲染,所以实际看到的一定会比 1px 粗一些。 解决 1px 问题的三种思路:
思路一:直接写 0.5px
如果之前 1px 的样式这样写:
border:1px solid #333
可以先在 JS 中拿到 window.devicePixelRatio
的值,然后把这个值通过 JSX 或者模板语法给到 CSS 的 data 里,达到这样的效果(这里用 JSX 语法做示范):
<div id="container" data-device={{window.devicePixelRatio}}></div>
然后就可以在 CSS 中用属性选择器来命中 devicePixelRatio
为某一值的情况,比如说这里尝试命中 devicePixelRatio
为 2 的情况:
#container[data-device="2"] { border:0.5px solid #333 }
直接把 1px 改成 1/devicePixelRatio
后的值,这是目前为止最简单的一种方法。这种方法的缺陷在于兼容性不行,IOS 系统需要 8 及以上的版本,安卓系统则直接不兼容。
思路二:伪元素先放大后缩小
这个方法的可行性会更高,兼容性也更好。唯一的缺点是代码会变多。
思路是先放大、后缩小:在目标元素的后面追加一个 ::after
伪元素,让这个元素布局为 absolute
之后、整个伸展开铺在目标元素上,然后把它的宽和高都设置为目标元素的两倍,border
值设为 1px。接着借助 CSS 动画特效中的放缩能力,把整个伪元素缩小为原来的 50%。此时,伪元素的宽高刚好可以和原有的目标元素对齐,而 border
也缩小为了 1px 的二分之一,间接地实现了 0.5px 的效果。
代码如下:
#container[data-device="2"] { position: relative; } #container[data-device="2"]::after{ position:absolute; top: 0; left: 0; width: 200%; height: 200%; content:""; transform: scale(0.5); transform-origin: left top; box-sizing: border-box; border: 1px solid #333; } }
思路三:viewport 缩放来解决
这个思路就是对 meta 标签里几个关键属性下手:
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
这里针对像素比为 2 的页面,把整个页面缩放为了原来的 1/2 大小。这样,本来占用 2 个物理像素的 1px 样式,现在占用的就是标准的一个物理像素。根据像素比的不同,这个缩放比例可以被计算为不同的值,用 js 代码实现如下:
const scale = 1 / window.devicePixelRatio; // 这里 metaEl 指的是 meta 标签对应的 Dom metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
这样解决了,但这样做的副作用也很大,整个页面被缩放了。这时 1px 已经被处理成物理像素大小,这样的大小在手机上显示边框很合适。但是,一些原本不需要被缩小的内容,比如文字、图片等,也被无差别缩小掉了。