CSS常见面试题

551 阅读18分钟

1.display: none;visibility: hidden;的区别

(1)display: none; 会让元素从渲染树消失,渲染的时候不会占用空间
visibility: hidden; 不会让元素从渲染树消失,渲染的时候会占用空间, 不会响应hover事件
opacity: 0; 会直接隐藏而且会占用空间,会响应hover事件

(2)display: none; 是非继承属性,子孙节点消失由于元素从渲染树消失造成,
通过修改子孙节点属性无法显示;
visibility: hidden; 是继承属性,子孙节点消失由于继承了hidden,
通过设置visibility: visible; 可以让子孙节点显示

(3)display: none; 会触发文档重排(回流)
visibility: visible; 会触发重绘

(4)屏幕阅读器不会读取display: none; 元素内容
会读取visibility: hidden; 元素内容

2.link@import区别

  • 从属关系区别
    @import是CSS提供的语法规则,只有导入样式表的作用;
    link是HTML提供的标签,不仅仅用于加载CSS文件,还具有reltypehref等属性
  • 加载顺序区别
    加载页面时,link标签引入的CSS文件同时被加载;
    @import引入的CSS将在页面加载完毕后被加载
  • 兼容性区别
    @import是CSS2.1出现的语法,有一定的兼容性问题;
    link是HTML元素,不存在兼容性问题
  • DOM可控制性区别
    可以通过JS操作DOM,插入link标签来改变样式;
    DOM无法控制@import插入样式

3.Render Tree和CSSOM Tree的区别

  • DOM树

    ① 浏览器把获取到的html代码解析成一个DOM树,html中的每个标签都是DOM树中的一个节点,根节点就是我们常用的document对象

    ② DOM树里面包含了所有的html标签,包括display:none;隐藏,还有用JS动态添加的元素等。

  • CSSOM树

    CSS下载完之后对CSS进行解析,解析成CSS对象,然后把CSS对象组装起来,构建CSSOM树

  • Render Tree

    ① CSSOM树和DOM树连接在一起(一 一对应)形成一个Render Tree,渲染树用来计算可见元素的布局并且作为将像素渲染到屏幕上的过程的输入。

    ② 渲染树会忽略display: none;的元素

4.重排与重绘

  • 重排reflow(回流) 当浏览器发现某个部分发生了变化影响了布局,需要倒回去重新渲染。

    添加、删除可见的DOM元素
    元素位置改变、尺寸改变、内容改变
    页面初始化、resize事件等

  • 重绘repaint 改变某个元素的背景色、文字颜色、边框颜色等影响周围或内部布局的属性时,屏幕的一部分要重画,但元素的几何尺寸不变

  • 注意:

    回流必定引起重绘,而重绘不一定会引起回流
    display: none;的节点不会被加入渲染树,而visibility: hidden;会被加入渲染树
    display:none;会触发回流;visibility: hidden;会触发重绘

  • 浏览器工作原理看这篇

5.CSS画三角形&扇形

画三角形

<style>
*{
  margin: 0;
  padding: 0;
}
div{
  width: 0;
  height: 0;
  border-width: 20px;
  border-style: solid;
  border-color: #31c27c transparent transparent transparent;
}
</style>

画扇形

方式一:

<style>
*{
  margin: 0;
  padding: 0;
}
div{
  width: 0;
  border-style: solid;
  border-color: #31c27c transparent transparent transparent;
  border-width: 50px;
  border-radius: 50%;
}
</style>

方式二:(当时灵光乍现想出来的,居然可以...我觉得有点作弊嫌疑)

<style>
*{
  margin: 0;
  padding: 0;
}
div{
  width: 200px;
  height: 200px;
  background: #31c27c;
  /*border-top-right-radius: 100%;*/
  /*border-top-left-radius: 100%;*/
  /*border-bottom-left-radius: 100%;*/
  border-bottom-right-radius: 100%;
}
</style>

6.垂直水平居中一个元素的几种方式

(本来不想写6,7,8的,原因是网上的答案已经非常非常泛滥了,无论面试大小公司都会问到,但是不写的话这篇博客就算不上CSS总结了,所以尽量把我看到的都总结进来)

