深入理解 CSS——CSS进阶与实践(5w字高频面试题整理)

 本文总结了CSS高频面试题,并搭配了演示动画进行CSS样式演示。介绍了关于如何理解盒模型,如何实现块级元素水平居中,如何实现两侧固定中间自适应的三栏布局、如何实现两栏布局,如何进行响应式设计,对BFC的理解,flex布局和grid布局的适配场景,如何获取奇数节点/偶数节点,单行及多行文本溢出解决,如何绘制三角形,常见表示单位长度的em/px/rem/vh/vw的区别,隐藏页面元素的方式及区别,如何清除浮动,如何解决margin塌陷,设备像素/物理像素/CSS像素的区别,选择器类型优先级和权重,如何让chrome浏览器支持小于12px字体,CSS动画常用实现方法,怎么理解重流重绘,根据重流重绘思考解决方法;CSS性能优化方案等

 对盒子模型理解多少?

什么是盒子模型

盒子模型(Box Model)是指在网页布局中,每个 HTML 元素被看作一个矩形的盒子,这个盒子包含内容区域、内边距(padding)、边框(border)和外边距(margin)四个部分。盒子模型描述了这些部分如何相互影响,以及它们如何决定元素在页面中的尺寸和位置。

具体来说,盒子模型可以分为以下四个部分:

  1. 内容区域(Content):内容区域是盒子中用来显示实际内容的部分,例如文本、图片等。内容区域的大小由元素的宽度(width)和高度(height)属性决定。

  2. 内边距(Padding):内边距是内容区域与边框之间的空间,用来控制内容与边框之间的距离。内边距可以通过 padding 属性来设置。

  3. 边框(Border):边框是围绕内容区域和内边距的线条或样式,用来界定元素的边界。边框可以通过 border 属性来设置,包括边框的样式、宽度和颜色。

  4. 外边距(Margin):外边距是盒子与其他元素之间的空间,用来控制元素与周围元素之间的距离。外边距可以通过 margin 属性来设置。

这些部分共同构成了一个完整的盒子模型,决定了元素在页面中的大小、位置和布局。

盒子模型的计算方式

标准盒模型宽度=width+padding+border

怪异盒模型宽度=width(包含了padding和border,挤压了内容区域宽度)

标准盒子模型

打开浏览器控制台,查看dom元素,看布局-》盒子模型,可以看到box:sizing:content-box这个是浏览器默认的盒子模型。

标准盒子模型盒子的宽度=内容区域宽度width+padding+border

 示例:给top类的div设置宽高200px,boder为1px,margin和padding各50px。看下盒子在浏览器中占据的宽度

.top {
  width: 200px;
  height: 200px;
  border: 1px solid blue;
  background: #ccc;
  margin: 50px;
  left: 2oopx;
  padding: 20px;
}

可以看到,盒子在浏览器的宽度=width+左右padding+左右border

                                                  =200px+40px+2px

怪异盒模型

通过设置box:sizing:border-box改变盒子模型为怪异盒模型

示例:给bottom类的div设置宽高200px,boder为1px,margin和padding各50px。看下盒子在浏览器中占据的宽度

bottom {
  width: 200px;
  height: 200px;
  border: 1px solid green;
  background: #ccc;
  margin: 50px;
  padding: 20px;
  box-sizing: border-box;
}

 可以看到,内容区域的宽度变成158px了,padding和border分解了width。

盒子的宽度=width=200px

相同情况下,怪异盒模型盒子的体积<标准盒模型

 标准盒模型VS怪异盒模型

通过CSS 中的 box-sizing 属性切换

标准盒模型

box-sizing: content-box

怪异盒模型。

box-sizing: border-box

可以看下面的对比,标准盒模型比较好理解,内容区域的宽度=width。

怪异盒模型,实际的内容区域宽度<=给定width,padding和border会瓜分内容的宽度,而盒子的宽度等于width。

说说flexbox弹性盒模型以及适用场景

弹性盒模型(Flexbox)是 CSS3 中引入的一种布局模型,旨在提供一种更加灵活的方式来设计和排列元素,特别适用于构建响应式和动态布局。Flexbox 布局通过定义容器和其内部元素之间的弹性关系,使得元素可以根据可用空间动态调整大小和位置,从而实现更加灵活和自适应的布局设计。

为什么会有 Flex 布局

  1. 更简洁的代码:相比传统的布局方式(如浮动、定位),Flexbox 布局提供了更简洁、直观的代码结构,减少了开发者编写复杂布局所需的代码量。

  2. 更强大的布局控制:Flexbox 提供了强大的布局控制能力,可以轻松实现各种复杂的布局设计,包括多列布局、响应式布局等。

  3. 更好的响应性支持:Flexbox 布局适用于响应式设计,可以根据不同设备和屏幕尺寸来调整布局,提供更好的用户体验。

  4. 更好的浏览器支持:Flexbox 布局得到了现代浏览器的广泛支持,可以在各种主流浏览器上稳定运行,为开发者提供了更好的跨浏览器兼容性。

 适用场景

水平和垂直居中:Flexbox 布局非常适合实现元素在水平和垂直方向上的居中对齐,无论是单个元素还是多个元素。

等高布局:Flexbox 可以轻松实现等高的列布局,即使内容高度不同,也可以让列等高显示。

自适应布局:Flexbox 可以根据容器的大小和内容的变化,自动调整元素的大小和位置,适应不同屏幕尺寸和设备。

多列布局:Flexbox 可以实现多列布局,同时控制列的宽度、间距和对齐方式,适用于各种网站和应用的布局设计。

容器常用属性

Flexbox(弹性盒模型)布局中常用的属性包括:

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

这些属性可以帮助开发者控制 Flexbox 布局

flex-direction——主轴项目排列方向

决定主轴的方向,即项目的排列方向。容器中默认存在两条轴,主轴和交叉轴,呈90度关系。项目默认沿主轴排列flex-direction:row从左至右。通过flex-direction来决定主轴的方向;每根轴都有起点和终点,这对于元素的对齐非常重要。

.container {   
    flex-direction: row | row-reverse | column | column-reverse;  
} 
  • row(默认值):主轴为水平方向,起点在左端
  • row-reverse:主轴为水平方向,起点在右端
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿 

 

flex-wrap——元素换行

弹性元素永远沿主轴排列,那么如果主轴排不下,通过flex-wrap决定容器内项目是否可换行。默认情况是不换行,但这里也不会任由元素直接溢出容器,会涉及到元素的弹性伸缩

.container {  
    flex-wrap: nowrap | wrap | wrap-reverse;
}  

属性对应如下:

  • nowrap(默认值):不换行
  • wrap:换行,第一行在上方
  • wrap-reverse:换行,第一行在下方

 (1)nowrap(默认):不换行。

(2)wrap:换行,第一行在上方。

(3)wrap-reverse:换行,第一行在下方。

flex-flow——主轴和换行

flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap= 主轴不换行

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}

justify-content——主轴对齐

定义了项目在主轴上的对齐方式

.box {
    justify-content: flex-start | flex-end | center | space-between | space-around;
}

属性对应如下:

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center:居中
  • space-between:两端对齐,项目之间的间隔都相等(用的比较多)
  • space-around:两个项目两侧间隔相等(两个项目中间的距离=两端项目离两侧距离的两倍)
  • space-evenly:等距包含容器边缘

效果图如下:

align-items——交叉轴对齐

定义项目在交叉轴上如何对齐

.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

属性对应如下:

  • flex-start:交叉轴的起点对齐
  • flex-end:交叉轴的终点对齐
  • center:交叉轴的中点对齐
  • baseline: 项目的第一行文字的基线对齐
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度

align-content——多轴线对齐

定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用

.box {
    align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

属性对应如吓:

  • flex-start:与交叉轴的起点对齐
  • flex-end:与交叉轴的终点对齐
  • center:与交叉轴的中点对齐
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍
  • stretch(默认值):轴线占满整个交叉轴

效果图如下:

容器成员属性如下

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

常用的也就是flex:1表示剩余空间自动分配。一般用作响应式布局,比如实现自适应两栏布局,左侧固定宽,右侧通过flex:1自适应宽。

order——顺序

定义项目的排列顺序。数值越小,排列越靠前,默认为0

.item {
    order: <integer>;
}

flex-grow——放大比例

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

.item {
    flex-grow: <number>;
}

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)

如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍

弹性容器的宽度正好等于元素宽度总和,无多余宽度,此时无论flex-grow是什么值都不会生效

flex-shrink——缩小比例

定义了项目的缩小比例(容器宽度<元素总宽度时如何收缩),默认为1,即如果空间不足,该项目将缩小。在容器宽度有剩余时,flex-shrink也是不会生效的

.item {
    flex-shrink: <number>; /* default 1 */
}

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

flex-basis——主轴初始尺寸

不常用的属性。

设置的是元素在主轴上的初始尺寸,所谓的初始尺寸就是元素在flex-growflex-shrink生效前的尺寸。浏览器根据这个属性,计算主轴是否有多余空间,默认值为auto,即项目的本来大小,如设置了width则元素尺寸由width/height决定(主轴方向),没有设置则由内容决定

.item {
   flex-basis: <length> | auto; /* default auto */
}

当设置为0的是,会根据内容撑开。它可以设为跟widthheight属性一样的值(比如350px),则项目将占据固定空间

flex——复合属性

flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto,也是比较难懂的一个复合属性

我觉得只用记住flex:1表示剩余空间自动分配就好了。真复杂。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

一些属性有:

  • flex: 1 = flex: 1 1 0%
  • flex: 2 = flex: 2 1 0%
  • flex: auto = flex: 1 1 auto
  • flex: none = flex: 0 0 auto,常用于固定尺寸不伸缩

align-self——项目自定义对齐

允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

