使用display:flex来填充剩余垂直空间的CSS

355

在一个三行布局中:

  • 顶部行应根据其内容大小调整大小
  • 底部行应具有固定的像素高度
  • 中间行应扩展以填充容器

问题是随着主要内容的扩展,它会挤压标题和页脚行:

Flexing Bad

section {
  display: flex;
  flex-flow: column;
  align-items: stretch;
  height: 300px;
}
header {
  flex: 0 1 auto;
  background: tomato;
}
div {
  flex: 1 1 auto;
  background: gold;
  overflow: auto;
}
footer {
  flex: 0 1 60px;
  background: lightgreen;
  /* fixes the footer: min-height: 60px; */
}
<section>
  <header>
    header: sized to content
    <br>(but is it really?)
  </header>
  <div>
    main content: fills remaining space<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    <!-- uncomment to see it break - ->
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    <!-- -->
  </div>
  <footer>
    footer: fixed height in px
  </footer>
</section>

Fiddle:

我很幸运能够使用最新和最先进的CSS,无需考虑过时的浏览器。我想我可以使用弹性布局来最终摆脱基于表格的旧布局。出于某些原因,它并没有做到我想要的...

记录一下,在SO上有许多相关问题涉及“填充剩余高度”,但没有解决我在弹性布局中遇到的问题。参考资料:


在fiddle上似乎按预期工作。 - Dayan
是的,您需要取消注释其余<div>的内容以查看它如何中断。也许我应该链接损坏的版本。抱歉。 - Zilk
我现在已经将两个版本添加到问题中了。 - Zilk
我现在明白你的意思了。 - Dayan
请问如何让一个 DIV 元素填充剩余的屏幕空间高度? - Jonathan Stray
@JonathanStray 是的,从技术上讲,现在可能是可以关闭的。但我个人建议在使用mjolnir之前先咨询其他CSS金牌专家的意见。 - TylerH
6个回答

409

让它简单: 演示

section {
  display: flex;
  flex-flow: column;
  height: 300px;
}

header {
  background: tomato;
  /* no flex rules, it will grow */
}

div {
  flex: 1;  /* 1 and it will fill whole space left if no flex value are set to other children*/
  background: gold;
  overflow: auto;
}

footer {
  background: lightgreen;
  min-height: 60px;  /* min-height has its purpose :) , unless you meant height*/
}
<section>
  <header>
    header: sized to content
    <br/>(but is it really?)
  </header>
  <div>
    main content: fills remaining space<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    <!-- uncomment to see it break -->
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    <!-- -->
  </div>
  <footer>
    footer: fixed height in px
  </footer>
</section>

全屏显示版本

section {
  display: flex;
  flex-flow: column;
  height: 100vh;
}

header {
  background: tomato;
  /* no flex rules, it will grow */
}

div {
  flex: 1;
  /* 1 and it will fill whole space left if no flex value are set to other children*/
  background: gold;
  overflow: auto;
}

footer {
  background: lightgreen;
  min-height: 60px;
  /* min-height has its purpose :) , unless you meant height*/
}

body {
  margin: 0;
}
<section>
  <header>
    header: sized to content
    <br/>(but is it really?)
  </header>
  <div>
    main content: fills remaining space<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    <!-- uncomment to see it break -->
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br> x
    <br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    <!-- -->
  </div>
  <footer>
    footer: fixed height in px
  </footer>
</section>


36
如果我们希望某个部分的高度达到100%,该怎么办? - Paul Totzke
7
如果你需要让一个网页的头部和底部都固定,那么你只需将高度设置为100%即可。通常情况下,父元素需要设置一个可用的高度,否则代码会出现经典的“null”例子:html、body和section {height:100%;},其中section是body的直接子元素。这个链接 http://jsfiddle.net/7yLFL/445/ 可以演示这个效果。 - G-Cyrillus
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Paul Totzke
2
在Firefox中使用这个解决方案时遇到了问题。我通过将 flex: 1 更改为 flex-grow: 1 来纠正它。感谢您提供的解决方案! - strange_developer
1
喜欢这个答案。干得好。 - Len White
显示剩余15条评论

24

如果扩展的中心组件的内容超出其边界,则下面的示例包括滚动行为。此外,中心组件在视口中占据剩余空间的100%。