方式一:绝对定位+margin-left+margin-top控制

1.步骤

1.1 给该元素设置绝对定位
1.2 设置绝对定位元素的 left:50%; top:50%;
1.3 再设置绝对定位元素的 margin-left: -元素宽度的一半px; 
    margin-top: -元素高度的一半px;

2.注意点:

  • 如果只需要水平居中,只需要设置leftmargin-left的值; 如果只需要垂直居中,只需要设置topmargin-top的值;
  • 需要知道元素的宽度
<div></div>

<style>
    div{
      width: 200px;
      height: 200px;
      background: #000;
      position: absolute;
      top: 50%;
      left: 50%;
      margin: -100px 0 0 -100px;
    }
</style>

方式二:绝对定位+margin控制

1.步骤

1.1 给该元素设置绝对定位
1.2 给该元素设置 margin: auto;
1.3 设置left、right、top、bottom的值都为0。

2.注意点

  • 不需要知道元素的宽度
  • 如果仅仅是水平居中,设置 margin: 0 auto;right: 0;left: 0;即可
//水平居中
<div></div>

<style>
    div{
      width: 200px;
      height: 200px;
      background: #000;
      position: absolute;
      margin: 0 auto;
      left: 0;
      right: 0;
    }
</style>

//垂直水平居中
<style>
    div{
      width: 200px;
      height: 200px;
      background: #000;
      position: absolute;
      margin: auto;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
    }
</style>

方式三:CSS3的transform属性

1.步骤

1.1 给该元素设置绝对定位
1.2 设置top: 50%; left: 50%;
1.3 设置transform: translate(-50%,-50%);

2.注意点

  • 2019马上2020了,显然你还是得考虑浏览器兼容问题(笑)
  • 如果是水平居中,设置left: 50%;transform: translateX(-50%);即可;
    如果是垂直居中,设置top:50%;transform: translateY(-50%);即可
<style>
    div{
      width: 200px;
      height: 200px;
      background: #000;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%,-50%);
    }
</style>

方式四:flex布局

1.步骤

1.1 给当做容器的那个元素设置高度和宽度,设置容器的布局方式为伸缩布局
1.2 设置伸缩容器主轴对齐方式和侧轴对齐方式为center

2.注意点

  • 还是兼容性问题
  • 注意搞清楚谁是伸缩容器,上面两个步骤都是给伸缩容器设置的