.item {
    align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

效果图如下:

介绍一下grid网格布局

flex布局适合一维度,某行或某列进行布局。而grid适合规则的多行多列布局。

CSS Grid 布局是在 CSS3 中引入的一种新的布局方式,旨在解决传统的基于盒子模型的布局方式(如浮动、定位等)所面临的一些限制和复杂性。CSS Grid 布局通常用于需要更复杂的网格结构和布局的场景,例如多列布局、多行布局、项目之间需要精确对齐的情况等。比如下面的布局可以用grid实现

 

以下是一些适合使用 CSS Grid 布局的场景:

  1. 复杂的多列布局:CSS Grid 布局非常适合创建多列布局,可以轻松地定义多个列和行,以及它们之间的间距和对齐方式。

  2. 响应式布局:CSS Grid 布局可以很好地支持响应式设计,通过定义不同的网格模板,可以在不同的屏幕尺寸下实现不同的布局。

  3. 项目之间需要精确对齐的布局:CSS Grid 布局提供了强大的对齐和定位能力,可以精确控制项目在网格中的位置和对齐方式。

  4. 复杂的嵌套布局:CSS Grid 布局支持嵌套网格,可以创建复杂的布局结构,使得布局更加灵活和可维护 

网格线及单元格

        划分网格的线,称为"网格线"(grid line)。水平网格线划分出行,垂直网格线划分出列。正常情况下,n行有n + 1根水平网格线,m列有m + 1根垂直网格线,比如三行就有四根水平网格线。 行和列的交叉区域,称为"单元格"(cell)。正常情况下,n行和m列会产生n x m个单元格。比如,3行3列会产生9个单元格。

同样,Grid 布局属性可以分为两大类:

  • 容器属性,
  • 项目属性

关于容器属性有如下:

  • display: grid;:将元素设置为网格容器。
  • grid-template-rows:定义网格布局的行高。
  • grid-template-columns:定义网格布局的列宽。
  • gap:定义网格行列之间的间距。
  • grid-template-areas:通过命名区域来定义网格布局。
  • grid-row 和 grid-column:定义元素在网格中的位置。

grid-template-columns/grid-template-rows 属性

grid-template-columns 属性设置列宽,grid-template-rows 属性设置行高

.wrapper {
  display: grid;
  /*  声明了三列,宽度分别为 200px 200px 200px */
  grid-template-columns: 200px 200px 200px;
  grid-gap: 5px;
  /*  声明了两行,行高分别为 50px 50px  */
  grid-template-rows: 50px 50px;
}

以上表示固定列宽为 200px 200px 200px,行高为 50px 50px

(1)repeate函数

有时候,重复写同样的值非常麻烦,尤其网格很多时。这时,可以使用repeat()函数,简化重复的值。

  • 第一个参数是重复的次数
  • 第二个参数是重复的值

所以上述代码可以简写成

.wrapper {
  display: grid;
  grid-template-columns: repeat(3,200px);
  grid-gap: 5px;
  grid-template-rows:repeat(2,50px);
}

示例:定义了6列,第一列和第四列的宽度为100px,第二列和第五列为20px,第三列和第六列为80px

 


grid-template-columns: repeat(2, 100px 20px 80px);

(2)auto-fill 关键字

有时,单元格的大小是固定的,但是容器的大小不确定,适配响应式布局。如果希望每一行(或每一列)容纳尽可能多的单元格,这时可以使用auto-fill关键字表示自动填充,不需要具体个数。


.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
}

 每列宽度100px,然后自动填充,直到容器不能放置更多的列。

除了auto-fill,还有一个关键字auto-fit,两者的行为基本是相同的。只有当容器足够宽,可以在一行容纳所有单元格,并且单元格宽度不固定的时候,才会有差别:auto-fill会用空格子填满剩余宽度,auto-fit则会尽量扩大单元格的宽度。

(3)fr 关键字

为了方便表示比例关系,网格布局提供了fr关键字(fraction 的缩写,意为"片段")(你也可以理解为份儿)。如果两列的宽度分别为1fr2fr,就表示后者是前者的两倍。


.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

表示两个相同宽度的列。

fr可以与绝对长度的单位结合使用,这时会非常方便。


.container {
  display: grid;
  grid-template-columns: 150px 1fr 2fr;
}

第一列的宽度为150像素,第二列的宽度是第三列的一半。 

(4)minmax()

   minmax()函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。


grid-template-columns: 1fr 1fr minmax(100px, 1fr);

minmax(100px, 1fr)表示列宽不小于100px,不大于1fr

grid-auto-columns /grid-auto-rows 属性

有时候,一些项目的指定位置,在现有网格的外部。比如网格只有3行 x 3列,但是,8号项目指定在第4行,9号项目指定在第5行。但是某一个项目指定在第5行。这时,浏览器会自动生成多余的网格,以便放置项目。

grid-auto-columns属性和grid-auto-rows属性用来设置,自动创建的多余网格的列宽和行高。它们的写法与grid-template-columnsgrid-template-rows完全相同。如果不指定这两个属性,浏览器完全根据单元格内容的大小,决定新增网格的列宽和行高。

在grid容器里指定自动新增的行高度 grid-auto-rows

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-auto-rows: 50px; 
}

上面代码指定新增的行高统一为50px(原始的行高为100px)。

 介绍了这么多属性,直接看下grid布局实际使用吧。面试又不让你背书,用到的时候百度一下。

实现响应式布局元素自动填充、换行,靠左对齐

 如下是grid布局的使用场景,通常用于响应式布局,比如展示卡片列表,要适配不同宽度的屏幕。只用对父元素即容器设置行高和列宽即可,无需在子元素身上加宽高。

 核心代码

  .container {
    display: grid;
    grid-template-rows: 200px;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    background-color: bisque;
    gap: 5px;
    grid-auto-rows: 200px;
  }
  • display: grid;:这行代码将 .container 元素设置为一个网格布局容器,表示该容器将使用 CSS Grid 布局来排列其子元素。

  • grid-template-rows: 200px;:这行代码定义了网格布局的行高为 200px,意味着容器中的每一行都将具有固定的高度为 200px。

  • grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));:这行代码定义了网格布局的列。其中 repeat(auto-fit, minmax(200px, 1fr)) 表示重复自动适应的列,每列的最小宽度为 200px,最大宽度为 1fr(剩余空间的平均分配)。这样可以实现响应式布局,让列根据容器的宽度自动调整。

  • gap: 5px;:这行代码定义了网格布局中行和列之间的间隔为 5px,即行与行、列与列之间的间距为 5px。

  • grid-auto-rows: 200px;:这行代码定义了未显式指定高度的网格行的高度为 200px,即当内容超出指定行高时,会自动增加新的行,并且这些行的高度也为 200px。

思考:这个场景能不能用flex实现呢

其实是可以的,但是观察一下,当最后一行没有填满,元素如何靠左对齐呢?

用flex布局实现就比较麻烦,要考虑最后一行的个数和对齐方式,会增加额外的比如伪元素填充空白区域以实现效果。

而grid布局将页面划分为多个行列可以很容易实现多行多列对齐布局,这也是grid布局存在的意义。

实现第一个元素占2*2,其余水平、垂直排列

这种布局参考B站首页,左侧会留一个轮播图进行视频推荐

 

实现的原理就是在子元素上利用grid-row 和 grid-column:定义元素在网格中的位置。grid-row:1/3表示从第一行到第三行(包前不包后),占两行。grid-column:1/3表示第一列到第三列

  .element1 {
    grid-row: 1/3;
    grid-column: 1/3;
  }

已经有了flex布局了为什么还新增grid布局?

        Grid 布局与flex布局有一定的相似性,都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。Flexbox主要用于一维布局,即沿着一个方向(水平或垂直)排列元素,适用于构建灵活的、响应式的页面结构。

        而Grid布局则更适合于二维布局,可以同时控制行和列,实现复杂的网格结构。Grid 布局则是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格。Grid 布局远比 Flex 布局强大。网格布局(Grid)是最强大的 CSS 布局方案。

        网格布局它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。以前,只能通过复杂的 CSS 框架达到的效果,现在浏览器内置了。

如何让块级元素垂直居中水平居中,尽可能多的实现?

        让块级元素同时垂直居中和水平居中是前端开发中常见的布局需求,通常可以通过多种方式来实现。这道题目旨在考察对 CSS 布局的熟练程度和灵活运用能力。从最常用的方法开始介绍以下几种实现方式:

  1. flex弹性布局:父元素设置为flex布局,display:flex 并利用justify-content和align-items设置为center实现
  2. absolute绝对定位+transform平移:父元素相对定位,子元素绝对定位,设置left和top50%,transform: translate(-50%, -50%)平移左、上-50%实现
  3. absolute绝对定位+margin:auo:父元素相对定位,子元素绝对定位,设置top、right、left、bottom为0,margin:auto实现
  4. absolute绝对定位+margin:父元素相对定位,子元素绝对定位,设置子元素的margin-left和margin-top为自身宽度的-50%,自身高度的-50%实现。需要具体的子元素宽高
  5. table-cell表格布局:父元素设置为表格布局,display:table-cell,利用text-align:center和vertical-align:middle设置水平和垂直居中,同时子元素的display:inline-block行内块元素。因为text-align是作用在行内元素水平居中的。
  6. grid网格布局:父元素设置为grid布局,display:grid。子元素设置justify-self和align-self为center实现。

除了第4种需要知道子元素的具体宽高,其余均不需要

 1.使用flex弹性布局

利用flex布局的justify-content:center和align-items:center分别实现水平居中和垂直居中。此方法的优点是不需要知道子元素的宽度和高度。

 核心代码:

.container {
    display: flex;
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
}

  完整代码如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div style="margin-bottom: 10px">
      父元素黑色边框包围, 块级元素<span style="color: red">红色背景</span>
    </div>
    <div class="container">
      <div class="element">块级元素</div>
    </div>
  </body>
</html>
<style>
  .container {
    /* 前置条件 */
    height: 400px;
    width: 400px;
    border: 1px black solid;

    /* 垂直居中布局 */
    display: flex;
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
  }
  .element {
    background-color: red;
  }
</style>

2.使用绝对定位+transform属性

子元素使用绝对定位position:absolute;相应父元素显示声明定位为相对定位position:relative。

子元素利用绝对定位,让top和left各位父元素的50%,这时子元素盒子的左上角在中心点。只需平移变换,让子元素的中心与父元素的中心重合。如何平移呢?

让子元素向左移动自身宽度的50%,在向上移动自身高度的50%不就好了。向右和向下是正的,向左和向上是负的哦。

 核心代码:

.container {
    position: relative;
}

