Flex布局下的overflow 属性

1,046 阅读5分钟

在前端web页面开发中,overflow属性常用于处理一些边界溢出情况,使得页面样式和交互更加友好。

一、基础知识

首先简单介绍下什么是CSS overflow属性。 MDN 上对该属性的解释如下:

设置元素溢出时所需的行为——即当元素的内容太大而无法适应它的区块格式化上下文

overflowoverflow-xoverflow-y 两个属性的简写

主要取值如下:

  • visible(默认值): 内容不能被裁减并且可能渲染到边距盒(padding)的外部。

image.png

  • hidden: 内容将被裁减以适应边距(padding)盒。不提供滚动条,也不支持允许用户滚动(例如通过拖拽或者使用滚轮)。内容可以以编程的方式滚动(例如,通过设置scrollLeft 等属性的值或 scrollTo() 方法), 因此该元素仍然是一个滚动的容器。

image.png

如上图所示,裁剪的内容是会占据文档流方向上的边距空间的。

  • clip: 类似于 hidden,内容将以元素的边距(padding)盒进行裁剪。clip 和 hidden 之间的区别是 clip 关键字禁止所有滚动,包括以编程方式的滚动。该盒子不是一个滚动的容器,并且不会创建新的格式化上下文

  • scroll: 内容将被裁减以适应边距(padding)盒。无论是否实际裁剪了任何内容,浏览器总是显示滚动条,以防止滚动条在内容改变时出现或者消失。打印机可能会打印溢出的内容。

image.png

  • auto: 内容适应边距(padding)盒,它看起来与 visible 相同,但建立了一个新的块级格式化上下文。如果内容溢出,则浏览器提供滚动条。

image.png

二、overflow 生效的条件

溢出是在盒子无法容纳下太多的内容的时候发生的。但前提是必须知道盒子的尺寸,这样才能判断内容是否溢出。

例如,我们可以通过设置widthheight属性来约束盒子的尺寸,当内容过多以至于盒子无法容纳时,内容就会从盒子中溢出。

// css
.container {
  width: 100px;
  height: 50px;
  border: 1px solid #000;
}


// html
<div class="container">
    This box has a height and a width.
</div>

image.png

这时我们就可以通过设置overflow属性来控制溢出的行为。如下,我们将container的overflow设置为auto,就可以看到y轴方向上会出现一个滚动条。

image.png

下面,我们看一个反例:

parent 元素包含 child1 和 child2 两个子元素,parent元素有固定的宽高,我们希望 child2 元素中内容溢出时能够被隐藏。但设置的overflow: hidden 并未生效。主要原因在于我们未给 child2 元素设置宽高,且也无法通过 parent 元素的尺寸来计算 child2 元素的宽高,所有即使设置了 overflow 属性,也无法生效。

// css
.parent {
  width: 100px;
  height: 100px;
  border: 1px solid #000;
}
.child2 {
  overflow: hidden;
}

// html
<div class="parent">
    <div class="child1">child1</div>
    <div class="child2">
      child2 child2 child2 child2 child2 child2 child2 child2 child2 child2 child2 child2
    </div>
</div>

image.png

三、flex布局与overflow

了解了 overflow 的基本知识以及生效条件后,接着进入主题,flex布局下overflow属性何时会生效呢?

3.1 flex布局下子元素内容溢出

假设一个flex布局的元素container,其中包含三个子元素firstsecondthrid。我们希望子元素 first 中内容溢出时会出现滚动条。具体代码如下:

<div class="container">
    <div class="first">
      first first first first first first first first first first first first 
    </div>
    <div class="second">
      second  
    </div>
    <div class="third">
      third
    </div>
</div>
.container {
  display: flex;
  width: 300px;
  padding: 10px 0;
  border: 1px solid #000;
}
.first {
  background-color: pink;
  white-space: nowrap;
  overflow: auto;
}
.second {
  background: yellow;

}
.third {
  background: blue;
}

image.png

从图中可以看出,即使css代码中明明已经设置了 overflow: auto,但first元素中内容溢出也并未出现滚动条。这里overflow未生效的主要原因在于first元素的宽度无从得知。

虽然父容器container显示设置了width为300px,但是默认情况下flex布局下的子元素只会从主轴的起始线开始排成一列,不会根据flex容器的宽度来计算自身的宽度。对此我们可以通过设置子元素的flex-growflex-basis 等属性,使得子元素有迹可循。

  • first 元素添加如下属性,即该元素沾满剩余空间
{
    flex-grow: 1
}

image.png

  • first 元素添加如下属性,即设置一个基础尺寸
{
    flex-basis: 100px
}

image.png

总的来说,如果希望flex布局下某个子元素中的 overflow 属性能够生效,关键在于子元素的尺寸能够确定。

3.2 flex嵌套布局下子元素溢出

如下是一个两层flex嵌套布局,我们希望 fisrt-one元素内容溢出时能够出现滚动条。

<div class="container">
    <div class="first">
      <div class="first-one">
        one one one one one one one one one one one one one one one one one one one one one one
      </div>
      <div class="first-two">
        two
      </div>
    </div>
</div>
.container {
  width: 300px;
  display: flex;
  padding: 10px 0;
  border: 1px solid #000;
}
.first {
  display: flex;
}
.first-one {
  flex: 1;
  background: red;
  white-space: nowrap;
  overflow: auto;
}
.first-two {
  white-space: nowrap;
  background: greenyellow;
}

image.png

如图所示,first-one元素的overflow属性也并未生效。这里我们需要给其父元素fisrt 添加如下属性,即可生效:

.first {
    overflow: hidden;
}

image.png

这里原因可能是因为first元素虽然是flex布局下的子元素,但是本身也是一个flex布局的容器,所以自身不会创建一个新的块级格式上下文(BFC)。而文章开头说了overflow是用于设置元素的内容太大而无法适应它的区块格式化上下文时的行为。所以设置了overflow: hidden后,创建新的区块格式化上下文,就解决了该问题。

关于这个问题的具体原因个人也不是很确定是什么,希望有大神指点!

小结
overflow属性生效的关键在于设置该属性的元素有确定的尺寸(即:宽度和高度)。可以通过如下两种方式去保证元素有确定的尺寸:

  • 通过 heightwidth 设置。(注意:设置百分比时需保证父元素有确定尺寸)
  • 通过 flex 属性设置,对于设置了 flex: 1 的元素需配合 overflow: hidden 一起才能保证该元素有确定尺寸。且其父级flex容器也必须有确定的尺寸。

参考

[1] overflow

[2] 区块格式化上下文