前端面试题系列文章:
- 【1】备战前端实习面试之HTML篇
- 【2】备战前端实习面试之CSS篇
- 【3】备战前端实习面试之JavaScript篇
- 【4】备战前端实习面试之React篇
- 【5】备战前端实习面试之Vue篇
- 【6】备战前端实习面试之Node.js篇
- 【7】备战前端实习面试之浏览器篇
- 【8】备战前端实习面试之性能优化篇
- 【9】备战前端实习面试之计算机网络篇
- 【10】备战前端实习面试之手写代码篇
- 【11】备战前端实习面试之代码输出结果篇
CSS
一、盒模型
每个标签都是一个盒模型,由四个部分组成,分别是 margin
、border
、padding
、content
。
而盒模型分为两种,分别是标准盒模型和怪异盒模型,其中
- 标准盒模型的宽高等于
content
,通过box-sizing: content-box
设置。 - 怪异盒模型的宽高等于
content + padding + border
,通过box-sizing: border-box
设置。
二、position 属性的值有哪些及其区别
- static(出现在正常的文档流中)
默认。位置设置为 static 的元素,它始终会处于页面流给予的位置(static 元素会忽略任何 top、bottom、left 或 right 声明)。 - relative(不脱离文档流)
发生偏移时的参照为 position 属性取 static 时盒子的位置 - absolute(脱离文档流)
元素相对于最近的非 static 定位的祖先元素发生偏移 - fixed(脱离文档流)
元素相对于屏幕视口(viewport)的位置来发生偏移, 元素的位置在屏幕滚动时不会改变。这一点与 absolute 不同,absolute 在屏幕滚动时会跟着一起滚动 - sticky
可以被认为是 relative 和 fixed 的混合,元素在跨越特定阈值前为相对定位,之后为固定定位: sticky 会让元素在页面滚动时如同在正常流中(relative定位),但当滚动到特定位置时就会固定在屏幕上如同 fixedsticky定位的阈值是相对它的最近滚动祖先来定义的,而 sticky 的作用区域也是它的第一个非static父元素内,也就是说粘性布局的效果只在该父元素内表现出来。
- inherit
规定从父元素继承position属性的值
三、浮动的脱离文档流和绝对定位的脱离文档流是一样的吗
浮动会使元素脱离文档流,但是不会脱离文本流,在于其他盒子的文本内容计算布局的时候,还是占位置的。
大盒子里包裹着使用 float: left
浮动的元素,其他小盒子会无视它,从浏览器左上角开始布局,但大盒子内的文本依旧会为浮动元素让出位置,这就导致了“字围”现象。
绝对定位会使元素脱离文档流,同时也会脱离文本流,在于其他盒子的文本内容计算布局的时候,不占位置。
使用绝对定义的元素,其他小盒子也会忽略它,但大盒子内的文本不同于浮动的脱离文档流,而是会忽略浮动的元素,因此文字会与浮动元素重叠。
四、讲讲 BFC
BFC(块级格式化上下文)是一个独立的布局环境,可以理解为一个容器,这个容器有它自己的布局规则,布局时不会影响外界,同时也不受外部影响。
BFC 的布局规则:
- 内部的盒子会在垂直方向上自上而下地排列,和文档流的排列方式一致。
- 盒子垂直方向的距离由
margin
决定。属于同一个 BFC 的两个相邻盒子的margin
会发生重叠。 - 计算BFC的高度时,浮动元素也参与计算。
- 每个元素的左
margin
值和容器的左border
相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 - BFC 的区域不会与浮动的容器发生重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
BFC 的作用:
- 利用 BFC 避免 margin 重叠。
- 阻止元素被浮动元素覆盖
- 可应用于自适应两栏布局(避免右侧与左侧发生重叠)
- 清除内部浮动
- 创建自适应两栏布局
触发 BFC 的条件:
- 根元素,即 HTML 元素(最大的一个 BFC)
float
的值不为none
position
的值为absolute
或fixed
display
的值为flex/inline-flex弹性元素
或grid/inline-grid网格元素
或inline-block行内块元素
或table-cell表格单元格
或table-caption表格标题
overflow
值不为visible
contain
值为layout
或content
或strict
如何解决 margin 重叠:
- 兄弟之间重叠(底部元素设置 BFC )
- 底部元素变为行内盒子:
display: inline-block
- 底部元素设置浮动:
float
- 底部元素的
position
的值为absolute/fixed
- 父子之间重叠
- 父元素加入:
overflow: hidden
- 父元素添加透明边框:
border:1px solid transparent
- 子元素变为行内盒子:
display: inline-block
- 子元素加入浮动属性或定位
五、为什么要清除浮动?清除浮动的方式?
清除浮动是为了清除使用浮动元素产生的影响。这个影响就是,浮动元素的高度会塌陷,而高度的塌陷使页面后面的布局不能正常显示。
清除浮动的五种方法:
- 给浮动的父元素设置宽高(不推荐,企业中一般不设宽高)
- 给要清除浮动的元素设置
clear: both
属性(但margin
属性会失效) - 隔墙法
- 外墙法:
- ①在两个盒子中间添加一个额外的块级元素
- ②给这个额外添加的块级元素设置
clear: both
- 注意:外墙法可以让第二个盒子使用
margin-top
属性,但不可以让第一个盒子使用margin-bottom
属性,因此直接给额外添加的块级元素设置宽高即可
- 内墙法:
- ①在第一个盒子中所有子元素最后添加一个额外的块级元素
- ②给这个额外添加的块级元素设置
clear: both
- 注意:内墙法可以让第二个盒子使用
margin-top
属性,也可以让第一个盒子使用margin-bottom
属性,因此直接给额外添加的块级元素设置宽高即可
- 外墙法和内墙法的区别:外墙法不能撑起第一个盒子的高度,而内墙法可以撑起第一个盒子的高度
- 给浮动的元素设置伪元素选择器
.box::after{ content: ""; /* 设置添加的子元素的内容为空 */ display: block; /* 设置添加的子元素为块级元素 */ height: 0; /* 设置添加的子元素的高度为0 */ visibility: hidden; /* 设置添加的子元素看不见 */ clear: both; /* 给添加的子元素 clear: both; */ } /* 注意:过去的浏览器不支持 CSS3 新特性,因此需要加上:*/ .box{ *zoom: 1; /* 兼容 IE 6 */ }
- 包含浮动元素的父级标签添加
overflow:hidden
或者overflow:auto
六、什么是伪类和伪元素?他们的作用和区别?
定义:
- 伪类:是以一个冒号(:)作为前缀,被添加到一个选择器末尾的关键字。
- 伪元素:是以两个冒号(::)作为前缀,同样是添加到选择器后面去选择某个元素的某个部分。
作用:
- 伪类:用于当已有的元素处于某个状态时,为其添加对应的样式,这个状态是根据用户行为而动态变化。
- 伪元素:用于创建一些不在文档树中的元素,并为其添加样式,但是这些元素实际上并不在文档中生成。
区别:
- 伪类:在某个状态给指定元素添加相应的样式时,它是已有元素上添加类别的,不会产生新的元素。
- 伪元素:在内容元素的前后插入额外的元素或样式,它们只在外部显示可见,但不会在文档的源代码中找到它们。
七、CSS3 的新特性
- 过渡
语法:
transition: transition-property
【CSS属性】,transition-duration
【花费时间】,transition-timing-function
【效果曲线(默认ease)】,transition-delay
【延迟时间(默认0)】。
// 连写(可以省略后面的两个参数):
transition:width, 5s, ease, 2s
transition-property: width;
transition-duration: 1s;
transition-timing-function: linear;
transition-delay: 2s;
transition-timing-function 的参数:
值 | 描述 |
---|---|
linear | 匀速(等于 cubic-bezier(0,0,1,1)) |
ease | 逐渐变慢(cubic-bezier(0.25,0.1,0.25,1)) |
ease-in | 加速(等于 cubic-bezier(0.42,0,1,1)) |
ease-out | 减速(等于 cubic-bezier(0,0,0.58,1)) |
ease-in-out | 先加速后减速(等于 cubic-bezier(0.42,0,0.58,1)) |
cubic-bezier(n,n,n,n) | 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值 |
- 动画
①animation:animation-name
【动画名称】,animation-duration
【一个周期花费时间】,animation-timing-function
【运动曲线(默认ease)】,animation-delay
【动画延迟(默认0)】,animation-fill-mode
,animation-direction
【是否反向播放动画(默认normal)】,animation-iteration-count
【播放次数(默认1)】,animation-play-state
【是否暂停动画(默认 running )】
②告诉系统外面需要自己创建一个名称叫做xxx的动画@keyframes 动画名称 { from { } to { } }
animation-name
规定动画的名称。由大小写敏感的字母a-z、数字0-9、下划线(_)和/
或横线(-)组成。第一个非横线字符必须是字母,数字不能在字母前面,不允许两个横线出现在开始位置animation-duration
规定动画完成一个周期所花费的秒或毫秒。默认是 0 ,表示无动画。animation-timing-function
规定动画的速度曲线。默认是 “ease”。可选参数如下:
值 | 描述 |
---|---|
linear | 动画从头到尾的速度是相同的。 |
ease | 默认。动画以低速开始,然后加快,在结束前变慢。 |
ease-in | 动画以低速开始。 |
ease-out | 动画以低速结束。 |
ease-in-out | 动画以低速开始和结束。 |
cubic-bezier(n,n,n,n) | 在 cubic-bezier 函数中自己的值。可能的值是从 0 到 1 的数值。 |
animation-delay
规定动画何时开始。默认是 0。animation-fill-mode
规定对象动画在执行之前和之后如何将样式应用于其目标。可选参数如下:
值 | 描述 |
---|---|
none | 默认状态,回到动画没开始时的状态。 |
forwards | 让动画停留在结束状态。 |
backwards | 让动画回到第一帧的状态。 |
both | 向前和向后填充模式都被应用。 |
animation-direction
规定动画是否在下一周期逆向地播放。默认是 “normal”。可选参数如下:- normal 默认值。动画正常播放。
- alternate 动画轮流反向播放。
- reverse 动画反向播放。
- alternate-reverse 动画反向轮流播放。
效果如图:
animation-iteration-count
规定动画被播放的次数。默认是 1。无限播放则是 infiniteanimation-play-state
规定动画是否正在运行或暂停。可以通过查询它来确定动画是否正在运行。另外,它的值可以被设置为暂停和恢复的动画的重放。默认是 “running”。可选参数如下:
值 | 描述 |
---|---|
paused | 规定动画已暂停。 |
running | 规定动画正在播放。 |
inherit | / |
initial | / |
unset | / |
- 形状转换
- transform-origin 定义形变点的位置。
- 2D transform 方法
translate(x,y) 定义 2D 转换,沿着 X 和 Y 轴移动元素。 translateX(n) 定义 2D 转换,沿着 X 轴移动元素。 translateY(n) 定义 2D 转换,沿着 Y 轴移动元素。 rotate(angle) 定义 2D 旋转,在参数中规定角度,参数为数值、单位 deg。 scale(x,y) 定义 2D 缩放转换,改变元素的宽度和高度,参数为数值、无单位。 scaleX(n) 定义 2D 缩放转换,改变元素的宽度。 scaleY(n) 定义 2D 缩放转换,改变元素的高度。 matrix(n,n,n,n,n,n) 定义 2D 转换,使用六个值的矩阵。 skew(x-angle,y-angle) 定义 2D 倾斜转换,沿着 X 和 Y 轴,参数为数值、单位 deg。 skewX(angle) 定义 2D 倾斜转换,沿着 X 轴。 skewY(angle) 定义 2D 倾斜转换,沿着 Y 轴。 x-axis 定义视图被置于 X 轴的何处。可能的值:left,center,right,length,% y-axis 定义视图被置于 Y 轴的何处。可能的值:top,center,bottom,length,% z-axis 定义视图被置于 Z 轴的何处。可能的值:length
- 3D Transform 方法
matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n) 定义 3D 转换,使用 16 个值的 4x4 矩阵。 translate3d(x,y,z) 定义 3D 转化。 translateX(x) 定义 3D 转化,仅使用用于 X 轴的值。 translateY(y) 定义 3D 转化,仅使用用于 Y 轴的值。 translateZ(z) 定义 3D 转化,仅使用用于 Z 轴的值。 scale3d(x,y,z) 定义 3D 缩放转换。 scaleX(x) 定义 3D 缩放转换,通过给定一个 X 轴的值。 scaleY(y) 定义 3D 缩放转换,通过给定一个 Y 轴的值。 scaleZ(z) 定义 3D 缩放转换,通过给定一个 Z 轴的值。 rotate3d(x,y,z,angle) 定义 3D 旋转。 rotateX(angle) 定义沿 X 轴的 3D 旋转。 rotateY(angle) 定义沿 Y 轴的 3D 旋转。 rotateZ(angle) 定义沿 Z 轴的 3D 旋转。 perspective(n) 定义 3D 转换元素的透视视图。 x-axis 定义视图被置于 X 轴的何处。可能的值:left,center,right,length,% y-axis 定义视图被置于 Y 轴的何处。可能的值:top,center,bottom,length,% z-axis 定义视图被置于 Z 轴的何处。可能的值:length transform-style 规定被嵌套元素如何在 3D 空间中显示。 flat 子元素将不保留其 3D 位置。 preserve-3d 子元素将保留其 3D 位置。 perspective 规定 3D 元素的透视效果(近大远小)。 number 元素距离视图的距离,以像素计。 none 默认值。与 0 相同。不设置透视。 perspective-origin 规定 3D 元素的底部位置。 x-axis 定义该视图在 x 轴上的位置。默认值:50%。可能的值:left,center,right,length,% y-axis 定义该视图在 y 轴上的位置。默认值:50%。可能的值:top,center,bottom,length,% backface-visibility 定义元素在不面对屏幕时是否可见。 visible 背面是可见的。 hidden 背面是不可见的。
阴影
box-shadow
:水平阴影的位置 垂直阴影的位置 模糊距离 阴影的大小 阴影的颜色 阴影开始方向(默认是从里往外,设置inset就是从外往里);边框图片
border-image
:图片url 图像边界向内偏移 图像边界的宽度(默认为边框的宽度) 用于指定在边框外部绘制偏移的量(默认0) 铺满方式–重复(repeat)、拉伸(stretch)或铺满(round)(默认:拉伸(stretch));边框圆角
border-radius
:左上角,右上角,右下角,左下角;背景
background-clip
规定背景的绘制区域- border-box 背景被裁剪到边框盒。
- padding-box 背景被裁剪到内边距框。
- content-box 背景被裁剪到内容框。
background-origin
- padding-box 背景图像相对于内边距框来定位。
- border-box 背景图像相对于边框盒来定位。
- content-box 背景图像相对于内容框来定位。
background-size
- length 设置背景图像的高度和宽度。第一个值设置宽度,第二个值设置高度。如果只设置一个值,则第二个值会被设置为 “auto”。
- percentage 以父元素的百分比来设置背景图像的宽度和高度。第一个值设置宽度,第二个值设置高度。如果只设置一个值,则第二个值会被设置为 “auto”。
- cover 把背景图像扩展至足够大,以使背景图像完全覆盖背景区域。背景图像的某些部分也许无法显示在背景定位区域中。
- contain 把图像图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域。
反射
-webkit-box-reflect
:方向【above-上 | below-下 | right-右 | left-左】,偏移量,遮罩图片文字阴影
text-shadow
:水平阴影,垂直阴影,模糊的距离,以及阴影的颜色颜色
rgba
(rgb为颜色值,a为透明度)hsla
(h:色相”,“s:饱和度”,“l:亮度”,“a:透明度”)渐变
Filter(滤镜)
- 黑白色 filter: grayscale(100%)
- 褐色 filter:sepia(1)
- 饱和度 saturate(2)
- 色相旋转 hue-rotate(90deg)
- 反色 filter:invert(1)
- 透明度 opacity(.5)
- 亮度 brightness(.5)
- 对比度 contrast(2)
- 模糊 blur(3px)
- 阴影 drop-shadow(5px 5px 5px #000)
混合模式
- background-blend-mode(用于同一个元素的背景图片和背景颜色)
- multiply 正片叠底
- screen 滤色
- overlay 叠加
- darken 变暗
- lighten 变亮
- color-dodge 颜色减淡模式
- color-burn 颜色加深
- hard-light 强光
- soft-light 柔光
- difference 差值
- exclusion 排除
- hue 色相
- saturation 饱和度
- color 颜色
- luminosity 亮度
- mix-blend-mode(用于一个元素的背景图片或者颜色和子元素)
- 数值同 background-blend-mode
- background-blend-mode(用于同一个元素的背景图片和背景颜色)
多列布局
加上私有前缀,兼容
- -webkit- (谷歌,Safari,新版Opera浏览器,以及几乎所有iOS系统中的浏览器(包括 iOS 系统中的火狐浏览器);基本上所有基于WebKit 内核的浏览器)
- -moz- (火狐浏览器)
- -o- (旧版Opera浏览器)
- -ms- (IE浏览器 和 Edge浏览器)
column-count 规定元素应该被分隔的列数。
column-fill 规定如何填充列。
column-gap 规定列之间的间隔。
column-rule 设置所有 column-rule-* 属性的简写属性。
column-rule-color 规定列之间规则的颜色。
column-rule-style 规定列之间规则的样式
column-rule-width 规定列之间规则的宽度。
column-span 规定元素应该横跨的列数。
column-width 规定列的宽度。
columns 规定设置 column-width 和 column-count 的简写属性
媒体查询
语法:@media 媒体类型 and (媒体特性){你的样式}@media screen and (min-width:600px) and (max-width:900px) { body {background-color:#f5f5f5;} }
- not关键词
- 使用关键词“not”是用来排除某种制定的媒体类型,也就是用来排除符合表达式的设备。换句话说,not关键词表示对后面的表达式执行取反操作,如:
@media not print and (min-width:1200px) { 样式代码 } // 上面代码表示的是:样式代码将被使用在除打印设备和设备宽度小于1200px下的所有设备中
- 使用关键词“not”是用来排除某种制定的媒体类型,也就是用来排除符合表达式的设备。换句话说,not关键词表示对后面的表达式执行取反操作,如:
- only关键词
- 媒体类型
- all 用于所有媒体类型设备。
- print 用于打印机。
- screen 用于计算机屏幕、平板电脑、智能手机等等。
- speech 用于大声“读出”页面的屏幕阅读器。
- 媒体特性
- 如果是横屏landscape、竖屏portrait,则语法:orientation:portrait | landscape
但与CSS属性不同的是,媒体特性是通过min/max来表示大于等于或小于做为逻辑判断,而不是使用小于(<)和大于(>)这样的符号来判断@media only screen and (orientation:landscape) { body { background-color:lightblue; } }
更复杂的媒体查询@media screen and (max-width:480px) { .ads{ display:none; } } 上面代码表示的是:当屏幕小于或等于480px时,页面中的广告区块(.ads)都讲被隐藏
- 如果是横屏landscape、竖屏portrait,则语法:orientation:portrait | landscape
- 媒体查询中的“与”逻辑
@media screen and (min-width:400px) and (orientation:landscape) { body{ color:blue; } }
- 媒体查询中的“或”逻辑
@media screen and (min-width:400px), screen and (orientation:landscape) { body{ color:blue; } }
- 媒体查询中的“非”逻辑可以用not操作符让整个媒体查询失效。这就直接反转了整个媒体查询的含义。因而在下面的例子中,文本只会在朝向为竖着的时候变成蓝色。
@media not all and (orientation:landscape) { body{ color:blue; } }
八、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:光标显示为何种形态
九、隐藏元素的方法有哪些
- display: none
- 不会在页面中占据位置,也不会响应绑定的监听事件。
- visibility: hidden
- 在页面中占据位置,但不会响应绑定的监听事件。
- opacity: 0
- 在页面中占据位置,且会响应绑定的监听事件。
- position: absolute
- z-index: 负值
- transform: scale(0,0)
- 在页面中占据位置,但不会响应绑定的监听事件。
- clip/clip-path
- 在页面中占据位置,但不会响应绑定的监听事件。
十、display:none 与 visibility:hidden 的区别
这两个属性都是让元素隐藏,不可见。
区别如下:
- 在渲染树中
display:none
会让元素完全从渲染树中消失,渲染时不会占据任何空间;visibility:hidden
不会让元素从渲染树中消失,渲染的元素还会占据相应的空间,只是内容不可见。
- 是否是继承属性
display:none
是非继承属性,子孙节点会随着父节点从渲染树消失,通过修改子孙节点的属性也无法显示;visibility:hidden
是继承属性,子孙节点消失是由于继承了hidden
,通过设置visibility:visible
可以让子孙节点显示;
- 修改常规文档流中元素的
display
通常会造成文档的重排,但是修改visibility
属性只会造成本元素的重绘; - 如果使用读屏器,设置为
display:none
的内容不会被读取,设置为visibility:hidden
的内容会被读取。
十一、display:inline-block 什么时候会显示间隙?
- 有空格时会有间隙,可以删除空格解决;
- 使用
font-size
时,可通过设置font-size:0
、letter-spacing
、word-spacing
解决; margin
正值时,可以让margin
使用负值解决;
十二、单行、多行文本溢出隐藏
单行文本溢出
overflow: hidden; /* 溢出隐藏 */ white-space: nowrap; /* 禁止换行 */ text-overflow: ellipsis; /* 使用省略号表示被截断的文本 */
多行文本溢出
display: -webkit-box; /* 使用弹性盒子布局 */ -webkit-line-clamp: 3; /* 设置显示的行数 */ -webkit-box-orient: vertical; /* 设置垂直方向排列 */ overflow: hidden; /* 溢出隐藏 */ text-overflow: ellipsis;
注意:由于上面的三个属性都是 CSS3 的属性,没有浏览器可以兼容,所以要在前面加一个-webkit- 来兼容一部分浏览器。
十三、说说 flex 布局?flex: 1 代表什么?
flex 布局称弹性布局。采用 flex 布局的元素,称为 flex 容器,简称“容器”;它的所有子元素自动成为容器成员,称为 flex 项目,简称“项目”。
容器默认存在两根轴:水平的主轴(mainaxis)和垂直的交叉轴(crossaxis),项目默认沿主轴排列。
以下6个属性设置在容器上:
- flex-direction:决定主轴的方向(即项目的排列方向)。
- flex-wrap:定义,如果一条轴线排不下,如何换行。
- flex-flow:是flex-direction属性和flex-wrap属性的简写形式,默认值为rownowrap。
- justify-content:定义了项目在主轴上的对齐方式。
- align-items:定义项目在交叉轴上如何对齐。
- align-content:定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
以下6个属性设置在项目上:
- order:定义项目的排列顺序。数值越小,排列越靠前,默认为
0
。 - flex-grow:定义项目的放大比例,默认为
0
,即如果存在剩余空间,也不放大。 - flex-shrink:定义了项目的缩小比例,默认为
1
,即如果空间不足,该项目将缩小。 - flex-basis:定义了在分配多余空间之前,项目占据的主轴空间。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为
auto
,即项目的本来大小。 - flex:是
flex-grow
,flex-shrink
和flex-basis
的简写,默认值为0 1 auto
。 - align-self:允许单个项目有与其他项目不一样的对齐方式,可覆盖
align-items
属性。默认值为auto
,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch
。
推荐阅读:阮一峰的 Flex 布局教程:语法篇
flex 属性的可选值如下:
- 当 flex 取值为 none,则计算值为
0 0 auto
,如.item {flex: none;} .item { flex-grow: 0; flex-shrink: 0; flex-basis: auto; }
- 当 flex 取值为 auto,则计算值为
1 1 auto
,如.item {flex: auto;} .item { flex-grow: 1; flex-shrink: 1; flex-basis: auto; }
- 当 flex 取值为一个非负数字
a
,则计算值为a 1 0%
,如.item {flex: 1;} .item { flex-grow: 1; flex-shrink: 1; flex-basis: 0%; }
- 当 flex 取值为一个长度
b
或百分比b%
,则计算值为1 1 b%
,如.item-2 {flex: 24px;} .item-1 { flex-grow: 1; flex-shrink: 1; flex-basis: 24px; } 或 .item-1 {flex: 0%;} .item-1 { flex-grow: 1; flex-shrink: 1; flex-basis: 0%; }
- 当 flex 取值为两个非负数字
x
和y
,则计算值为x y 0%
,如.item {flex: 2 3;} .item { flex-grow: 2; flex-shrink: 3; flex-basis: 0%; }
- 当 flex 取值为一个非负数字
j
和一个长度k
或百分比k%
,则计算值为j 1 k%
,如.item {flex: 2333 3222px;} .item { flex-grow: 2333; flex-shrink: 1; flex-basis: 3222px; }
十四、什么是层叠上下文?什么是层叠水平?元素的层叠顺序?层叠准则?
层叠上下文的概念:层叠上下文是 HTML 中的一个三维概念,如果一个元素含有层叠上下文,就说这个元素在z轴上“高人一等”,在视觉上有更高的优先级,即这个元素会优先被用户看到。
层叠水平的概念:决定了同一个层叠上下文中元素在z轴上的显示顺序。
层叠顺序:
对于上图,从上到下分别是:
- 背景和边框
- 负的z-index
- 块级盒
- 浮动盒
- 行内盒
- z-index:0
- 正z-index
注意: 当定位元素
z-index:auto
,生成盒在当前层叠上下文中的层级为 0,不会建立新的层叠上下文,除非是根元素。
- 正z-index
层叠准则:
- 谁大谁上:当具有明显的层叠水平标识的时候,如生效的z-index属性值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。
- 后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在DOM流中处于后面的元素会覆盖前面的元素。
推荐阅读:张鑫旭的深入理解CSS中的层叠上下文和层叠顺序
十五、z-index属性在什么情况下会失效
通常 z-index 的使用是在有两个重叠的标签,在一定的情况下控制其中一个在另一个的上方或者下方出现。z-index值越大就越是在上层。z-index元素的position属性需要是relative,absolute或是fixed。
z-index属性在下列情况下会失效:
- 父元素position为relative时,子元素的z-index失效。解决:父元素position改为absolute或static;
- 元素没有设置position属性为非static属性。解决:设置该元素的position属性为relative,absolute或是fixed中的一种;
- 元素在设置z-index的同时还设置了float浮动。解决:float去除,改为display:inline-block;
十六、width:auto 和 width:100%的区别
width:100%
100% 表示子元素的真正宽度等于父元素的真正宽度。width:auto
auto 表示子元素的 宽度+内边距+外边距+边框 等于父元素的真正宽度。
十七、min-width、max-width、width的包含(优先级)关系
width < min-width
时,以min-width
为主;min-width < width < max-width
时,以width
为主;max-width < width
时,以max-width
为主。
十八、margin:值为负数是什么意思
- 若元素本身没有宽度
margin-left
:会增大元素左边的宽度<div class="wrap"> 最外层的宽度为800px <div class="box">里层的元素没有宽度,设置了margin-left: -100px</div> </div>
.wrap { background-color: #f00; width: 800px; height: 300px; margin: 100px auto 0; } .box { background-color: #007AFF; margin-left:-100px; height: 200px; }
margin-right
:会增大元素右边的宽度<div class="wrap"> 最外层的宽度为800px <div class="box">里层的元素没有宽度,设置了margin-right: -100px</div> </div>
.wrap { background-color: #f00; width: 800px; height: 300px; margin: 100px auto 0; } .box { background-color: #007AFF; margin-right: -100px; height: 200px; }
margin-top
:会将本元素向上移动(后面的元素也会跟着上移)<div class="wrap"> 最外层的宽度为800px <div class="box">里层的元素没有宽度,设置了 margin-top: -100px </div> </div>
.wrap { background-color: #f00; width: 800px; height: 300px; margin: 100px auto 0; font-size: 30px; } .box { background-color: #007AFF; height: 200px; margin-top: -100px; }
没有设置
margin-top: -100px
时:
设置了 margin-top: -100px
时:
margin-bottom
:本元素不移动,后面的元素会上移<div class="wrap"> 最外层的宽度为 800px ,设置了 margin: 100px <div class="box">里层的元素没有宽度,设置了 margin-bottom: -100px </div> <div class="test"></div> </div>
没有设置.wrap { background-color: #f00; width: 800px; height: 300px; margin: 100px auto 0; font-size: 30px; } .box { background-color: #007AFF; height: 200px; margin-bottom: -100px; } .test { background-color: green; height: 100px; }
margin-bottom: -100px
时:
设置了 margin-bottom: -100px
时:
- 若元素本身有宽度
margin-left
:本元素向左移动<div class="wrap"> 最外层的宽度为800px <div class="box">里层的元素有宽度,设置了margin-left: -100px</div> </div>
.wrap { background-color: #f00; width: 800px; height: 300px; margin: 100px auto 0; font-size: 30px; } .box { background-color: #007AFF; width: 800px; height: 200px; margin-left: -100px; }
margin-right
:本元素不动,后面的元素往左移动<div class="wrap"> <div class="box">里层的元素有宽度,设置 margin-right: -100px </div> <div class="test"></div> </div>
没设置.wrap { background-color: #f00; width: 800px; height: 300px; margin: 100px auto 0; font-size: 25px; } .box { float: left; background-color: #007AFF; width: 700px; height: 200px; margin-right: -100px; } .test { float: left; background-color: green; width: 100px; height: 100px; }
margin-right: -100px
时:
设置 margin-right: -100px
后:
margin-top
:会将本元素向上移动(后面的元素也会跟着上移)margin-bottom
:本元素不移动,后面的元素会上移
推荐阅读:详述padding和margin中的负值
十九、font-style 属性中 italic 和 oblique 的区别?
italic
和 oblique
这两个关键字都表示“斜体”的意思。
它们的区别在于,italic
是使用当前字体的斜体字体,而 oblique
只是单纯地让文字倾斜。
二十、readonly 和 disabled的区别
readonly 属性规定输入字段为只读。
readonly
属性只对<input type="text">、<input type="number">、<textarea>和<input type="password">等可以输入的表单元素
有效。readonly
属性只是将元素设置为只读,其他操作正常,用户仍然可以使用 tab 键切换到该字段,还可以选中或拷贝其文本。应用:
readonly
属性可以防止用户对值进行修改,直到满足某些条件为止(比如选中了一个复选框)。然后,需要使用 JavaScript 消除readonly
值,将输入字段切换到可编辑状态。disabled 属性规定应该禁用 input 元素。
disabled
属性可以作用于所有的表单元素。disabled
属性阻止对元素的一切操作,例如获取焦点,点击事件等等。
二十一、overflow:scroll 时不能平滑滚动的问题怎么处理?
以下代码可解决这种卡顿的问题:-webkit-overflow-scrolling:touch;
因为这行代码启用了硬件加速特性,所以滑动很流畅。
二十二、opacity可以有过渡效果么
可以,实践如下:
<div class="test"></div>
body {
background-color: black;
}
.test {
width: 100px;
height: 100px;
background-color: rgba(255,255,255,1);
opacity: 1;
}
.test:hover {
opacity: 0;
transition: 2s;
}
二十三、opacity为0.5的元素,背景色0.5alpha是更浅么?
是的,实践如下:
<div class="test"></div>
body {
background-color: black;
}
.test {
width: 100px;
height: 100px;
background-color: rgba(255,255,255,1);
opacity: 0.5;
}
当 .test
的 background-color: rgba(255,255,255,1);
时,效果如图:
当 .test
的 background-color: rgba(255,255,255,0.5);
时,效果如图:
二十四、为什么css 选择器的查找是从右往左的
我们知道 DOM 树和 CSSOM 树会合并成 render 树,这个操作实际上就是需要将 css 附着到 DOM 树上,因此需要根据选择器提供的信息对 DOM 树进行遍历,才能将样式成功附着到对应的 DOM 元素上。
如果我们有这样一段 DOM 树:
.main
/ \
section aside
/ \ / \
h1 .content .desc a
/ /
p p
并定义一段 css:.main .desc p{}
,如果浏览器是从左往右解析 css 选择器:
- 遍历 DOM 树
- .main -> .section -> h1 ,发现没有找到指定的 css ,则回溯
- .main -> section -> .content -> p ,发现也没有,回溯
- .main -> aside -> .desc ,终于成功找到了
从左往右解析就是这么麻烦,但如果是从右往左的话,就可以直接找到指定的 css 样式,这样就有效减少了回溯次数,提升了css 解析的性能。
二十五、link 和 @import 的区别
两者都是外部引用 css 的方式,区别如下:
- link 是 XHTML 标签,无兼容问题;@import 是在 css2.1 时提出的,低版本的浏览器不支持;
- link 引入 css 时,在页面载入时同时加载;@import 引用的 CSS 会等到页面完全载入以后再加载;
- link 支持使用 js 去控制 DOM 修改样式,@import不支持;
- link 是 XHTML 标签,除了加载 css 外,还可以定义 rss 等其他事务,@import 是 CSS 提供的,只能用于加载 css
二十六、动画性能如何优化
动画中尽量少使用会触发重排重绘的 css 属性
使用更低耗的
transform
、opacity
等属性,尽量不使用box-shadow
、gradients
等尤其消耗 GPU 的属性
css 属性性能消耗图如下:尽量减少或者固定层的数量,不要在动画过程中创建层
尽量减少层的更新次数,可以使用
translate3d
来达到此效果
二十七、px和 rem 的区别
px 是像素,是绝对单位长度;rem 是相对单位,相对 html 根节点的 font-size
的值,直接给 html 节点的 font-size:62.5%
。
1rem = 10px;
(16px * 62.5% = 10px)
一、实现一个宽高自适应的正方形
- 方法一:利用vw来实现
.square { width: 10%; height: 10vw; background: tomato; }
- 方法二:利用元素的margin/padding百分比是相对父元素width的性质来实现
.square { width: 20%; height: 0; padding-top: 20%; background: orange; }
- 方法三:利用子元素的margin-top的值来实现的
.square { width: 30%; overflow: hidden; background: yellow; } .square::after { content: ""; display: block; margin-top: 100%; }
二、实现一个等腰三角形
<div class="test"></div>
效果如下:.test { width: 0; height: 0; border: 100px solid transparent; /* 需要哪个方向的三角形,就保留哪个方向的代码即可 */ border-top-color: red; /* 向上 */ border-right-color: green; /* 向右 */ border-bottom-color: blue; /* 向下 */ border-left-color: orange; /* 向左 */ }
.test {
width: 0;
height: 0;
border: 100px solid transparent;
border-top-color: red;
border-left-color: red;
}
效果如下:
三、实现一个扇形
<div class="test"></div>
.test {
border-radius: 100px;
width: 0;
height: 0;
border: 100px solid transparent;
/* 需要哪个方向的圆,就保留哪个方向的代码即可 */
border-top-color: red; /* 向上 */
border-right-color: green; /* 向右 */
border-bottom-color: blue; /* 向下 */
border-left-color: orange; /* 向左 */
}
效果如下:
四、实现一个半圆
<div class="test"></div>
上半圆
长度设为宽度的两倍.test{ width: 100px; height: 50px; background-color: skyblue; border-radius: 100px 100px 0 0; }
右半圆
宽度设为长度的两倍.test{ width: 100px; height: 200px; background-color: skyblue; border-radius: 0 100px 100px 0; }
下半圆
长度设为宽度的两倍.test{ width: 200px; height: 100px; background-color: skyblue; border-radius: 0px 0px 100px 100px; }
左半圆
宽度设为长度的两倍.test{ width: 100px; height: 200px; background-color: skyblue; border-radius: 100px 0px 0px 100px; }
五、实现一个圆环
- 两个标签的嵌套
<div class="parent"> <div class="child"></div> </div>
.parent { width: 200px; height: 200px; background-color: blue; border-radius: 50%; } .child { width: 100px; height: 100px; border-radius: 50%; background-color: skyblue; position: relative; top: 50px; left: 50px; }
- 使用伪元素,before/after
<div class="parent"></div>
.parent { width: 200px; height: 200px; background-color: blue; border-radius: 50%; } .parent:after { content: ""; display: block; width: 100px; height: 100px; border-radius: 50%; background-color: skyblue; position: relative; top: 50px; left: 50px; }
- 使用 border
<div class="parent"></div>
.parent { width: 100px; height: 100px; background-color: skyblue; border-radius: 50%; border: 50px solid blue; }
- 使用 border-shadow
<div class="parent"></div>
.parent { width: 100px; height: 100px; background-color: skyblue; border-radius: 50%; box-shadow: 0 0 0 50px blue; margin: auto; } /* 或者 */ .parent { width: 200px; height: 200px; background-color: skyblue; border-radius: 50%; box-shadow: 0 0 0 50px blue inset; margin: auto; }
- 使用 radial-gradient
<div class="parent"></div>
效果如图:.parent { width: 200px; height: 200px; border-radius: 50%; background: -webkit-radial-gradient(circle closest-side, skyblue 50%, blue 50%); }
六、实现两栏布局
<div class="whole">
<div class="left">left</div>
<div class="right">right</div>
</div>
*{
padding: 0;
margin: 0;
}
div{
height:500px;
}
方法一:浮动布局
.left{ width:300px; background-color:yellow; float:left; } .right{ margin-left:300px; background-color:aqua; }
左侧栏固定宽度向左浮动,右侧主要内容则用margin-left留出左侧栏的宽度,默认宽度为auto,自动填满剩下的宽度。
方法二:BFC
.whole{ overflow: hidden; } .left{ float: left; width:300px; background-color:yellow; } .right{ background-color:aqua; }
方法三:浮动布局+负外边距(双飞翼布局的两栏版)
.left{ width:300px; float: left; margin-right: -100%; background-color:yellow; } .right{ width: 100%; float: left; margin-left:300px; background-color:aqua; }
左侧固定栏指定一个右侧的100%的负外边距,为整个屏幕的宽度,这就使得right最左侧可以与屏幕最左侧对齐。
此时right的宽度是100%,因此需要指定一个左侧的外边距用于空出左侧栏的位置,即左侧栏的宽度300px
- 方法四:绝对定位
.left{ width:300px; background-color:yellow; position: absolute; } .right{ margin-left: 300px; background-color:aqua; }
- 方法五:flex盒模型
.whole{ display:flex; } .left{ width: 300px; background-color:yellow; } .right{ flex: 1; background-color:aqua; }
- 方法六:float+calc()函数
.left{ width:300px; background-color:yellow; float: left; } .right{ float: right; width: calc(100% - 300px); background-color:aqua; }
七、实现三栏布局
三栏布局一般指的是页面中一共有三栏,左右两栏宽度固定,中间自适应的布局。
方法一:浮动定位布局:两边使用 float,中间使用 margin
<div class="wrap"> <div class="left">左侧</div> <div class="right">右侧</div> <div class="middle">中间</div> </div>
.wrap{ background: #eee; padding: 20px; } .left{ width: 200px; height: 200px; float: left; background: coral; } .right{ width: 200px; height: 200px; float: right; background: lightblue; } .middle{ height: 200px; margin-left: 220px; margin-right: 220px; background: lightpink; }
方法二:绝对定位布局:两边使用 absolute,中间使用 margin
<div class="wrap"> <div class="left">左侧</div> <div class="right">右侧</div> <div class="middle">中间</div> </div>
.wrap{ position: relative; } .left{ position: absolute; width: 100px; height: 200px; background: coral; } .right{ position: absolute; right: 0; top: 0; width: 200px; height: 200px; background: lightblue; } .middle{ height: 200px; margin: 0 200px 0 100px; background: lightpink; }
方法三:flex布局
<div class="wrap"> <div class="left">左侧</div> <div class="middle">中间</div> <div class="right">右侧</div> </div>
.wrap{ display: flex; } .left{ width: 200px; height: 300px; background: coral; } .right{ width: 200px; height: 300px; background: lightblue; } .middle{ flex: 1; margin: 0 10px; background: lightpink; }
方法四:grid 布局
<div class="wrap"> <div class="left">左侧</div> <div class="middle">中间</div> <div class="right">右侧</div> </div>
.wrap{ height: 200px; display: grid; grid-template-columns: 200px auto 200px; grid-template-rows: 100px; grid-column-gap: 10px; } .left{ background: coral; } .right{ background: lightblue; } .middle{ background: lightpink; }
方法五:两边使用 float 和负 margin
<div class="wrap"> <div class="middle">中间</div> </div> <div class="left">左侧</div> <div class="right">右侧</div>
.wrap{ float: left; width: 100%; } .middle{ height: 200px; margin: 0 210px 0 110px; background: lightpink; } .left{ width: 100px; height: 200px; float: left; margin-left: -100%; background: coral; } .right{ width: 200px; height: 200px; float: right; margin-left: -200px; background: lightblue; }
方法六:双飞翼布局
方法七:圣杯布局
八、实现双飞翼布局
左、中、右三个盒子同级,在中间盒子里放一个小盒子,设置小盒子的margin,从而留出两侧盒子位置。
<div class="container">
<div class="middle"> <h4>中间弹性区</h4> </div>
</div>
<div class="left"> <h4>左边栏</h4> </div>
<div class="right"> <h4>右边栏</h4> </div>
.container{
float: left;
width: 100%;
height: 500px;
}
.middle{
/* 处理中间栏的内容被遮盖问题 */
height: 500px;
margin: 0 200px;
background-color: lightpink;
}
.left{
float: left;
width: 200px;
height: 500px;
margin-left: -100%;
background-color: lightblue;
}
.right{
float: right;
width: 200px;
height: 500px;
margin-left: -200px;
background-color: lightgreen;
}
实现的布局如下:
九、实现圣杯布局
左、中、右三个盒子在一个同一个盒子中,设置外侧盒子的padding,从而留出两侧盒子位置。
<header><h4>Header内容区</h4></header>
<div class="container">
<div class="middle"><h4>中间弹性区</h4></div>
<div class="left"><h4>左边栏</h4></div>
<div class="right"><h4>右边栏</h4></div>
</div>
<footer><h4>Footer内容区</h4></footer>
header, footer{
width: 100%;
height: 40px;
background-color: darkseagreen;
}
.container{
height:500px;
overflow:hidden;
padding: 0 200px;
}
.middle{
width: 100%;
height: 500px;
background-color: deeppink;
float:left;
}
.left{
width: 200px;
height: 500px;
background-color: blue;
float:left;
margin-left: -100%;
position: relative;
left: -200px;
}
.right{
width: 200px;
height: 500px;
background-color: darkorchid;
float:left;
margin-left: -200px;
position: relative;
right: -200px;
}
实现的布局如下:
十、怎么画0.5px的细线
viewport
html 文件的<head>
头部将<meta>
设置如下:<meta name="viewport" content="width=device-width,initial-sacle=0.5">
在页面中正常绘制线条即可。
阴影box-shadow
.hr { margin: 100px; height: 1px; box-shadow: 0 0.5px 0 #000; }
缩放transform:scale()
.hr { background-color: black; height: 1px; transform: scaleY(0.5); }
可以看到,画出来的线条变虚了,但粗细没有改变
因此还需要给线条加上 transform-origin: 50% 100%
:
- 线性渐变linear-gradient
.hr { margin: 100px; height: 1px; background: linear-gradient(0deg, #fff, #000); }
十一、怎么随机生成一堆不难看的颜色
网页中颜色的使用方式有以下几种:
- 颜色名称:如
red
、green
、blue
等 - 十六进制颜色,每两位代表红或绿或蓝的比例:如
#ffffff白色
、#000000黑色
等 - rgba:如
rgba(red, green, blue, 1)
,可选参数有:- r:红色值。可填正整数 | 百分数。
- g:绿色值。可填正整数 | 百分数。
- b:蓝色值。可填正整数 | 百分数。
- a:透明度。取值在
0 ~ 1
之间。
- hsla颜色值:如
hsla(360, 50%, 50%, 0.5)半透明红色
,可选参数有:- h:色调。0(或360)表示红色,120表示绿色,240表示蓝色,也可取其他数值来指定颜色,取值为:0 - 360。
- s:饱和度。取值在
0.0% ~ 100.0%
之间。 - l:亮度。取值在
0.0% ~ 100.0%
之间。 - a:透明度。取值在
0 ~ 1
之间。
实践:
声明 html 样式结构如下:
<ul id="ul">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
声明 js 代码结构如下:
function createColor(){
// code
}
window.onload = function () {
//获取 ul 节点
var oUl = document.getElementById("ul");
//获取li标签
var aLi = oUl.getElementsByTagName("li");
//循环li
for(let i = 0; i < aLi.length; i++) {
aLi[i].style.background = Color();
}
};
下面补充 js 中的 createColor
函数。
生成方式一:十六进制
// 写法一:
function createColor() {
let color = '#';
for (let i = 0; i < 6; i++) {
color += '0123456789abcdef'[Math.floor(Math.random()*16)];
}
return color;
}
// 写法二:
function createColor() {
return '#' + (function(color){
return (color += '0123456789abcdef'[Math.floor(Math.random()*16)])
&& (color.length === 6) ? color : arguments.callee(color);
})('');
}
生成方式二:rgba
function createColor() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
const a = Math.random(); // 如果是 rgb ,则固定该值即可
const color = `rgba(${r}, ${g}, ${b}, ${a})`;
return color;
}
rgba:
rgb:
生成方式三:hsla
function createColor() {
const colorAngle = Math.floor(Math.random()*360);
const color = `hsla(${colorAngle}, 100%, 50%, 1)`;
return color;
}
十二、用 transition 和 animation 分别写出对应的样式实现 360°旋转
transition
<div>transition</div>
div { width: 100px; height: 100px; background-color: green; } div:hover { transform: rotate(360deg); transition: transform 5s linear; }
animation
<div>animation</div>
div { width: 100px; height: 100px; background-color: green; animation: turn 5s linear; /* 注意:值没有逗号 */ } @keyframes turn { from{ transform: rotate(0deg); } to{ transform: rotate(360deg); } }
十三、实现一个点击之后从中心旋转并放大的正方形
<div class="test"></div>
.test {
width: 100px;
height: 100px;
background-color: green;
}
.click {
transform: rotate(360deg) scale(5);
transition: transform 1s linear;
}
const div = document.getElementsByClassName('test');
div[0].addEventListener('click', () => {
div[0].classList.add('click');
})
十四、css 实现弹窗
可以使用 CSS 和 HTML 结合的方式来创建:
HTML 结构:
<button id="openBtn">打开弹窗</button>
<div id="modal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<h2>这是一个弹窗</h2>
<p>这是弹窗的内容。</p>
</div>
</div>
CSS 样式:
/* 遮罩层样式 */
.modal {
display: none;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
/* 弹窗内容样式 */
.modal-content {
background-color: #fff;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 50%;
}
/* 关闭按钮样式 */
.close {
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
JavaScript 代码(用于控制弹窗的显示和隐藏):
var modal = document.getElementById("modal");
var openBtn = document.getElementById("openBtn");
var closeBtn = document.getElementsByClassName("close")[0];
// 打开弹窗
openBtn.onclick = function() {
modal.style.display = "block";
}
// 关闭弹窗
closeBtn.onclick = function() {
modal.style.display = "none";
}
// 点击遮罩层外部区域关闭弹窗
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}