.element {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

完整版代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div style="margin-bottom: 10px">
      父元素黑色边框包围, 块级元素<span style="color: red">红色背景</span>
    </div>
    <div class="container">
      <div class="element">块级元素</div>
    </div>
  </body>
</html>
<style>
  .container {
    /* 前置条件 */
    height: 400px;
    width: 400px;
    border: 1px black solid;

    /* 垂直居中布局 */
    position: relative;
  }
  .element {
    background-color: red;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
</style>

3.使用绝对定位+margin:auto——子元素需要宽高,但不需要具体的

        在绝对定位的元素中,设置 margin: auto; 本身是无法实现垂直居中的效果的。因为绝对定位的元素脱离了文档流,margin: auto; 只能在普通流中的块级元素中实现水平居中,对于绝对定位的元素来说,并不会产生垂直居中的效果。

       在绝对定位的情况下,设置了 top: 0; left: 0; right: 0; bottom: 0; 之后,这样 .element 元素会紧贴着 .container 元素的四个边缘。

  这个时候在设置margin: auto; 作用是将 .element 元素在水平和垂直方向上均分剩余空间,从而实现垂直居中的效果。

注意子元素一定是有宽高的,否则子元素直接铺满父元素。

 核心代码

  .container {
    position: relative;
  }
  .element {
    width: 100px;
    height: 100px;

    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
  }

 完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div style="margin-bottom: 10px">
      父元素黑色边框包围, 块级元素<span style="color: red">红色背景</span>
    </div>
    <div class="container">
      <div class="element">块级元素</div>
    </div>
  </body>
</html>
<style>
  .container {
    /* 前置条件 */
    height: 400px;
    width: 400px;
    border: 1px black solid;

    /* 垂直居中布局 */
    position: relative;
  }
  .element {
    /* 前置条件 */
    background-color: red;
    width: 100px;
    height: 100px;

    /* 垂直居中布局 */
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
  }
</style>

 4.使用绝对定位+margin——需要子元素具体宽高

 与示例2一样,子元素绝对定位,top和left设为50%,让子元素的左上角居中,这个时候如果知道子元素的宽高,就可以用margin移动子元素,margin-left和margin-top等于子元素自身的-50%。利用margin的负值特性,margin-left为负值时元素向左移,margin-top为负值时元素向上移

核心代码

  .container {
    position: relative;
  }
  .element {
    width: 100px;
    height: 100px;

    /* 垂直居中布局 */
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px;
    margin-left: -50px;
  }

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div style="margin-bottom: 10px">
      父元素黑色边框包围, 块级元素<span style="color: red">红色背景</span>
    </div>
    <div class="container">
      <div class="element">块级元素</div>
    </div>
  </body>
</html>
<style>
  .container {
    /* 前置条件 */
    height: 400px;
    width: 400px;
    border: 1px black solid;

    /* 垂直居中布局 */
    position: relative;
  }
  .element {
    /* 前置条件 */
    background-color: red;
    width: 100px;
    height: 100px;

    /* 垂直居中布局 */
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px;
    margin-left: -50px;
  }
</style>

 5.使用table-cell表格布局

table-cell 布局通常用于以下场景:

  1. 垂直居中table-cell 布局非常适合实现垂直居中的效果,通过将父元素设置为 display: table;,子元素设置为 display: table-cell; vertical-align: middle;,可以轻松实现子元素在父元素中垂直居中。

  2. 等高列布局:在需要实现等高列布局的情况下,table-cell 布局可以确保多个列的高度相等,使得布局更加整齐和统一。

  3. 水平居中:虽然主要用于垂直居中,但table-cell 布局也可以结合其他属性实现水平居中的效果,例如通过设置 text-align: center; 来实现水平居中。

  4. 网格布局:在一些简单的网格布局场景下,table-cell 布局也可以用来实现类似网格的结构,方便对元素进行排列和对齐。

尽管table-cell 布局在一些特定的场景下具有一定的优势,但在实际开发中,由于 Flexbox 和 CSS Grid 布局的出现,通常更推荐使用这两种布局方式来实现复杂的布局需求,因为它们更灵活、易用,并且能够更好地适应响应式布局的需求。

利用表格布局的特性实现垂直居中,该方法也不需要子元素的具体宽高。写法类似于flex布局,只要记住水平和垂直居中的关键字:text-align、vertical-align即可。

 核心代码

  .container {
    /* 垂直居中布局 */
    display: table-cell;
    text-align: center; /* 水平居中 */
    vertical-align: middle; /* 垂直居中 */
  }
  .element {

    /* 垂直居中布局 */
    display: inline-block;
  }

子元素也可以使用margin:auto实现水平方向居中 ;但使用margin子元素的宽度必须得有,否则水平方向会撑满父元素

  .container {
    /* 垂直居中布局 */
    display: table-cell;
    vertical-align: middle; /* 垂直居中 */
  }
  .element {
    width:100px;
    margin:auto;
  }

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div style="margin-bottom: 10px">
      父元素黑色边框包围, 块级元素<span style="color: red">红色背景</span>
    </div>
    <div class="container">
      <div class="element">块级元素</div>
    </div>
  </body>
</html>
<style>
  .container {
    /* 前置条件 */
    height: 400px;
    width: 400px;
    border: 1px black solid;

    /* 垂直居中布局 */
    display: table-cell;
    text-align: center; /* 水平居中 */
    vertical-align: middle; /* 垂直居中 */
  }
  .element {
    /* 前置条件 */
    background-color: red;

    /* 垂直居中布局 */
    display: inline-block;
  }
</style>

6.使用grid网格布局

使用grid布局,需要将父元素设置为grid。这使得 .container 元素成为一个网格容器,可以通过网格布局来排列其子元素。将子元素设置justify-self:center,align-self:center实现水平和垂直居中。该方法也不需要具体的子元素的宽和高。

 核心代码

.container {
    display: grid;
}

.element {
    justify-self: center; /* 水平居中 */
    align-self: center; /* 垂直居中 */
}

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div style="margin-bottom: 10px">
      父元素黑色边框包围, 块级元素<span style="color: red">红色背景</span>
    </div>
    <div class="container">
      <div class="element">块级元素</div>
    </div>
  </body>
</html>
<style>
  .container {
    /* 前置条件 */
    height: 400px;
    width: 400px;
    border: 1px black solid;

    /* 垂直居中布局 */
    display: grid;
  }
  .element {
    /* 前置条件 */
    background-color: red;

    /* 垂直居中布局 */
    justify-self: center; /* 水平居中 */
    align-self: center; /* 垂直居中 */
  }
</style>

如何实现两侧固定,中间自适应的三栏布局,并且中间元素优先加载?

本题如果要求中间必须先加载出来,其次是左右两端。那么主要考察圣杯布局和双飞翼布局。

 圣杯布局和双飞翼布局达到的效果基本相同,都是侧边两栏宽度固定,中间栏宽度自适应,且中间区域最先加载、渲染。 主要的不同之处就是在解决中间部分被挡住的问题时,采取的解决办法不一样。

  • 圣杯布局是在父元素上设置了padding-left和padding-right,在给左右两边的内容设置position为relative,通过左移和右移来使得左右两边的内容得以很好的展现。
  • 而双飞翼则是在center这个div中再加了一个div来放置内容,在给这个新的div设置margin-left和margin-right 为左右元素预留空间,再通过margin-left设置为负值完成左移和右移。

 1.圣杯布局——中左右

整体思路:

  1. 父元素container预留左右padding用于左右元素占位;
  2. 中 、左、右元素均向左浮动,便于三个块级元素在一行排列;
  3. 中间区域宽度100%,自动撑开中间区域。
  4. 左侧使用margin-left:-100%,先移动到中间区域的左边贴合;在使用定位position:relative;+right:200px(父元素padding预留的宽度,也是左侧子元素的宽度),左元素距离右侧200px,使得左侧贴合父元素的左侧;
  5. 右侧使用margin-left:-200px(右侧区域的宽度),使其移动到中间区域的右边,贴合;再使用定位position:relative+left:200px,使得元素距离左侧200px,贴合父元素的右侧。
  <body>
    <div class="top">头部</div>
    <div class="container">
      <div class="column center">中间区域</div>
      <div class="column left">左边区域</div>
      <div class="column right">右边区域</div>
    </div>
    <div class="bottom">底部</div>
  </body>

圣杯布局逐步拆解:

container父元素用padding预留左右两侧的宽度。

中左右元素均向左浮动,否则没法在一行排列。

得到如下的结果

想办法让左侧移动到预留的位置里

可以使用margin-left:-100%;向左移动父元素宽度看下效果

由于父元素设置了padding所以左元素最多只能移动到跟中间元素左侧对齐的位置。那么如何让左元素贴着父元素的左边呢?

方法是给左元素加相对定位position:relative,让right为200px,距离右侧200px。可以看到下图,左边已经固定好位置了。为什么使用relative?

因为relative是不脱离文档流的,是相对于元素自身原来的位置进行定位的,通过设置right属性为200px,可以将元素向左移动200px,或者说距离右侧200px

    .left {

      width: 200px;
      height: 200px;
      background: pink;
      margin-left: -100%;

      position: relative;
      right: 200px;

    }

 

 同理让右元素移动到右上角。先用margin-left的负值, 向左移动自身的宽度即可,看下效果如下。可以看见右侧元素因为也受到父元素padding的设置,最多只能移动到中间区域的右侧。

    .right {
      width: 200px;
      height: 200px;
      background: lightblue;

      margin-left: -200px;
    }

 

 由左元素移动到最左侧可以推理。让右元素贴右边。也可以使用定位来解决。给元素添加relative属性,让其距离左边200px。

    .right {
      width: 200px;
      height: 200px;
      background: lightblue;
      margin-left: -200px;

      position: relative;
      left: 200px;
    }

但与此同时,右侧还有更简单的方法,设置margin-right:-200px;使得元素上移到最右侧

这是因为给元素的margin-right设置为负值,相当于元素宽度减少了,元素相对于原来的位置左移了自身的宽度。但是这个不好理解,能记住的还是记住上面那个定位实现右侧弄上去的方法。

    .right {
      width: 200px;
      height: 200px;
      background: lightblue;

      margin-right: -200px;
    }

完整效果如下

完整代码如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="top">头部</div>
    <div class="container">
      <div class="column center">中间区域</div>
      <div class="column left">左边区域</div>
      <div class="column right">右边区域</div>
    </div>
    <div class="bottom">底部</div>
  </body>
</html>
<style>
  html,
  body {
    margin: 0;
    padding: 0;
    height: 100%;
  }

  .top {
    height: 10%;
    background: #ccc;
    text-align: center;
  }

  .bottom {
    height: 10%;
    background: #000;
    text-align: center;
    color: white;
  }
  .container {
    height: 80%;
    background: #efefef;

    padding-left: 200px;
    padding-right: 200px;
    .column {
      float: left;
    }
    .left {
      width: 200px;
      height: 200px;
      background: pink;

      margin-left: -100%;
      position: relative;
      right: 200px;
    }
    .center {
      height: 400px;
      width: 100%;
      background: goldenrod;
    }
    .right {
      width: 200px;
      height: 200px;
      background: lightblue;
      margin-right: -200px;
      /* margin-left: -200px;
      position: relative;
      left: 200px; */
    }
  }
</style>

2.双飞翼布局——中左右

而圣杯布局是父元素通过padding预留出来的左右位置。双飞翼布局通过给中间元素在加套一个div,让内部的margin-left和margin-right设置值,为左右元素浮动预留空间。

双飞翼布局的整体思路:

  1. 中、左、右元素均向左浮动,便于三个块级元素在一行排列;
  2. 中间区域外部div宽度100%,自动撑开父元素区域;内部div的margin-left和margin-right分别设置为左区域和右区域的宽度
  3. 左侧使用margin-left:-100%,由于父元素没有padding,左侧贴合左边;
  4. 右侧使用margin-left:-200px(右侧区域的宽度),右侧贴合右边。 
    <div class="top">头部</div>
    <div class="container">
      <div class="center-box column"><div class="center">中间区域</div></div>
      <div class="column left">左边区域</div>
      <div class="column right">右边区域</div>
    </div>
    <div class="bottom">底部</div>

双飞翼布局拆解:

左和右固定宽度,中间center-box的width:100%。要想让中左右在同一行排列,必须三个全部浮动;并且给中间元素设置margin-left和margin-right为200px;

浮动效果如下。但是加了浮动,左和右都没上去,因为中间区域浮动,宽度100%将上面撑满了。

 

调整左边区域,让左边上去,怎么上去呢

可以使用margin的负值,这里的-100%是相对父元素的宽度而不是子元素的宽度。

.left{      margin-left: -100%;}

效果如下所示,左边区域上去了,由于父元素没有设置padding,所以通过margin左移可以实现跟父元素的左侧对齐了。

 同理,向让右元素上去,但是右元素不需要到最左边。怎么让右元素到最右边呢

还是用margin的负值,让右边区域的margin左移自身的宽度不就好了。

.right {

      margin-left: -200px;

    }

效果如下

 完整版代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="top">头部</div>
    <div class="container">
      <div class="center-box column"><div class="center">中间区域</div></div>
      <div class="column left">左边区域</div>
      <div class="column right">右边区域</div>
    </div>
    <div class="bottom">底部</div>
  </body>
</html>
<style>
  html,
  body {
    margin: 0;
    padding: 0;
    height: 100%;
  }

  .top {
    height: 10%;
    background: #ccc;
    text-align: center;
  }

  .bottom {
    height: 10%;
    background: #000;
    text-align: center;
    color: white;
  }
  .container {
    height: 80%;
    background: #efefef;
    .column {
      float: left;
    }
    .left {
      width: 200px;
      height: 200px;
      background: pink;

      margin-left: -100%;
    }
    .center-box {
      width: 100%;

      .center {
        height: 400px;
        background: goldenrod;
        margin-left: 200px;
        margin-right: 200px;
      }
    }

    .right {
      width: 200px;
      height: 200px;
      background: lightblue;

      margin-left: -200px;
    }
  }
</style>

如何实现两栏布局,左侧固定,右侧自适应?

1.改造圣杯布局或双飞翼布局

如果也要求右侧自适应内容优先加载,可以在上面的三栏布局中将最右侧的干掉。

 以双飞翼布局为例,将右侧浮动干掉。中间使用margin-left为左侧预留空间。右侧不预留。

    <div class="container">
      <div class="center-box column"><div class="center">右间区域</div></div>
      <div class="column left">左边区域</div>
    </div>
  .container {
    height: 80%;
    background: #efefef;
    .column {
      float: left;
    }
    .left {
      width: 200px;
      height: 200px;
      background: pink;
      margin-left: -100%;
    }
    .center-box {
      width: 100%;

      .center {
        height: 400px;
        background: lightblue;
        margin-left: 200px;
      }
    }
  }

 2.使用float+margin

如果不强制右侧内容优先加载,可以简单的让左侧浮动,右侧不浮动,通过margin-left为左侧预留空间。

    <div class="container">
      <div class="column left">左边区域</div>
      <div class="column right">右边区域</div>
    </div>

 CSS样式

  .container {
    height: 80%;
    background: #efefef;

    .left {
      width: 200px;
      height: 200px;
      background: pink;
      float: left;
    }
    .right {
      margin-left: 200px;
      background: lightblue;
      height: 400px;
    }
  }

3.flex弹性布局 

还有一种更为简单的使用则是采取:flex弹性布局

父元素设为flex。左侧设固定宽度,右侧自适应,让右侧flex:1撑满剩余空间

    <div class="container">
      <div class="column left">左边区域</div>
      <div class="column right">右边区域</div>
    </div>
  .container {
    height: 80%;
    background: #efefef;

    display: flex;

    .left {
      width: 200px;
      height: 200px;
      background: pink;
    }
    .right {
      background: lightblue;
      height: 400px;

      flex: 1;
    }
  }

谈谈你对BFC的理解

通过询问 BFC 来考察面试者对 CSS 布局的深入理解程度,以及对盒模型、浮动、边距折叠等概念的掌握情况。了解 BFC 的概念和应用可以帮助开发者更好地处理布局问题,避免一些常见的布局 bug,提高页面的稳定性和可维护性。

BFC(Block Formatting Context)是 CSS 中的一个概念,用来描述块级盒子的布局规则。一个元素的 BFC 决定了该元素内部的布局方式,以及与其他元素之间的关系。BFC 是一个独立的渲染区域,内部的元素布局不会影响到外部元素。对 BFC 的理解是:

  1. 清除浮动:BFC 可以包含浮动元素,避免浮动元素对父元素高度的塌陷问题,从而实现自适应高度的布局。计算BFC的高度时,浮动子元素也参与计算。
  2. 垂直布局:BFC 内部的块级元素会在垂直方向上一个接一个的放置,不会出现重叠或交叉的情况。
  3. 边距折叠:BFC 可以阻止垂直方向上相邻块级元素的外边距折叠,确保外边距的计算符合预期。但对于同一个BFC的俩个相邻的盒子的margin还是会发生重叠,与方向无关。
  4. 内部元素独立性:BFC 内部的元素布局不会影响到外部元素,保持了元素之间的独立性。BFC的区域不会与外部的float元素区域重叠

 如何触发BFC

触发BFC的条件包含不限于:

  • 根元素,即HTML元素
  • 浮动元素:float值为left、right
  • overflow值不为 visible,为 auto、scroll、hidden
  • display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
  • position的值为absolute或fixed

场景1——用BFC解决高度塌陷

利用BFC特性,BFC在计算高度时,浮动元素也会参与。触发父级box形成BFC。

 

    <div class="box ">
      <div class="left"></div>
    </div>

<style>

  .box {
    width: 500px;
    margin: 50px auto;
    border: 5px solid red;
  }
  .left {
    width: 200px;
    height: 200px;
    background: #ccc;
    float: left;
  }
</style>

只需要给box加overflow:hidden或overflow:auto即可撑开

场景2——用BFC解决相邻元素外边距塌陷

如下示例,有两个相邻的div,设置width和height,设置margin四周的边距为50px,可以看到两个div中间的margin没有100px,只有50px。

    <div class="parent">
      <div class="top">上面的盒子</div>
      <div class="bottom">下面的盒子</div>
    </div>

 在 CSS 中,相邻的块级元素设置上下边距时可能会引起外边距折叠(margin collapse),导致高度塌陷(height collapse)的现象。这种外边距折叠的存在是为了简化布局和提高灵活性,同时也符合直觉。外边距折叠的规则是在 CSS 规范中明确定义的,它使得相邻元素的外边距可以合并,从而减少了样式表的复杂性。

外边距折叠存在的理由包括:

  1. 简化布局:外边距折叠可以使相邻元素的外边距合并,减少了需要设置的外边距值,简化了布局的过程。
  2. 一致性:外边距折叠符合直觉,使得相邻元素的外边距表现一致,不会出现意外的间距效果。
  3. 节省空间:外边距折叠可以节省页面中元素之间的空间,使得页面看起来更加整洁和紧凑。

虽然外边距折叠有其存在的理由,但在某些情况下,我们希望避免外边距折叠,特别是在需要精确控制元素间距的布局中。这时可以使用 BFC(Block Formatting Context)来解决外边距折叠的问题。通过创建 BFC,可以使得元素处于独立的渲染上下文中,避免外边距折叠的影响,确保布局的稳定性和可控性。

1.使用overflow:hidden

同一个BFC的俩个相邻的盒子的margin会发生重叠。让top和bottom不属于同一个BFC不就可以了。

解法方法: 在上下两个盒子里任选一个,在套一层div,设置overflow:hidden。使用overflow:hidden后,top-box里面形成了BFC,不影响外面。则不会出现margin重叠

    <div class="parent">
      <div class="top-box">
        <div class="top">上面的盒子</div>
      </div>
      <div class="bottom">下面的盒子</div>
    </div>
  .top-box {
    overflow: hidden;
  }

 可以看到,上面的div在垂直方向上都有了自己的50px边距,且不影响旁边的元素。

2.使用display:inline-block布局

同理也是让top形成一个独立的BFC区域

    <div class="parent">
      <div class="top-box">
        <div class="top">上面的盒子</div>
      </div>
      <div class="bottom">下面的盒子</div>
    </div>
  .top-box {
    display: inline-block;
  }

3.使用display:flex布局

给父元素设置flex,垂直方向排列,可以看到垂直方向外边距塌陷解决

    <div class="parent">
      <div class="top">上面的盒子</div>
      <div class="bottom">下面的盒子</div>
    </div>
  .parent {
    display: flex;
    flex-direction: column;
  }

场景3——自适应两栏布局

虽然.aslide为浮动元素,但是main的左边依然会与包含块的左边相接触。如果想让左侧aside单独一列怎么处理,如果不通过设置父元素的padding或者给main加margin呢

这里利用BFC的特性:BFC的区域不会与外部的float元素区域重叠。

触发右侧main为BFC,给main加overflow:hidden。

  .main {
    height: 200px;
    background: #fcc;
    overflow:hidden;
  }

  效果如下,这里你可能让问,为什么不给左边aside加BFC呢

因为aside本身就是float,浮动已经创建了BFC呀。现在是main被浮动影响了,而且这两个是相邻兄弟的关系。让main也是BFC,那两个独立的BFC就不会冲突啦。

如何清除浮动?

清除浮动是为了解决浮动元素造成的父元素高度塌陷或布局错乱的问题。当一个元素浮动之后,其父元素的高度将不再包含该浮动元素,可能导致父元素高度为0,从而影响整体布局。清除浮动的目的是让父元素能够正确地包含浮动元素,保持布局的稳定性和一致性,常见的清除浮动的方法有

  • 父级加overflow:hidden 创建BFC清除浮动
  • 父级设置clearfix
  • 父级也浮动

 示例:有下面两个div,父元素box宽度500px,没有高度;子元素宽高200px;想要效果是子元素将父元素撑开,但由于子元素浮动,脱离文档流,父元素当它不存在。所以父元素没有撑开。

 

    <div class="box ">
      <div class="left"></div>
    </div>

<style>

  .box {
    width: 500px;
    margin: 50px auto;
    border: 5px solid red;
  }
  .left {
    width: 200px;
    height: 200px;
    background: #ccc;
    float: left;
  }
</style>

  1.使用overflow:hidden

使用 overflow 属性:为父元素添加 overflow: hidden; 或 overflow: auto;,可以触发 BFC(块级格式化上下文),从而清除浮动。这种方法不需要额外的元素,但可能会影响内容的溢出。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="box ">
      <div class="left"></div>
    </div>
  </body>
</html>
<style>
  .box {
    width: 500px;
    margin: 50px auto;
    border: 5px solid red;

    overflow: hidden;

  }
  .left {
    width: 200px;
    height: 200px;
    background: #ccc;
    float: left;
  }
</style>

 2.使用空div放在浮动元素下面+clear:both

给浮动元素下面加一个空的div通过clear:both清除浮动,

    <div class="box">
      <div class="left"></div>
      <div class="clear"></div>
    </div>

 设置样式

  .clear {
    clear: both;
  }

 3.父级使用::after伪元素

使用伪元素清除浮动:通过在父元素上应用伪元素并清除浮动,可以避免添加额外的空元素。这种方法比较常用,也比较优雅。

伪元素用于模拟空的块级元素。必须加content,没有content的话伪类不生效;同时还要设置显示方式为块级元素

  .box {
    width: 500px;
    margin: 50px auto;
    border: 5px solid red;

    ::after {
      clear: both;
      content: "";
      display: block;
    }
  }

但是如果清除浮动的元素较多,在每个元素的CSS样式里去添加显然不合理,因此,可以将清除浮动的样式单独提取为一个class,专门用于清除浮动,也就是下面的方法

4.使用clearfix清除浮动类

使用 clearfix 类:定义一个 clearfix 类,将其应用于父元素,通过伪元素清除浮动。

    <div class="box clearfix">
      <div class="left"></div>
    </div>
  .clearfix::after {
    content: "";
    display: block;
    clear: both;
  }

说说设备像素、设备独立像素、css像素、dpr、ppi 之间的区别?

        在css中我们通常使用px作为单位,在PC浏览器中css的1个像素都是对应着电脑屏幕的1个物理像素这会造成一种错觉,我们会认为css中的像素就是设备的物理像素。但实际情况却并非如此。css中的像素只是一个抽象的单位,在不同的设备或不同的环境中,css中的1px所代表的设备物理像素是不同的。当我们做移动端开发时,同为1px的设置,在不同分辨率的移动设备上显示效果却有很大差异,这背后就涉及了css像素、设备像素、设备独立像素、dpr、ppi的概念。

设备像素(物理像素)

        设备像素由屏幕生产之后就不发生改变。设备像素是显示设备(如手机、电脑屏幕)上的最小物理像素点。它们是硬件层面的像素,用于显示图像和文本。设备像素的数量决定了屏幕的分辨率,通常以宽×高的形式表示(例如,我们常说的1920×1080像素分辨率就是用的设备像素单位1920×1080)。

设备独立像素(逻辑像素)

设备独立像素(Device Independent Pixel):与设备无关的逻辑像素,代表可以通过程序控制使用的虚拟像素,是一个总体概念,包括了CSS像素

        设备独立像素就是在设备像素的基础上人为定义的一层逻辑像素。举个例子,一个屏幕的物理像素是2560*1440,但是我们可以人为定义这个屏幕就是1280*720,所以1个设备独立像素就用4个设备像素显示(宽2*高2)。

        传统的pc屏幕,1个设备像素就等于1个设备独立像素;但是现在市面上有很多高清屏幕,比如苹果的retina屏幕,这是由于1个像素点用多个物理像素显示,所以高清屏的画质就更加锐利,没有颗粒感,显示效果出众。设计师出图时会有2x、3x的图,也是为了去适配高清屏幕。现在去看Macbook Pro的屏幕参数都是比较大的比如:2560 x 1600;这里的这个2560 x 1600都是物理像素,实际macbook的逻辑分辨率可能只有1440*900。 

CSS像素

        由于不同的物理设备的物理像素的大小是不一样的,所以这样就产生了一个问题,不同设备之间没有一个统一的单位了;css像素就是为了解决这个问题而出现的,所以要求1px在各个设备之间一定要看起来差不多大小。由于css像素是一个视角单位,所以在真正实现时,为了方便基本都是根据设备像素换算的。浏览器根据硬件设备能够直接获取css像素。

        css像素,是设备独立像素的一种,默认情况下 1css像素=1设备独立像素。CSS像素的大小取决于显示设备的像素密度和缩放级别。无缩放情况下,1个CSS像素等于1个设备独立像素。页面进行缩放操作会引起csspx的变化,假设页面放大一倍,原来的 1px 的东西变成 2px,元素会占据更多的设备像素进行显示。 

思考:那对某个物理设备来说,究竟需要多少设备像素(物理像素)来表示CSS的1px大小呢?

这就引出了dpr,也就是物理像素和css像素的换算关系

 设备像素比dpr(device pixels ratio)

dpr即是设备像素比(dpr 描述的是未缩放状态下,物理像素CSS像素的初始比例关系)

设备像素比(dpr) 是指在移动开发中1个css像素占用多少设备像素,比如dpr=2就代表1个css像素用2x2个设备像素来绘制。

 每英寸像素(ppi)——物理

PPI(每英寸像素密度)指的是显示设备每英寸的物理像素数量。在显示设备上,PPI用于衡量每英寸的像素密度,即屏幕上每英寸的物理像素数量。这个数值越高,屏幕显示的图像和文本就会更加清晰和细腻。

px、em、rem、vw、vh有什么区别?

这道题注意考察你对响应式布局中常见长度单位的理解。px 是绝对长度单位,而 emremvw 和 vh 是相对长度单位,它们各自适用于不同的布局需求和设计场景。

        传统的项目开发中,我们只会用到px%em这几个单位,它可以适用于大部分的项目开发,且拥有比较良好的兼容性。从CSS3开始,浏览器对计量单位的支持又提升到了另外一个境界,新增了remvhvwvm等一些新的计量单位。利用这些新的单位开发出比较良好的响应式页面,适应多种不同分辨率的终端,包括移动设备等

pxemremvw 和 vh 是 CSS 中常用的长度单位,它们各自有不同的特点和用途,下面是它们之间的区别:

px(像素)

   px 是绝对长度单位,表示屏幕上的一个像素点。px 是最常用的长度单位,具有固定的大小,不会随着页面缩放而改变大小。在设计中常用于精确控制元素的尺寸和位置。有些人会把px认为是相对长度,原因在于在移动端中存在设备像素比,px实际显示的大小是不确定的,这里之所以认为px为绝对单位,在于px的大小和元素的其他属性无关

em

   em 是相对长度单位,相对于元素的字体大小来计算。1 em 等于当前元素font-size大小。如果应用在父元素上,则相对于父元素的字体大小。em 可以用于实现相对于字体大小的布局,具有一定的灵活性。

rem

   rem 也是相对长度单位,相对于根元素(html 元素)的字体大小来计算。1 rem 等于根元素的字体大小,不受父元素字体大小的影响。rem 通常用于实现相对于根元素的布局,更容易控制整体布局的比例和缩放。

vw(视口宽度单位)

   vw 表示视口宽度的百分比,1 vw 等于视口宽度的 1%。vw 可以用于根据视口宽度来设置元素的大小,实现响应式设计。通常用于创建相对于视口宽度的布局,适用于移动端和响应式设计。

vh(视口高度单位)

   vh 表示视口高度的百分比,1 vh 等于视口高度的 1%。vh 可以用于根据视口高度来设置元素的大小,实现响应式设计。通常用于创建相对于视口高度的布局,适用于移动端和响应式设计。

em使用场景

使用em可以实现首行缩进,比如设置text-indent:4rem,首行缩进4个字符,由于em根据当前font-size进行的,所以4em可以理解为4个字符的宽度。改变font-size为32px,缩进的仍是4个。示例如下

  .item {
    font-size: 20px;
    text-indent: 4em; /*使用em实现缩进*个字符*/
    width: 300px;
    background: goldenrod;
  }

 使用em实现每行多少个字符,可以将宽度width设置字符数*em

  .item {
    font-size: 20px;
    text-indent: 4em; /*使用em实现缩进*个字符*/
    width: 20em; /*使用em实现每行多少个字符*/
    background: goldenrod;
  }

 rem使用场景

首先rem只跟html的fontsize有关。主要用于移动端的适配

 Web 端:

  1. 响应式设计rem 在 Web 端常用于实现响应式设计。通过将根元素的字体大小设置为相对于视口宽度的百分比,可以实现根据屏幕大小调整元素大小的效果,从而使网页布局更具弹性和适应性。

  2. 相对布局:使用 rem 可以实现相对于根元素字体大小的布局,使得整个页面的布局比例更加统一和一致。这对于保持页面的整体比例和平衡非常有帮助。

在移动端:

  1. 移动端适配:在移动端开发中,使用 rem 可以更好地适配不同设备的屏幕尺寸和分辨率。通过设置根元素的字体大小为相对值,可以实现页面元素的自适应布局,使得页面在不同移动设备上显示效果更一致。

  2. 字体大小控制:在移动端开发中,使用 rem 可以更方便地控制页面中的字体大小。通过设置根元素的字体大小,可以统一调整页面中所有元素的字体大小,使得页面在不同设备上显示更加统一和清晰。

 什么是视口?vh、vw使用场景

视口 != 不等于屏幕大小,视口要去掉浏览器头和底部。如下红色区域才是手机端打开的视口区域。

 设置item的宽等于80vw,高等于80vh,可以发现,当视口宽度反正变化时,item的宽度占整个页面的宽度是固定的,在响应式布局中vw和vh用的很多

  .item {
    font-size: 20px;
    width: 80vw;
    height: 80vh;
    background: goldenrod;
  }

 

 此外还有vmax 和vmin

vmax:vh和vw中较大的值

vmin:vh和vw中较小的值

如果某个元素在手机横屏和竖屏时大小保持一致,可以考虑使用vmax或vmin

你在项目里如何做响应式设计?使用哪些方法?

在项目中实现响应式设计是非常重要的,以确保网站或应用在不同设备上都能够提供良好的用户体验。以下是一些常用的方法和技术来实现响应式设计:

  1. 使用媒体查询:媒体查询是CSS3中的一种技术,可以根据设备的特性(如屏幕宽度、高度、设备类型等)来应用不同的样式。通过在CSS中使用媒体查询,可以针对不同的屏幕尺寸和设备类型提供不同的布局和样式。

  2. 使用相对单位:使用百分比、vw/vh、rem等设置元素的宽高、内外边距、定位相对位置信息等。

  3. 弹性布局:使用弹性布局(Flexbox)和网格布局(Grid)可以使页面中的元素在不同屏幕尺寸下自动调整布局。这些布局技术可以帮助实现灵活的响应式设计,使页面元素能够自适应不同的屏幕大小。

  4. 图片响应式设计:通过使用max-width: 100%;来确保图片在不同屏幕尺寸下能够按比例缩放,避免图片在小屏幕上显示不全或变形的问题。

  5. 移动优先:采用移动优先的设计理念,即首先针对移动设备进行设计和开发,然后再逐步增加针对大屏幕设备的样式和功能。这样可以确保在小屏幕设备上提供良好的用户体验。

  6. 视口设置:通过设置<meta>标签中的viewport属性,可以控制页面在移动设备上的显示方式,包括视口宽度、缩放比例等。

  7. 断点设计:在设计响应式布局时,通常会定义一些断点(breakpoints),即在不同屏幕宽度下应用不同的样式。通过合理设置断点,可以确保页面在各种屏幕尺寸下都能够呈现出最佳的布局效果。

@Media媒体查询

  CSS3增加了更多的媒体查询,就像if条件表达式一样,我们可以设置不同类型的媒体条件,并根据对应的条件,给相应符合条件的媒体调用相对应的样式表。使用@Media查询,可以针对不同的媒体类型定义不同的样式,如:

@media screen and (max-width: 1920px) { ... }

当视口在375px - 600px之间,设置特定字体大小18px

@media screen (min-width: 375px) and (max-width: 600px) {
  body {
    font-size: 18px;
  }
}

        通过媒体查询,可以通过给不同分辨率的设备编写不同的样式来实现响应式的布局

 使用相对单位而非绝对单位

百分比

        通过百分比单位 " % " 来实现响应式的效果。比如当浏览器的宽度或者高度发生变化时,通过百分比单位,可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果

vw/vh

  vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度。 任意层级元素,在使用vw单位的情况下,1vw都等于视图宽度的百分之一。

rem

      在以前也讲到,rem是相对于根元素htmlfont-size属性,默认情况下浏览器字体大小为16px,此时1rem = 16px。可以利用前面提到的媒体查询,针对不同设备分辨率改变font-size的值,如下:

@media screen and (max-width: 414px) {
  html {
    font-size: 18px
  }
}

@media screen and (max-width: 375px) {
  html {
    font-size: 16px
  }
}

@media screen and (max-width: 320px) {
  html {
    font-size: 12px
  }
}

 对CSS选择器优先级的理解

选择器

关于css属性选择器常用的有:

  • id选择器(#box),选择id为box的元素

  • 类选择器(.one),选择类名为one的所有元素

  • 标签选择器(div),选择标签为div的所有元素

  • 后代选择器(#box div),选择id为box元素内部所有的div元素

  • 子选择器(.one>one_1),选择父元素为.one的所有.one_1的元素

  • 伪类选择器(:hover),示例:鼠标悬浮样式

  • 伪元素选择器(:before),示例:在被选元素的前面插入内容

  • 属性选择器([attribute=value]),示例:选择所有使用attribute=value的元素

 什么是伪类?

伪类是用来选择文档中特定状态的元素的选择器。伪类强调某种状态。

打开浏览器控制台,检查元素样式,可以看到如下的伪类。常见的有鼠标悬浮上去的样式,用:hover表示,点击后的样式(如点击完超链接)用:visited表示。伪类不用自己定义,跟着元素走的。

 以下是一些常见的伪类(Pseudo-classes)

  • :hover:鼠标悬停在元素上时应用的样式。
  • :active:元素被激活(例如被点击)时应用的样式。
  • :focus:元素获得焦点时应用的样式。
  • :visited:已访问链接的样式。
  • :first-child:选择父元素下的第一个子元素。
  • :last-child:选择父元素下的最后一个子元素。
  • :nth-child():选择父元素下指定位置的子元素。
  • :not():选择不匹配指定选择器的元素。

 别的记不住不用担心,这辈子可能都遇不到

什么是伪元素

伪元素是用来选择文档中特定部分的元素的选择器。伪元素强调的是占位。

 以下是一些常见的伪元素(Pseudo-elements)

  • ::before:在元素内容之前插入生成的内容。
  • ::after:在元素内容之后插入生成的内容。
  • ::first-line:选择元素的第一行文本。
  • ::first-letter:选择元素的第一个字母。
  • ::selection:选择用户选择的文本部分。

 优先级顺序

优先级顺序指的是将多个分散的优先级分别作用在某个元素上时,哪个优先级更高。注意这里只的不是权重,权重指的是多个优先级累加作用在某个元素。 越能够准确表示某个元素的选择器优先级更高!

优先级顺序:

!important > 内联样式 style > id选择器 > 伪类选择器 > 属性选择器 = class 选择器 > 元素(类型)选择器

伪类选择器之所以比类选择器高,是因为,像:hover 这种鼠标悬浮样式肯定要覆盖原有类的样式才能生效。

当多个规则应用于同一元素时,浏览器会根据这四个部分的优先级来确定应用哪个规则。具体规则如下:

  • 如果两个规则的优先级不同,优先级高的规则将会被应用。
  • 如果两个规则的优先级相同,后面定义的规则将会被应用(即“就近原则”)。
  • 如果两个规则的优先级和位置都相同,则后面的规则将会覆盖前面的规则。

需要注意的是,通用选择器(*)、子选择器(>)、相邻兄弟选择器(+)、通用兄弟选择器(~)等并不影响选择器的优先级,它们只是用来选择元素的不同方式。

理解 CSS 选择器的优先级可以帮助开发者更好地控制样式的应用顺序,避免样式冲突和混乱。 同时注意:继承的样式优先级没有元素自身直接定义的优先级高

 1.思考块级元素1和2分别是什么颜色

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="blue red">块级元素1是什么颜色?</div>
    <div class="red blue">块级元素2是什么颜色?</div>
  </body>
</html>
<style>
  .blue {
    color: blue;
  }
  .red {
    color: red;
  }
</style>

 这题考察的是选择器优先级相等时,就近原则,看下上面就近原则的定义:

"如果两个规则的优先级相同,后面定义的规则将会被应用(即“就近原则”)。"

在这个示例中,虽然 .blue 类和 .red 类都分别设置了 color 属性,但是由于它们同时被应用在同一个元素上,并且在 CSS 样式表中,.blue类的定义在前,.red  类的定义在后,所以最终会以最后定义的样式为准。因此,无论元素上的类顺序如何,最终这两个块级元素都会显示为红色。

优先级权重

选择器的优先级是用来确定当多个规则应用于同一元素,哪个规则将会被应用的一种机制。CSS 选择器的优先级由四个部分组成,分别是:

  1. !important CSS 中用来提高样式优先级的一种机制,它可以覆盖其他样式规则的优先级,使得具有 !important 标记的样式具有最高的优先级。当一个样式规则使用了 !important 标记时,无论其他样式规则的优先级如何,带有 !important 的样式规则都会被应用。

  2. 内联样式(Inline styles):通过在 HTML 元素的 style 属性中直接定义样式,内联样式的优先级最高,优先级为 1000。

  3. ID 选择器:通过 # 符号定义的 ID 选择器,ID 选择器的优先级为 100。

  4. 类选择器、属性选择器和伪类选择器:包括类选择器(.class)、属性选择器([attribute])、伪类选择器(:pseudo-class)等,它们的优先级为 10。

  5. 元素选择器和伪元素选择器:包括元素选择器(element)和伪元素选择器(::pseudo-element),它们的优先级为 1。

 CSS样式有哪些可以继承?

在 CSS 中,有一些样式属性是可以被子元素继承的,这些属性通常会被子元素继承并应用。一般来说,文本相关的样式属性比如字体、颜色等会被子元素继承,而盒模型相关的样式属性比如宽度、高度等则不会被继承。以下是一些常见可以被继承的 CSS 样式属性:

  1. 字体相关:font-familyfont-sizefont-weightfont-style等。
  2. 文本相关:colorline-heighttext-aligntext-decoration等。
  3. 元素间距:marginpadding等。
  4. 列表样式:list-style-typelist-style-position等。

特殊的继承line-height:line-height 是一个既可以继承又可以被重置的属性。

    <div class="parent">
      <span>CSS样式继承,有哪些可以继承</span>
    </div>

 在这个示例中只给parent设置了样式,子元素没有,打开浏览器控制台,可以看到span继承了parent的字体相关属性

  .parent {
    width: 80vw;
    height: 80vh;
    background: goldenrod;

    font-size: 20px;
    font-weight: bold;
    text-indent: 2em;
    text-align: center;
    word-spacing: 10px;
  }

line-height继承

line-height 是一个既可以继承又可以被重置的属性。具体来说

  • 如果子元素没有设置自己的 line-height 属性,那么它会继承父元素的 line-height 值。
  • 如果子元素设置了自己的 line-height 属性,那么它会使用自己设置的值,而不再继承父元素的值。
  • 另外,line-height 还有一个特殊之处在于,它可以用于控制行高,不仅可以设置具体的像素值或百分比值,还可以使用无单位的数值。line-height使用百分比,如line-height:50%,line-height会以父元素字体大小乘以百分比
  • 当使用无单位的数值时,如line-height:1.5,line-height 的计算方式是相对于当前元素的字体大小来确定行高,这种相对单位的使用方式使得 line-height 在响应式设计和移动端适配中具有一定的灵活性。

 比如给这个子元素加line-height50%,计算值可以得到line-height是10px。是父元素font-size的一半

 

CSS如何选择奇数节点、偶数节点?

1.获取所有的奇数节点

使用:nth-child伪类选择器,选择奇数节点有两种方式:

  • :nth-child(odd)可以选择所有奇数节点
  • :nth-child(2n+1)也可以,n从0开始
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
      <li>Item 4</li>
      <li>Item 5</li>
      <li>Item 6</li>
    </ul>

  li:nth-child(2n + 1) {
    background-color: aqua;
  }
  /* li:nth-child(odd) {
    background-color: aqua;
  } */

 

2.获取所有的偶数节点

使用:nth-child伪类选择器,选择偶数节点有两种方式:

  • :nth-child(even)可以选择所有奇数节点
  • :nth-child(2n)也可以,n从0开始
  li:nth-child(2n) {
    background-color: aqua;
  }

  li:nth-child(even) {
    background-color: aqua;
  } 

 

 margin设置负值后会怎么样,有何应用场景

当将 margin 设置为负值时,元素的边距会向相反方向扩展,从而产生一些特殊的效果。以下是一些应用场景和效果:

  1. 调整元素位置:通过将某个元素的 margin 设置为负值,可以使该元素在页面中向特定方向移动,从而微调元素的位置。这在实现一些特殊布局效果时可能会有用。例如前文介绍的圣杯布局或者双飞翼布局都用到margin为负值的移动。

  2. 消除外边距折叠:在某些情况下,可以使用负 margin 来消除外边距折叠(margin collapsing)的影响。通过给相邻元素设置负 margin,可以防止它们的外边距折叠,从而控制它们之间的间距。

  3. 实现重叠效果:通过给元素设置负 margin,可以实现元素之间的重叠效果。这在创建一些特殊的设计效果时可能会有用,比如实现图层叠加效果或者视觉上的重叠效果。

  4. 实现网格布局:在网格布局中,有时候可以使用负 margin 来创建网格间隔或者实现复杂的布局结构。通过巧妙地运用负 margin,可以实现更灵活的网格布局效果。

需要注意的是,使用负 margin 需要谨慎,因为它可能会导致意外的布局问题或者影响可访问性。在使用负 margin 时,建议进行充分的测试和调试,确保达到预期的效果并且不影响页面的整体布局和用户体验。

 margin-left为负值

margin-left为负值,元素自身向左移动

 margin-top为负值

margin-top为负值,元素自身向上移动

 margin-right为负值

margin-right为负值。注意是当前元素的右边元素,向左移动。

margin-bottom为负值

margin-bottom为负值。当前元素的下边元素向上移动。

 如何实现单行/多行文本溢出的省略样式

比如下面的两个div,一个单行溢出,一个多行,只能显示5行溢出。如何让元素溢出用...省略号表示

1. 单行溢出添加省略号

三行代码搞定:

  • white-space:nowrap;不让文字换行
  • overflow:hidden;溢出隐藏
  • text-overflow:ellipsis;溢出添加省略号

首先使用white-space:nowrap不让文字换行

 在使用overflow:hidden;溢出隐藏。但是省略号还没有呢

 添加省略号:text-overflow:ellipsis;溢出添加省略号

完整代码

  .single-line {
    width: 200px;
    height: 30px;
    border: 1px solid blue;
    background: #ccc;
    margin: 50px;
    line-height: 30px;
    /* 单行省略号 */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

 2.多行文本溢出显示省略号

多行文本要显示几行,可以用height/line-height计算,也可根据行数推高度

多行文本溢出显示省略号目前CSS官方还没有出标准,但是在webkit内核浏览器里面是可以做到的。因此,这里要改变盒子的属性,加上厂商的前缀,即display:-webkit-box;

使用webkit盒子的两个属性,每行显示的行数-webkit-line-clamp:5;还有文本排列方向,这里设置为垂直,从上到下,-webkit-box-orient:vertical;同时还有设置超出隐藏overflow:hidden

 完整代码

  .multi-line {
    width: 200px;
    height: 150px;
    line-height: 30px;
    border: 1px solid green;
    background: #ccc;
    margin: 50px;
    /* 多行省略号 */
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 5;
    -webkit-box-orient: vertical;
  }

如何画一个三角形?原理是什么?

边框法:利用width和height为0时,border交叉特性实现。通过给width和height设为0,四周border给相等的宽度,保留一条边的颜色,其余边颜色设置透明transparent即可。如果不设置transparent,默认是黑色。

1.等腰三角形

由下面的示例,依次给出border宽度和颜色变化的效果:给border增加50px,从视角上看border只是更粗写。

如果给border四个方向加不同的颜色呢?

如下所示,可以看到相邻border直接形成了颜色的交叉。谁也没把谁打败自己独占一行。继续,将盒子的宽高设为0,可以看到盒子只有4条边对应的border构成。而每条边对应的是等腰三角形。这个时候如果让一条边保留,其他三条边去掉颜色,但保留宽度,是不是就能留下一个等腰三角形?

 

通过给width和height设为0,四周border给相等的宽度,保留一条边的颜色,其余边颜色设置透明transparent即可。如果不设置transparent,默认是黑色。

 完整代码如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <div class="box1"></div>
      <div class="box2"></div>
      <div class="box3"></div>
      <div class="box4"></div>
    </div>
  </body>
</html>
<style>
  .container {
    display: flex;
    justify-content: space-between;
  }
  .box1 {
    width: 0px;
    height: 0px;
    border-top: 50px solid cyan;
    border-right: 50px solid transparent;
    border-bottom: 50px solid transparent;
    border-left: 50px solid transparent;
  }
  .box2 {
    width: 0px;
    height: 0px;
    border-top: 50px solid transparent;
    border-right: 50px solid pink;
    border-bottom: 50px solid transparent;
    border-left: 50px solid transparent;
  }
  .box3 {
    width: 0px;
    height: 0px;
    border-top: 50px solid transparent;
    border-right: 50px solid transparent;
    border-bottom: 50px solid orange;
    border-left: 50px solid transparent;
  }
  .box4 {
    width: 0px;
    height: 0px;
    border-top: 50px solid transparent;
    border-right: 50px solid transparent;
    border-bottom: 50px solid transparent;
    border-left: 50px solid green;
  }
</style>

2.等腰直角三角形 

 通过四条边相邻两条边的两两组合可以得到90度的等腰直角三角形。保留相邻两条边的颜色,颜色相同,另外两条边设置为transparent透明

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <div class="box1"></div>
      <div class="box2"></div>
      <div class="box3"></div>
      <div class="box4"></div>
    </div>
  </body>
</html>
<style>
  .container {
    display: flex;
    justify-content: space-between;
  }
  .box1 {
    width: 0px;
    height: 0px;
    border-top: 50px solid cyan;
    border-right: 50px solid cyan;
    border-bottom: 50px solid transparent;
    border-left: 50px solid transparent;
  }
  .box2 {
    width: 0px;
    height: 0px;
    border-top: 50px solid transparent;
    border-right: 50px solid pink;
    border-bottom: 50px solid pink;
    border-left: 50px solid transparent;
  }
  .box3 {
    width: 0px;
    height: 0px;
    border-top: 50px solid transparent;
    border-right: 50px solid transparent;
    border-bottom: 50px solid orange;
    border-left: 50px solid orange;
  }
  .box4 {
    width: 0px;
    height: 0px;
    border-top: 50px solid green;
    border-right: 50px solid transparent;
    border-bottom: 50px solid transparent;
    border-left: 50px solid green;
  }
</style>

3.等边三角形

使用边框法,通过高度计算三角形的底边边长得到等边三角形的高

比如想得到如下的等边三角形,边长200px,底边的宽度是由border-left和border-right向中间靠近得到的,所以border-left和border-right各占一半为100px。而高度则由border-top和border-bottom向中间靠近得到的。由三角形计算公式可得border-top=根号3*100=173px

 

  .box1 {
    width: 0px;
    height: 0px;
    border-top: 173px solid transparent;
    border-right: 100px solid transparent;
    border-bottom: 173px solid cyan;
    border-left: 100px solid transparent;
  }

CSS中,有哪些方式可以隐藏页面元素?区别?

通过css实现隐藏元素方法有如下:

  • display:none
  • visibility:hidden
  • opacity:0
  • 设置height、width模型属性为0
  • position:absolute

最常用的还是display:nonevisibility:hidden,其他的方式只能认为是奇招,它们的真正用途并不是用于隐藏元素,所以并不推荐使用它们,不过为了防止面试官恶心你,还是看看怎么实现的吧

1.display:none——dom移除

设置元素的displaynone是最常用的隐藏元素的方法,将元素设置为display:none后,元素在页面上将彻底消失,元素本身占有的空间就会被其他元素占有,也就是说它会导致浏览器的重排和重绘。消失后,自身绑定的事件不会触发,也不会有过渡效果

特点:元素不可见,不占据空间,无法响应点击事件

.hidden1 {
    display:none;
}

看下图示例

当hidden1使用display:none隐藏后下面的div挤上去覆盖了原本hidden1占有的空间。

2. visibility:hidden——占位存在

设置元素的visibilityhidden也是一种常用的隐藏元素的方法。从页面上仅仅是隐藏该元素,DOM结果均会存在,只是当时在一个不可见的状态,不会触发重排,但是会触发重绘,元素边框颜色等都没啦。

特点:元素不可见,占据页面空间,无法响应点击事件

.hidden2 {
    visibility:hidden;
}

3.opacity:0——事件可响应

opacity属性表示元素的透明度,将元素的透明度设置为0后,在我们用户眼中,元素也是隐藏的。不会引发重排,一般情况下也会引发重绘。如果利用 animation 动画,对 opacity 做变化(animation会默认触发GPU加速),则只会触发 GPU 层面的 composite,不会触发重绘

由于其仍然是存在于页面上的,所以他自身的的事件仍然是可以触发的,但被他遮挡的元素是不能触发其事件的。需要注意的是:其子元素不能设置opacity来达到显示的效果

特点:改变元素透明度,元素不可见,占据页面空间,可以响应点击事件

.hidden3 {
    opacity:0;
}

 示例:通过改变元素的透明度隐藏该元素

 4.设置height、width属性为0

将元素的marginborderpaddingheightwidth等影响元素盒模型的属性设置成0,如果元素内有子元素或内容,还应该设置其overflow:hidden来隐藏其子元素

特点:元素不可见,不占据页面空间,无法响应点击事件

.hidden2 {
    margin:0;     
    border:0;
    padding:0;
    height:0;
    width:0;
    overflow:hidden;
}

示例:将盒子所有属性置0,元素不占位

 5.position:absolute

使用position:absolute,元素脱离文档流,将元素移出可视区域。

特点:元素不可见,不影响页面布局

嗯。。。逐渐变态起来。。。非要这样做吗,我觉得没必要。

  .hidden3 {
    position: absolute;
    top: -9999px;
    left: -9999px;
  }

示例:使用定位实现元素消失

 让Chrome支持12px的文字方式有哪些?区别是什么?

Chrome 团队认为汉字小于12px就会增加识别难度,因此Chrome 中文版浏览器通常会将小于 12px 的字体大小自动调整为 12px。但是也可以通过浏览器默认设定页面的最小字号进行更改,用户可以前往 chrome://settings/fonts 根据需求更改最小字体,比如可以支持到0px。而在实际项目中,不能奢求用户更改浏览器设置。对于文本需要以更小的字号来显示,就需要用到一些小技巧。

 手动更改Chrome最小字号

 在chrome浏览器地址栏输入:chrome://settings/fonts

看下最小字体设置是否为0,如果为0,那font-size可以正常显示,否则,只能显示到设置的最小字体。

 正常的字体测试效果如下:

而设置了最小字体,比如设置了最小显示12px字体

那么就得到下面的结果

比12px小的字体也只显示到12px

 解决方法

常见的解决方案有:

zoom

-webkit-transform:scale()

-webkit-text-size-adjust:none

1.Zoom

zoom 的字面意思是“变焦”,可以改变页面上元素的尺寸,属于真实尺寸。其支持的值类型有:

zoom:50%,百分比,表示缩小到原来的一半

zoom:0.5,数字,表示缩小到原来的一半

需要注意的是,Zoom 并不是标准属性,需要考虑其兼容性

测试在最低只能支持12px的Chrome浏览器上,‘显示8px’字体

如果当前测试的字体font-size设置12px,或更小的值;此时浏览器最小只能支持到12px,因此缩放后的字体=12px*0.7的缩放,实现了接近8px的效果。

如果当前测试的font-size更大时,zoom的比例要相应缩小,保证两者乘积接近8px

2.-webkit-transform:scale() 

针对chrome浏览器,加webkit前缀,用transform:scale()这个属性进行放缩

注意的是,使用scale属性只对可以定义宽高的元素生效,所以,像span元素需要设置display:inline-block转为行内块元素

 方法如下,

.font4 {
    font-size: 12px;
    -webkit-transform: scale(0.7);
    display: inline-block;
}

 看下scale是怎么缩放的,这里给font4加个边框

 可以看到,scale是根据盒子的宽高向中心点等比例缩放的,缺点就是缩放后字体位置发生变化

 改变盒子的宽度,改下效果

3.-webkit-text-size-adjust:none(废弃)

该属性用来设定文字大小是否根据设备(浏览器)来自动调整显示大小

属性值:

  • percentage:字体显示的大小;
  • auto:默认,字体大小会根据设备/浏览器来自动调整;
  • none:字体大小不会自动调整
html { -webkit-text-size-adjust: none; }

这样设置之后会有一个问题,就是当你放大网页时,一般情况下字体也会随着变大,而设置了以上代码后,字体只会显示你当前设置的字体大小,不会随着网页放大而变大了

所以,我们不建议全局应用该属性,而是单独对某一属性使用

需要注意的是,自从chrome 27之后,就取消了对这个属性的支持。同时,该属性只对英文、数字生效,对中文不生

 CSS3动画有哪些?

不要怕,这题你会

1.transform改变位移

transform是CSS的一个属性,可以对DOM元素的位置、大小及形状进行矩阵变换,实现各种视觉效果。它相比直接修改DOM元素属性的优点是不影响其他元素的布局和重绘。

transform主要包括平移、缩放、旋转、倾斜四种效果。这四种效果都是通过矩阵变换实现的,但是CSS提供了更简单的函数用于拆解,分别是

  • translate平移
  • scale缩放
  • rotate旋转
  • skew倾斜

 translate函数——平移

接收一到两个参数,表示水平方向和垂直方向平移多少长度

transform:translate(10px);只传一个参数,表示水平方向向右平移10px;

transform:translate(10px,10px);两个参数,表示水平方向向右平移10px,垂直方向向下平移10px; 

transform:translate(50%,50%);百分比,表示水平方向向右移动自身50%宽,垂直方向向下移动自身50%高; 

 rotate函数——旋转

默认情况下以元素的中心作为圆点进行旋转,正数表示顺时针,负数表示逆时针。可以通过transform-origin改变圆点位置。

transform:rotate(30deg);正数,表示顺时针旋转30度

 

transform:rotate(30deg);正数,表示顺时针旋转30度

transform-origin:top left;将旋转中心改为盒子的左上角

 

scale函数——缩放

默认情况下以元素的中心作为圆点进行缩放。接收一个或两个参数,用于设置宽高的缩放比例,和旋转一样,缩放也可以通过transform-origin设置缩放的中心点。

transform:scale(0.6);只传一个元素,表示宽高都缩放至原来的0.6倍

transform:scale(0.5,0.8);传入两个元素,表示宽和高各自的缩放为0.5,0.8倍

transform-origin:top left;将缩放的位置置于左上角 

skew函数——倾斜

接收一到两个参数表示水平或垂直方向倾斜。同理也可使用transform-origin属性设置倾斜圆点

transform:skew(30deg);只传入一个参数表示水平方向倾斜

transform:skew(30deg,10deg);传入两个参数表示水平方向倾斜30度,垂直方向倾斜10度 

 同理可以通过transform-origin改变倾斜中心点

 

matrix函数

matrix可以接收六个参数,可以实现前面介绍的缩放、倾斜、平移。直接变换2D矩阵,但是太复杂的变换直接用现成库实现不好吗

2.transition增加动画效果

transition给DOM元素的属性变换增加过渡效果,比如让属性变换更加平滑或更加自然。

  • 当用户将鼠标悬停在一个元素上时,通过transition属性可以实现元素颜色、大小、位置等属性的平滑过渡,从而增加交互体验。
  • 当用户点击按钮时,通过transition属性可以实现按钮背景色、边框等属性的渐变过渡,增加按钮的交互感和视觉效果。
  • 在图片展示或相册页面中,通过transition属性可以实现图片放大缩小的动画效果,提升用户体验。
  • 在表单输入框中,通过transition属性可以实现输入框边框颜色或阴影的渐变过渡,增加输入焦点时的视觉效果。

使用方式:

选择器{

transition:需要过渡的属性 过渡时长 缓动函数 开始延迟时间;

}

 语法格式
 

 示例:鼠标移动元素放大1.5倍,增加过渡效果

左侧加了transition过渡效果,右边没有,可见过渡动画对视觉的友好

transition-property过渡属性

transition的第一个参数,它用于指定要应用过渡效果的CSS属性。transition-property可以接收以下值:

  1. all:表示所有CSS属性都将应用过渡效果,即元素任何属性的变化都会触发过渡动画。

  2. 属性名称:可以指定单个或多个CSS属性名称,只有指定的属性发生变化时才会触发过渡动画。多个属性名称之间用逗号分隔。

  3. none:表示不应用过渡效果,元素的状态变化将立即生效,没有过渡动画。

示例:给width、height、background-color鼠标悬浮时效果加过渡动画

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <div class="box box1">transition:width 1s ease</div>
      <div class="box box2">transition:height 1s ease</div>
      <div class="box box3">transition:background-color 2s ease</div>
    </div>
  </body>
</html>
<style>
  .container {
    display: flex;
    justify-content: space-around;
    align-items: center;
    height: 600px;
    flex-wrap: wrap;
  }
  .box {
    width: 200px;
    height: 200px;
    border-radius: 8px;
    background-color: #29d2cf;
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .box1 {
    transition: width 1s ease;
    &:hover {
      width: 250px;
    }
  }
  .box2 {
    transition: height 1s ease;
    &:hover {
      height: 250px;
    }
  }
  .box3 {
    transition: background-color 2s ease;
    &:hover {
      background-color: orange;
    }
  }
</style>

 缓动函数——ease

第三个参数,接收一个控制动画的速度曲线参数

ease:在整个过渡过程中,动画速度会逐渐变慢,开始时快速,结束时缓慢,整体效果比较平滑。

ease-in:动画速度会逐渐变快,开始时缓慢,结束时快速,整体效果是加速运动。

ease-out:动画速度会逐渐变慢,开始时快速,结束时缓慢,整体效果是减速运动

ease-in-out:动画速度会先加速再减速,开始和结束时速度较慢,中间时速度较快,整体效果是先加速再减速

 示例:

 缓动函数——linear

以匀速方式过渡动画

 缓动函数——steps

 3.animation和keyframes

CSS中,animation@keyframes是用来创建动画效果的两个关键部分,它们通常是一起使用的

@keyframes:用来定义动画关键帧的规则,其中包含了动画在不同阶段的样式变化。通过在@keyframes规则中定义不同的关键帧(如0%50%100%等),可以指定动画在不同时间点的样式状态。

animation:用于将动画应用到元素上,并指定动画的名称、持续时间、延迟时间、动画类型(如线性、ease-in、ease-out等)、重复次数等参数。通过animation属性,可以控制动画的播放效果和行为。

@keyframes用法

示例:定义一个spin关键帧初始时旋转0度,终止时旋转360度。通过animation将定义的spin关键帧应用在loading类上。指定动画从0旋转到100,在1s完成,并且是匀速的,无限次重复运动

示例:定义多个关键帧,完成如下球体的回弹效果。 让初始和结束在一个位置,50%即0.5秒沿y轴移动25%。

 4.3D渲染

CSS提供3D空间变换。在三维空间中的旋转、缩放、平移等效果。开启3D必须要的参数

    transform-style: preserve-3d;

    perspective: 500px;

transform属性

在3D转换中,可以使用rotateX(), rotateY(), rotateZ(), scaleZ(), translateZ(), translate3d(0, 0, 100px)等函数来实现元素在三维空间中的变换。沿着Z轴平移并不是放大,而是元素距离我们视角更近了。根据最后的3D渲染示例可以看出,沿z轴是纵深的变化。

 rotated属性

rotate3d()函数的语法: rotate3d(x, y, z, angle)

 x、y、z是一个三维向量,表示旋转轴的方向,可以是任意值。angle表示旋转的角度,单位为度(deg)。

 3D渲染示例:

两个box通过绝对定位重叠在一起,让box2超Z轴移动100px;鼠标移入时给父元素添加沿y轴旋转动画,看下3d旋转的效果。

 完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <div class="box1"></div>
      <div class="box2"></div>
    </div>
  </body>
</html>
<style>
  .container {
    width: 200px;
    margin: 0 auto;
    position: relative;
    /* 开启3D必须要的参数 */
    transform-style: preserve-3d;
    perspective: 500px;
    /* 给父元素加过渡 */
    transition: all 1s;
  }
  .container:hover {
    transform: rotate3d(0, 1, 0, 180deg);
  }

  .box1 {
    width: 200px;
    height: 200px;
    background-color: red;
    position: absolute;
  }

  .box2 {
    width: 200px;
    height: 200px;
    background-color: green;
    position: absolute;
    transform: translateZ(100px);
  }
</style>

怎么理解重流和重绘?如何根据重流和重绘思考性能优化方案?

首先必须要知道浏览器的渲染页面的过程

  • 解析HTML,生成DOM树,解析CSS,生成CSSOM树

  • 将DOM树和CSSOM树结合,生成渲染树(Render Tree)

  • Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)

  • Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素

  • Display:将像素发送给GPU,展示在页面上

重绘和重流触发条件

重绘

在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变。

当我们对 DOM 的修改引发了 DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来,如下面情况:

  • 页面一开始渲染的时候(这避免不了)
  • 添加或删除可见的DOM元素
  • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 元素的位置发生变化
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
  • 获取一些特定属性的值:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight

     获取一些特定属性的值有一个共性,就是需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流。除此还包括getComputedStyle方法,原理是一样的

重流

        当我们对 DOM的修改导致了样式的变化(colorbackground-color),却并未影响其几何属性时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式,这里就仅仅触发了重绘。触发回流一定会触发重绘。

 优化方案——减少重绘和重流

        由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。

        当你获取布局信息的操作的时候,如以下的布局信息。浏览器不得不立刻清空队列,触发回流重绘来返回正确的值

如何减少重绘和重流

1.避免频繁操作样式

        如果想设定元素的样式,通过改变元素的 class 类名 。示例:如改变元素的多个样式,可以不用频繁设置style属性,而是使用新的类名进行替换。

const container = document.getElementById('container')
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'

/*使用类名合并样式*/

<style>
    .basic_style {
        width: 100px;
        height: 200px;
        border: 10px solid red;
        color: red;
    }
</style>
<script>
    const container = document.getElementById('container')
    container.classList.add('basic_style')
</script>

 2.避免频繁操作DOM

        在使用 JavaScript 动态插入多个节点时, 可以使用DocumentFragment. 创建后一次插入. 就能避免多次的渲染性能。示例:在一个ul节点中一次性插入1w个li元素

<ul id="parent">
  ...
</ul>

方法一:for循环1w次,每次生成后通过appendChild挂载到父节点上

var parent = document.getElementById("parent");
for (var i = 0; i < 10000; i++) {
  var child = document.createElement("li");
  var text = document.createTextNode("" + i);
  child.appendChild(text);
  parent.appendChild(child);
}

DOM 反复操作会导致页面重绘、回流,效率非常低,而且页面可能会被卡死。

方法二:创建一个div,将1w个节点先挂载在div上,然后将div挂载在parent上

var parent = document.getElementById("parent");
var div = document.createElement("div");
for (var i = 0; i < 10000; i++) {
  var child = document.createElement("li");
  var text = document.createTextNode("" + i);
  child.appendChild(text);
  div.appendChild(child);
}
parent.appendChild(div);

        只跟 DOM 树交互一次,性能方面肯定是大有改善的,不过额外插入了一个 div,如果说不是跟 div 之类的节点进行交互呢,比如在 table 中插入 thtd?这种方式就不适用了。

方法三:使用DocumentFragment接收创建的节点,在使用的时候直接替换元素本身。不需要额外的div建中转。

var parent = document.getElementById("parent");
var frag = document.createDocumentFragment();
for (var i = 0; i < 10000; i++) {
  var child = document.createElement("li");
  var text = document.createTextNode("" + i);
  child.appendChild(text);
  frag.appendChild(child);
}
parent.appendChild(frag);

 处理DocumentFragment减少DOM操作,还可以通过设置元素属性display: none,将其从页面上去掉,然后再进行后续操作,这些后续操作也不会触发回流与重绘,这个过程称为离线操作。示例:更改container的多个位置大小属性

const container = document.getElementById('container')
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'

使用display:none离线操作后

let container = document.getElementById('container')
container.style.display = 'none'
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'
...(省略了许多类似的后续操作)
container.style.display = 'block'

3.使用计算属性缓存

多次访问client\offset\scroll等布局属性时,可以使用计算属性或者变量缓存,避免多次访问。示例:

例如,多次修改一个把元素布局的时候,我们很可能会如下操作

const el = document.getElementById('el')
for(let i=0;i<10;i++) {
    el.style.top  = el.offsetTop  + 10 + "px";
    el.style.left = el.offsetLeft + 10 + "px";
}

每次循环都需要获取多次offset属性,比较糟糕,可以使用变量的形式缓存起来,待计算完毕再提交给浏览器发出重计算请求

// 缓存offsetLeft与offsetTop的值
const el = document.getElementById('el')
let offLeft = el.offsetLeft, offTop = el.offsetTop

// 在JS层面进行计算
for(let i=0;i<10;i++) {
  offLeft += 10
  offTop  += 10
}

// 一次性将计算结果应用到DOM上
el.style.left = offLeft + "px"
el.style.top = offTop  + "px"

4.复杂动画

        对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响。

5.触发css3硬件加速

        可以让transformopacityfilters这些动画不会引起回流重绘

 如果要做优化,CSS提高性能的方法有哪些?

每一个网页都离不开css,但是很多人又认为,css主要是用来完成页面布局的,像一些细节或者优化,就不需要怎么考虑,实际上这种想法是不正确的。作为页面渲染和内容展现的重要环节,css影响着用户对整个网站的第一体验,因此,在整个产品研发过程中,css性能优化同样需要贯穿全程

  1. 合并和压缩CSS文件:将多个CSS文件合并为一个文件,并对CSS代码进行压缩,去除空格、注释和不必要的代码,可以减少文件大小,加快加载速度。

  2. 减少HTTP请求:尽量减少页面中引入的CSS文件数量,可以通过合并CSS文件或内联CSS来减少HTTP请求次数,从而提高页面加载速度。

  3. 使用CSS Sprites:将多个小图标合并成一张大图,并通过CSS的background-position属性来显示不同的图标,可以减少HTTP请求,提高性能。

  4. 避免使用过多的嵌套:过多的CSS选择器嵌套会增加样式匹配的复杂度,影响性能。尽量保持选择器简洁,避免过度嵌套。

  5. 使用简写属性:使用CSS属性的简写形式可以减少代码量,提高性能。例如,使用margin: 0;代替margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;

  6. 避免使用昂贵的选择器:避免使用类似*>~等昂贵的选择器,尽量使用简单的选择器,以提高样式匹配的效率。

  7. 使用局部作用域:在需要局部样式的情况下,可以使用CSS模块化的方法(如BEM、CSS Modules)来限定样式的作用域,避免全局污染,提高性能。

  8. 优化渲染性能:避免使用会触发重排(reflow)和重绘(repaint)的CSS属性,如widthheighttopleft等,可以减少页面重新渲染的次数,提高性能。

  9. 使用GPU加速:通过使用一些CSS属性(如transformopacityfilter等)可以触发GPU加速,提高动画和过渡效果的性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三月的一天

你的鼓励将是我前进的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值