<style>
    body,html{
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    div{
      width: 200px;
      height: 200px;
      background: #000;
    }
</style>

7.左右两边固定,中间自适应的三栏布局

注意看清楚每种方式的左中右的div是怎么写的!!!谁在中间,谁又嵌套了谁

方式一 自身浮动法

自身浮动法的原理就是使用对左右元素使用分别使用float:leftfloat:right,浮动使左右两个元素脱离文档流,中间元素正常在正常文档流中,使用margin指定左右外边距

<div class="left"></div>
<div class="right"></div>
<div class="center"></div>

<style>
    *{
      margin: 0;
      padding: 0;
    }
    .right, .left{
      width: 200px;
      height: 200px;
      background: teal;
    }
    .left{
      float: left;
    }
    .right{
      float: right;
    }
    .center{
      margin: 0 200px;
      height: 200px;
      background: peru;
    }
</style>

方式二 绝对定位法

绝对定位法原理是将左右两边使用absolute定位,再分别设置left: 0;right: 0;,因为绝对定位使元素脱离文档流,后面的center元素会自然流动到他们上面,然后使用margin属性,留出左右元素的宽度,即可使中间元素自适应屏幕宽度。

<div class="left"></div>
<div class="right"></div>
<div class="center"></div>

<style>
    *{
      margin: 0;
      padding: 0;
    }
    .left, .right{
      width: 200px;
      height: 200px;
      background: peru;
      position: absolute;
    }
    .left{
      left: 0;
    }
    .right{
      right: 0;
    }
    .center{
      margin: 0 200px;
      height: 200px;
      background: indigo;
    }
</style>

方式三 双飞翼布局

1.步骤

1.1 在一个容器, 里面放三个盒子,设置两侧盒子的宽度(固定)
1.2 设置中间盒子的宽度等于容器的宽度(100%)
1.3 让三个盒子都在同一个方向上浮动
1.4 给中间的盒子添加一个子盒子
1.5 给中间盒子的子盒子设置 margin: 0 两侧盒子的宽度;
1.6 设置左边盒子的 margin-left = -100%;
1.7 设置右边盒子的 margin-left = -自身的宽度;
<div class="box">
  <div class="left"></div>
  <div class="right"></div>
  <div class="center">
    <div class="center-in"></div>
  </div>
</div>

<style>
    *{
      margin: 0;
      padding: 0;
    }
    .box{
      width: 100%;
      height: 400px; //可以不要这句,只是为了看到效果
      background: thistle; //可以不要这句,只是为了看到效果
    }
    .left, .right{
      width: 200px;
      height: 200px;
      background: olivedrab;
      float: left;
    }
    .center{
      width: 100%;
      height: 200px;
      background: goldenrod;
      float: left;
    }
    .center-in{
      margin: 0 200px;
      height: 200px;
      background: rosybrown;
    }
    .left{
      margin-left: -100%;
    }
    .right{
      margin-left: -200px;
    }
</style>

方式四 圣杯布局

1.步骤:

1.1 在一个容器里面放三个盒子
1.2 设置两侧盒子的宽度(固定),设置中间盒子的宽度等于容器的宽度(100%)
1.3 设置容器的padding等于两侧盒子的宽度
1.4 让三个盒子都在同一个方向上浮动
1.5 设置左边盒子的 margin-left=-100%;
1.6 通过定位调整左边的盒子, 让左边的盒子不要盖住中间的区域
1.7 设置右边盒子的 margin-left=-自身的宽度;
1.8 通过定位调整右边的盒子, 让右边的盒子不要盖住中间的区域
1.9 给容器设置一个最小的宽度, 防止缩小后变形
<div class="box">
  <div class="center"></div>
  <div class="left"></div>
  <div class="right"></div>
</div>

<style>
    *{
      margin: 0;
      padding: 0;
    }
    .box{
      min-width: 400px;
      padding: 0 200px;
      background: thistle;
    }
    .left, .right{
      width: 200px;
      height: 200px;
      background: olivedrab;
      float: left;
    }
    .center{
      width: 100%;
      height: 200px;
      background: goldenrod;
      float: left;
    }
    .left{
      margin-left: -100%;
      position: relative;
      left: -200px;
    }
    .right{
      margin-left: -200px;
      position: relative;
      left: 200px;
    }
</style>

方式五 flex布局

设置伸缩容器的主轴对齐方式为flex-strat 左右两边固定,中间部分设置flex: 1;

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

<style>
    *{
      margin: 0;
      padding: 0;
    }
    .box{
      width: 100%;
      height: 100%;
      background: yellowgreen;
      display: flex;
      justify-content: flex-start;
    }
    .left, .right{
      width: 200px;
      height: 200px;
      background: purple;
    }
    .center{
      flex: 1;
      background: goldenrod;
    }
</style>

8.清除浮动的几种方式

方式一 给父元素设置高度

浮动的元素因为脱离了标准流,导致父元素的高度撑不起来,此时可以给父元素设置一个固定的高度

方式二 使用overflow: hidden;

overflow: hidden;有三个作用:

  • 清除浮动
    • 可以撑起第一个盒子的高度,可以使第二个盒子使用margin-top,也可以让第一个盒子使用margin-bottom(看下面内外墙法的例子就知道我在说啥了)
    • 需兼容IE6时也要给该元素加上*zoom: 1;
  • 将超出标签范围的(溢出的)内容裁减掉
  • 在开发中,如果两个盒子是嵌套关系,给内盒子设置margin-top: 100px;会导致两个盒子一起被顶下来
    • 解决一:给外层盒子设置边框即可 (边框颜色可以设置为透明色)
    • 解决二:给外层盒子设置overflow: hidden;
    <div class="one">
      <div class="two"></div>
    </div>
    
    <style>
        *{
          margin: 0;
          padding: 0;
        }
        .one{
          width: 200px;
          height: 200px;
          background: aquamarine;
          /*border: 1px solid transparent;*/
          overflow: hidden;
        }
        .two{
          width: 50px;
          height: 50px;
          background: indigo;
          margin-top: 100px;
        }
    </style>
    

方式三 clear 属性

  • clear 属性规定元素的哪一侧不允许其他浮动元素。
  • 取值:
    • left | 在左侧不允许浮动元素。
    • right | 在右侧不允许浮动元素。
    • both | 在左右两侧均不允许浮动元素。
    • none | 默认值。允许浮动元素出现在两侧。
  • 注意点: 给某个元素添加clear 属性之后,再给该元素设置margin 会失效

方式四 外墙法

  • 精髓:在浮动的两盒子间添加一个额外块级元素(所谓的墙),给该元素设置clear: both;属性
  • 注意点:
    • 外墙法不能撑起第一个盒子的高度
    • 外墙法可以使第二个盒子使用margin-top,但是不能让第一个盒子使用margin-bottom
    • 解决:可以通过设置额外标签的高度来增加间隙
    <style>
        *{
          margin: 0;
          padding: 0;
        }
        .one{
          background: indianred;
        }
        .two{
          background: lightseagreen;
        }
        p{
          width: 50px;
          height: 20px;
          float: left;
          background: wheat;
        }
        .wall{
          clear: both;
        }
    </style>
    
    <div class="one">
      <p>文字1</p>
      <p>文字2</p>
      <p>文字3</p>
      <p>文字4</p>
    </div>
    <div class="wall">
    </div>
    <div class="two">
      <p>文字a</p>
      <p>文字b</p>
      <p>文字c</p>
      <p>文字d</p>
    </div>
    

方式五 内墙法

  • 精髓:将额外标签写在第一个盒子的所有子元素的最后,给这个标签设置clear: both;属性
  • 注意点:
    • 内墙法可以撑起第一个盒子的高度
    • 内墙法可以使第二个盒子使用margin-top,也可以让第一个盒子使用margin-bottom
    • 同样也可以直接给额外添加的块级标签添加高度来增加间隙

内墙法和外墙法的区别

  • 额外标签添加的位置不一样
  • 外墙法可以使第二个盒子使用margin-top,但是不能让第一个盒子使用margin-bottom
    内墙法可以使第二个盒子使用margin-top,也可以让第一个盒子使用margin-bottom
  • 内墙法可以撑起第一个盒子的高度(可以自己试一试给第一个盒子设置背景颜色,使用内墙法之后,第一个盒子的背景颜色会显示出来)
    外墙法不能撑起第一个盒子的高度(很显然,因为额外添加的标签和第一个盒子没啥关系)

所谓外墙内墙,可以理解为 额外添加的标签是相对于第一个盒子而言,如果该标签在第一个盒子的外面,就是外墙法;如果该标签在第一个盒子内部,就是内墙法。

方式六 利用伪元素清除浮动

本质和内墙法差不多,都是在第一个盒子内部的最后添加了一个额外的元素

利用伪元素添加的子元素,即使给该元素设置了height: 0;,内容也仍然正常显示;因为内容可以超出元素范围

如果需要子元素不可见,同时设置height: 0;visibility: hidden;

.clearfix::after{
      /*设置添加的子元素的内容为空*/
      content: '';
      /*设置添加的子元素为块级元素*/
      display: block;
      /*设置添加的子元素的高度为0,使其不占用空间*/
      height: 0;
      /*设置添加的子元素不可见*/
      visibility: hidden;
      /*清除子元素左右的浮动*/
      clear: both;
}
.clearfix{
      /*兼容IE6*/
      *zoom: 1;
}

9.BFC(Block Fromatting Context 块级格式化上下文)

什么是Box

一句话:Box: CSS布局的基本单位

  • Box 是 CSS 布局的对象和基本单位,直观点来说,就是一个页面是由很多个Box组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。

  • Box类型:

    • block-level box
      display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context;

    • inline-level box
      display 属性为 inline, inline-block, inline-table 的元素,会生成 inline-level box。并且参与 inline formatting context;

    • run-in box
      CSS3中有的

什么是Formatting Context

Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。

  • 格式化上下文指的是初始化元素定义的环境。包含两个要点,一个是元素定义的环境,一个是初始化。

    在 CSS 中,元素定义的环境有两种,一种是块格式化上下文( Block Formatting Context 简称BFC ),另一种是行内格式化上下文( Inline Formatting Context 简称IFC )。

    这两种上下文定义了在 CSS中元素所处的环境,格式化则表明了在这个环境中,元素处于此环境中应当被初始化,即元素在此环境中应当如何布局等。

  • Formatting Context类型

    • BFC(Block Formatting Context)
      指块级格式化上下文,即一个创建了新的BFC的盒子是独立布局的,盒子里面的子元素的样式不会影响到外面的元素。在同一个BFC中,两个毗邻的块级盒在垂直方向(和布局方向有关)的 margin 会发生折叠。
      BFC决定元素如何对其内容进行布局,也决定与其他元素的关系和相互作用

    • IFC(Inline Formatting Context)
      指内联格式化上下文。IFC的线框(line box)高度由其包含行内元素最高的实际高度计算而来(不受竖直方向的padding/margin的影响)。IFC中的线框一般左右都紧贴整个IFC,但是会被float元素扰乱。同一个IFC下的多个线框高度不同。IFC中是不可能有块级元素的,当插入块级元素时(如在p中插入div),会产生两个匿名块,两者与div分隔开,即产生两个IFC,每个IFC对外表现为块级元素,与div垂直排列。

    • GFC(GridLayout Formatting Context)
      指网格布局格式化上下文,即当把一个元素的display值设置为grid的时候,此元素将会获得一个独立的渲染区域。可以通过在网格容器(grid container)上定义网格定义行(grid definition row)和网格定义列(grid definition column),在网格(grid item)上定义网格行(grid row)和网格列(grid column)来为每一个网格项目定义位置和空间

    • FFC(Flex Formatting Context)
      指自适应格式化上下文,即dispaly值为flexinline-flex的元素将会生成自适应容器。伸缩容器中的每一个子元素都是一个伸缩单元。伸缩单元可以是任意数量的。伸缩单元内和伸缩容器外的一切元素都不受影响。简单地说,Flexbox定义了伸缩容器内伸缩单元的布局。

BFC

1.如何创建BFC

一个HTML元素要创建BFC,则满足下列的任意一个或多个条件即可:

  • 根元素(html)
  • float的值不是none
  • position的值不是static或者relative
  • display的值是inline-blocktable-cellflextable-caption或者inline-flex
  • overflow的值不是visible

BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。

2.BFC布局规则

  • BFC的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算

3.BFC的作用

3.1 利用BFC避免外边距折叠
BFC产生外边距折叠要满足一个条件:两个相邻元素要处于同一个BFC中。所以,若两个相邻元素在不同的BFC中,就能避免外边距折叠
这有详细例子,推荐看!!

3.2 清除内部浮动
浮动元素是会脱离文档流的(绝对定位元素会脱离文档流)。如果一个没有高度或者heightauto的容器的子元素是浮动元素,则该容器的高度是不会被撑开的。我们通常会利用伪元素(:after或者:before)来解决这个问题。

BFC能包含浮动,也能解决容器高度不会被撑开的问题

3.3 使用BFC避免文字环绕

3.4 在多列布局中使用BFC
如果我们创建一个占满整个容器宽度的多列布局,在某些浏览器中最后一列有时候会掉到下一行。这可能是因为浏览器四舍五入了列宽从而所有列的总宽度会超出容器。但如果我们在多列布局中的最后一列里创建一个新的BFC,它将总是占据其他列先占位完毕后剩下的空间。


BFC参考了大量的别人的博客,因为MDN上面说了跟没说一样

这两篇推荐看!!!所有图片来自链接一

www.cnblogs.com/libin-1/p/7…

www.jianshu.com/p/66632298e…

英文文档来自:

浏览器工作原理

CSS3 run-in box

BFC和IFC