在这里查看 jsfiddle

html, body, .r_flex_container{
    height: 100%;
    display: flex;
    flex-direction: column;
    background: red;
    margin: 0;
}
.r_flex_container {
    display:flex;
    flex-flow: column nowrap;
    background-color:blue;
}

.r_flex_fixed_child {
    flex:none;
    background-color:black;
    color:white;

}
.r_flex_expand_child {
    flex:auto;
    background-color:yellow;
    overflow-y:scroll;
}

可用于演示此行为的HTML示例

<html>
<body>
    <div class="r_flex_container">
      <div class="r_flex_fixed_child">
        <p> This is the fixed 'header' child of the flex container </p>
      </div>
      <div class="r_flex_expand_child">
            <article>this child container expands to use all of the space given to it -  but could be shared with other expanding childs in which case they would get equal space after the fixed container space is allocated. 
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc,
            </article>
      </div>
      <div class="r_flex_fixed_child">
        this is the fixed footer child of the flex container
        asdfadsf
        <p> another line</p>
      </div>

    </div>
</body>
</html>

3
可以通过将选择器中的 html 移除,并将 height: 100vh 应用于 body 具体元素来略微简化此操作:https://jsfiddle.net/pm6nqcqh/1/ - Dai
我注意到在可扩展子元素上,flex:auto和flex:1之间存在差异。使用flex:auto时,其他子元素似乎会在需要时缩小,而使用flex:1时它们不会(在Chrome中)。 - mvermand

13
使用flex-grow属性对主要内容的
进行设置,并将display: flex;应用到其父级元素;

body {
    height: 100%;
    position: absolute;
    margin: 0;
}
section {
  height: 100%;
  display: flex;
  flex-direction : column;
}
header {
  background: tomato;
}
div {
  flex: 1; /* or flex-grow: 1  */;
  overflow-x: auto;
  background: gold;
}
footer {
  background: lightgreen;
  min-height: 60px;
}
<section>
  <header>
    header: sized to content
    <br>(but is it really?)
  </header>
  <div>
    main content: fills remaining space<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
  </div>
  <footer>
    footer: fixed height in px
  </footer>
</section>


除了使用“position: absolute”之外,是否有其他解决这个问题(其中“section”高度不固定)的方法? - Ben
1
@ben 如果你知道元素的高度,那么就可以避免使用 position: absolute;。[https://jsfiddle.net/xa26brzf/] - Deepu Reghunath

12

更现代的方法是使用网格属性。

section {
  display: grid;
  align-items: stretch;
  height: 300px;
  grid-template-rows: min-content auto 60px;
}
header {
  background: tomato;
}
div {
  background: gold;
  overflow: auto;
}
footer {
  background: lightgreen;
}
<section>
  <header>
    header: sized to content
    <br>(but is it really?)
  </header>
  <div>
    main content: fills remaining space<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
    
  </div>
  <footer>
    footer: fixed height in px
  </footer>
</section>


2
这已经超出了视口的高度。 - undefined

8

这是我能想到的最简单的示例。关键在于:

  1. 父元素设置 display:flex
  2. 子元素设置 flex-grow:1
  3. 父元素必须指定 height 属性。如果你在父级div上指定了 height:100%,请记住,该父元素存在于 <body> 中,除非你在body标签上也加上 height:100%,否则body不会占满整个屏幕。

http://jsfiddle.net/Ljbzsmvf/2/

div#parent {
  height: 300px;
  display: flex;
  flex-direction: column;
}

div#child {
  border: thin solid red;
  flex-grow: 1;
}
<div id='parent'>
  Parent
  <div id='child'>
    Child
  </div>
</div>


1

这里是展示解决方案的codepen演示

重要亮点:

  • 所有来自 html, body, ... .container 的容器,都应该将高度设置为100%
  • 引入flex到任何一个flex项中都会触发基于flex分配的项目大小计算:
    • 如果只有一个单元格设置了flex,例如:flex: 1,那么这个flex项将占据剩余的空间
    • 如果有多个带有flex属性的项目,则计算会更加复杂。例如,如果项目1设置为flex: 1而项目2设置为flex: 2,则项目2将占用剩余空间的两倍
  • 主要尺寸属性

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接