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

在三行布局中:

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

问题是,当主要内容展开时,它会压缩页眉和页脚行:

 flex 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>

小提琴:

我很幸运,我可以使用最新最好的CSS,而不用考虑传统浏览器。我认为我可以使用flex布局,最终摆脱旧的基于表格的布局。出于某种原因,它没有做我想要的……

为了记录,在SO上有许多关于“填充剩余高度”的相关问题,但没有一个能解决我在flex上遇到的问题。参考文献:

363150 次浏览

简单点:DEMO

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>

下面的例子包含了如果展开的中心组件的内容超出了它的边界时的滚动行为。此外,中心组件占用视口中100%的剩余空间。

jsfiddle here

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>

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

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>

对主内容div使用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>

下面是显示解决方案的codepen演示:

  • < a href = " https://codepen。io/mprinc/pen/JjGQvae" rel="nofollow noreferrer">演示-使用display:flex填充剩余的垂直空间

重要的亮点:

  • 所有容器来自htmlbody,….container,应该有高度集为100%
  • 引入flex到任意一个伸缩项将触发基于伸缩分布的项大小计算:
    • 如果只有一个单元格被设置为flex,例如:flex: 1,则该伸缩项将占用剩余的空间
    • 如果存在具有flex属性的不止一个,则计算将更加复杂。例如,如果项1被设置为flex: 1,而项2被设置为se到flex: 2,则项2将占用剩余空间的两倍多
  • 主大小属性

这是我能想到的最简单的例子。关键是

  1. Parent是display:flex
  2. Child有flex-grow:1
  3. Parent必须指定height。如果你在父div上指定了height:100%,那么请记住,父div存在于<body>中,你会看到body不是100%,除非你在body上也添加了height:100%

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>