CSS布局面试题

float元素定位

  • 浮动元素的位置是相对于它在包含块中的原始位置来计算的,具体的包含块取决于浮动元素的父元素、祖先元素的定位方式
  • 在 CSS 中,每个元素都有一个包含块,它是元素布局的基准。根据 W3C 规范,一个元素的包含块可以是以下之一:
    根元素:对于 HTML 文档来说,根元素就是 <html> 元素。
    position 属性值为 absolute 或 fixed 的元素。
    具有 transform 或 perspective 属性的元素。
    display 值为 flex 或 grid 的元素。
    其他元素的包含块是最近的块级元素。

实现两栏(三栏)布局的方法

  1. 表格布局
  2. 【重点】float+margin布局(目前主流,注意清除浮动
    • 具体方法见下方,需要特别注意三栏布局时浮动元素与普通元素的放置顺序以及父元素高度塌陷
  3. inline-block布局(注意间隙
  4. flexbox布局(兼容性不好)

两列布局

方法1(float)

  • 设置左左浮动,或设置左右浮动(需要设置父元素的宽度)
    • 如果父级元素没有设置高度,则需要设置overflow:hidden/display:flow-root创建BFC避免父元素“高度坍塌”
      • 当一个父元素的子元素设置了浮动或者绝对定位时,父元素的高度可能会丢失,从而导致所谓的“高度坍塌”问题。这是因为浮动或者绝对定位的元素脱离了文档流,不再占据父元素的空间,导致父元素无法自动计算出正确的高度
      • 通过设置 overflow:hidden,可以触发 BFC(块级格式化上下文)的生成,从而使得父元素包含其浮动或绝对定位的子元素。BFC是一种渲染区域,其中的元素布局是相互独立的,不会影响到外部元素。当父元素生成了BFC后,其高度将被计算为包含其子元素的高度,从而避免了高度坍塌问题。
      • 因此,使用 overflow:hidden 可以有效避免父元素高度坍塌问题。但需要注意的是,这也可能导致溢出内容被隐藏,需要根据实际情况进行权衡和选择。**display:flow-root可以创建无副作用的BFC**
  • 可参考笔记百度前端技术学院 第七天学习笔记(CSS布局)

方法2(float+margin)

  • 只设置一个左浮动元素(红色),然后给右边蓝色列设置与红色浮动等宽的margin-left使得两列不重合
  • **如果右边蓝色列不设置与红色浮动等宽的margin-left**,那么红蓝有一部分是重叠的,虽然不影响蓝色列文字的显示,但是后续文字padding的设置会很麻烦:红色浮动元素,蓝色普通元素,没设置margin-left
  • 红色浮动元素,蓝色普通元素+margin-left

方法3(flex)

  • flex布局
  • 父元素设置为 display: flex左侧元素占据固定的宽度即可,右侧元素会自动占据剩余的宽度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <div class="wrapper">
    <div class="left"></div>
    <div class="right"></div>
    </div>

    <style>
    .wrapper {
    display: flex;
    }
    .left {
    width: 200px;
    }
    </style>
    <div class="wrapper">
    <div class="left"></div>
    <div class="right"></div>
    </div>

    <style>
    .wrapper {
    display: flex;
    }
    .left {
    width: 200px;
    }
    </style>

三列布局(float+margin/子绝父相)

  1. 方法1 【3个浮动元素】:(可参考笔记三列布局(浮动或子绝父相)由于都是浮动元素,所以可以控制自己的宽高,也不用担心没脱离普通元素的文本流所引发的问题。(方法2就要注意这个问题)
    首先设置父级元素的宽度(width: 100%;overflow: hidden;
    1. 可以左左右设置浮动,然后中间设置margin调整间距
    2. 也可以都设置成左浮动,设置margin,调整间距。同样注意父元素设置为BFC清除浮动
  2. 方法2 【1、3列浮动,中间margin留位置】:
    • 设置第1、3列为浮动,中间使用margin将空间留出来给普通元素。
    • 防止第三列浮动元素受到中间普通元素文本的影响,需要在HTML中将最左和最右两个浮动写在一起,中间的普通元素放在最后
    • 错误示范:
      • 左列左浮动,中间使用margin-leftmargin-right预留出左右两列的宽度,第三列右浮动:错误代码+错误效果可以看到蓝色列顶部是在中间列下面的,三列并未对齐
      • 原因:第三列是**浮动,不会脱离文本流**,所以他会给中间的普通元素的文本留出位置。
    • 正确示范:
      • 在HTML中将最左和最右两个浮动写在一起,中间的普通元素放在最后。那么浮动元素:正确代码+效果此时,左边浮动尽量往上靠,右边浮动尽量往上靠,最后中间元素再进去看有没有空间
  3. 方法3 【1、3列绝对定位,中间margin留位置】:
    • 使用子绝父相,将父元素设置为相对定位(position:relative),使用position:absolute将第1、3列设置为绝对定位,中间使用margin将空间留出来给普通元素。
    • 但我们很少这么做,因为:
      • 绝对定位是完全脱离文档流的,缺少适应性方面的特性。浮动定位脱离文档流但不会脱离文本流
      • 绝对定位布局需要手动计算位置、易出现覆盖问题、不利于维护等因素,一般情况下使用浮动进行布局更为常见和方便。
      • 使用绝对定位需要手动计算元素相对于祖先元素的位置和大小,而使用浮动定位则是根据文档流进行布局,通常会更加容易实现和维护
  4. 方法4:flex布局:
    • 将容器设为display:flex,并设置justify-content: space-between,左侧导航、右侧侧边栏和中间内容区域分别作为弹性子元素,设置flex属性以及相应的宽度或基准大小,使其在空间分配上达到期望的效果
      • 左右元素给flex: 1 0 200px,中间元素给flex:2 0 200px,则可以实现一个自适应的三列布局
      • 注意:就算设置了flex的第二属性值flex-shrink,也不能缩小到比flex-basis小。如果窗口宽度小于600px则可以通过媒体查询和@media规则,针对不同屏幕尺寸和设备类型设置不同的样式,使三列布局在不同设备上呈现不同的宽度和排列方式

inline-block布局

  • 思路:文本一样排block元素
  • 优点: 不需要处理清除浮动等问题
  • 缺点: 需要处理两个inline-block元素之间的间隙

inline-block元素中间隙处理方法

  • 因为inline-block元素就像文字一样,两个文字中间一定是有间隙的,所以可以通过设置父元素font-size为0来消除文字间隙
  • 但此时他的子元素(inline-block元素)中的文字也会消失,所以我们可以分别设置inline-block子元素的font-size使子元素中文字可以显示出来。消灭父元素间距(font-size)再给inline-block元素设置font-size

什么时候使用浮动/inline-block布局

  • 总结:处理定宽的问题时使用inline-block布局自适应用浮动布局
  • 使用inline-block布局比浮动布局要简单,元素之间不会产生浮动带来的一些布局问题,比如清除浮动和高度塌陷等。但是处理一些自适应会比较麻烦,浮动布局会更加方便,但会脱离文档流,容易导致重绘DOM树,理论上会增加性能消耗
    • inline-block布局处理自适应麻烦是因为inline-block元素的宽度和高度是由内容决定的,如果要实现一些自适应布局,需要考虑元素的内容大小,可能需要使用一些技巧来控制元素的大小inline-block元素的宽度和高度是由内容决定的,如果要实现一些自适应布局,需要考虑元素的内容大小,可能需要使用一些技巧来控制元素的大小
    • 比如:
      • 如果需要使用inline-block来实现一个响应式的三列布局,可以实现,但是由于inline-block元素的宽度和高度是是由内容决定的,所以需要设置white-space: nowrap或者使用百分比宽度来防止元素换行,还需要在父元素中设置font-size: 0消除元素之间的空格,从而保证布局的正确性,然后还要在每个元素中重新设置字体大小
      • 宽度解决了还要考虑高度,如果三列布局中的某一列高度发生变化,可能会导致它下面的元素也跟着一起移动。(当一行内的元素高度不一时,以高度最大的元素高度为行高,即使高度小的元素周围有空,也不会有第二行元素上浮补位)这个问题可以通过设置vertical-align属性来解决,但是需要注意不同的取值可能会导致不同的效果。
      • 这些操作可能比较麻烦,需要一定的技巧和经验。
  • 区别:
    • float
      1. 默认顶部对齐。如遇到上行有空白,而当前元素大小可以挤进去,那么这个元素会在上行中,float会使元素产生块级框,可以理解为inline-block;但是inline-block元素之间会默认产生空白符,而float之间没有。
      2. float会脱离文档流,容易导致重绘,增加浏览器消耗。
        • 当一个元素浮动之后,它会从文档流中删除,并且不再占据原来的位置,但它的位置可能会对后面的元素造成影响。这时候,浏览器需要重新计算后面元素的位置,并且进行布局,从而可能导致 DOM 树的重绘。而且,如果浮动元素的大小或者位置发生变化,也会触发 DOM 树的重绘。
        • DOM 树的重绘是一种相对耗费性能的操作。如果页面中浮动元素过多或者变化频繁,就可能导致页面性能下降。因此,在使用浮动元素进行布局时,需要注意尽量减少浮动元素的数量,避免频繁地改变浮动元素的位置和大小,从而优化页面性能。DOM 树的重绘是一种相对耗费性能的操作。如果页面中浮动元素过多或者变化频繁,就可能导致页面性能下降。因此,在使用浮动元素进行布局时,需要注意尽量减少浮动元素的数量,避免频繁地改变浮动元素的位置和大小,从而优化页面性能。
      3. 给float的父元素设text-align: center会让float居中。
      4. float元素之间会紧贴。
      5. 注意: W3C中,float会使元素产生块级框,可以理解为inline-block(但实际不是);因为inline-block元素之间会默认产生空白符,而flaot之间没有
    • inline-block
      1. 默认基线对齐。当一行内的元素高度不一时,以高度最大的元素高度为行高,即使高度小的元素周围有空,也不会有第二行元素上浮补位。由于元素的容器属性为block,内容为inline,所以可以视为文字,然后通过vertical-align设置垂直对齐方式
      2. inline-block 不脱离文档流
      3. 给inline-block的父元素设text-align: center,会让inline-block居中。
      4. inline-block元素之间可能会包含html空白节点,这些节点会导致元素之间不紧贴
  • float
    1. 最初设立的初衷是实现环绕排版,也就是说,第一个子元素设float: left或者float: right,第二个子元素保持在文档流里,这样第二个子元素的内容会环绕第一个子元素排版。(浮动元素脱离文档流但不脱离文本流)
    2. 若干子元素居左,若干子元素居右,建议用float。当然,居右的元素如果用position: absolute; right: 0; top: 0;,也是可以的,不过这牵扯到父元素要设relative的问题,而且同样是脱离文档流,float代码更干净
      • 绝对定位是相对于其最近的已定位祖先元素或根元素进行定位,因此在页面中可能会出现一些层叠效果,而且在布局时需要手动计算元素的位置,通过 top、right、bottom、left 这四个属性来定义,如果需要元素水平居中或垂直居中,则还需要使用 transform 属性来实现稍有不慎可能会出现重叠或者错位等问题。相比之下,浮动元素相对于其上一个父元素、祖先元素进行定位,代码量会更加简洁,而且不需要手动计算位置
      • 另外,绝对定位元素的脱离文档流和浮动元素的脱离文档流有一些不同的表现形式。绝对定位元素会完全脱离文档流,不占据原来的位置,因此可能会对后续元素的布局产生影响,需要进行一些调整。而浮动元素则会仍然占据原来的位置,但是对其他元素的布局有影响,需要使用一些清除浮动的方法来处理。
  • inline-block布局:
    1. 要设置某些子元素在一行或者多行内显示,尤其是排列方向一致的情况下,应尽量用inline-block。因为inline-block的元素仍然在当前文档流里面,这样就减少了程序对DOM的更改操作,因为DOM的每一次更改,浏览器会重绘DOM树,理论上会增加性能消耗。float就会增加性能消耗
    2. 希望若干个元素平行排列,且在父元素中居中排列,此时可以用inline-block,且给父元素设text-align: center。还有一种办法是给这若干个元素设一个div父元素,然后给它设宽度,并使用margin: 0 auto。然而,如果考虑到若干个元素需要在窄分辨率下换行,那么inline-block依然是好办法。
    3. inline-block可以用一排a {display: inline-block}实现横向导航栏,无论是居左的导航栏还是居右的都适用,尽管用float也可以实现,但是推荐用inline-block实现。
  • 可参考这篇博客

position:absolute/fixed有什么区别?

  • 前者相对最近的absolute/relative
  • 后者相对屏幕(对于移动端就是viewport),但是近几年在移动端fixed才能正常使用,所以要兼容比较老的版本则最好在移动端别是一fixed

float父元素高度塌陷

  • 父级元素高度塌陷:假设一个float元素是100px的高度,那么他会希望父级元素能撑开100px的高度,但是因为float元素脱硫文档流,所以如果父级里没有其他元素能撑起100px的高度,那么父级高度就会变成0。
  • 为什么需要清除浮动/为什么会存在高度塌陷浮动元素不会占据父元素布局空间,所以父元素布局时不会管浮动元素,所以浮动元素有可能超出父元素从而对其他元素产生影响

解决父级元素高度塌陷(清除浮动)

方法1:overflow属性控制父元素(有副作用)

  • 原理: 创建一个新的BFC来包含所有子元素(包括浮动)
  • 我们可以让父元素能控制自己的宽高(规定浮动元素超出父元素时的管理规则)。给父级元素设置overflow:auto,则父级元素会关注内部的元素,当内部元素超出时进行滚动。(当然overflow:hidden也可以)
  • 缺点:overflow副作用

方法2:使用display:flow-root创建BFC

  • flow-root是一个新的 display 属性值,它可以创建无副作用的BFC
  • 父级元素中使用 display: flow-root 即可创建新的BFC。
  • 比如,给父元素box的样式添加display: flow-root;(例子)

方法3:float元素后清除浮动

  • 可参考笔记清除浮动( clear 属性)
  • 通过给float元素使用**::after 伪元素**来清除浮动:
    1
    2
    3
    4
    5
    6
    7
    8
    .clearfix::after {
    content:".";
    display:block;
    height:0;
    visibility:hidden;
    clear:both;
    }
    .clearfix { *zoom:1; }
  • ::after的意思是在.clearfix内部的最后加入伪元素::after
  • 首先要显示伪元素,所以display:block(display默认inline)
  • 然后为伪元素加入空内容,以便伪元素中不会有内容显示在页面中,所以, content:"";(.也可以,只要加上visibility:hidden;)
  • 其次,为使伪元素不影响页面布局,将伪元素高度设置为0,所以, height:0
  • 最后,要清除浮动,所以,clear:both

after伪元素其实是通过 content 在元素的后面生成了内容为一个点的块级元素。这样一来只要设置这两个非浮动元素之间的距离就行了。


如何适配移动端页面

  • 使用CSS响应式布局
    • 通过媒体查询和 CSS 布局技术,实现在不同屏幕宽度下的不同布局,以适配不同尺寸的设备。
  • 相对单位
  • 移除不必要的元素和样式:在移动端页面中,通常需要考虑性能和加载速度的问题,因此需要删除不必要的元素和样式,比如:隐藏 折行
  • 使用适当的图片大小和格式。为了避免加载过慢或占用过多的带宽,需要对图片进行适当压缩和优化,以及根据不同设备和屏幕尺寸提供不同大小和格式的图片。

,