【问题标题】:Using Flexbox, have elements stretch to fill gap between rows [duplicate]使用 Flexbox,让元素拉伸以填充行之间的间隙 [重复]
【发布时间】:2017-05-22 13:31:56
【问题描述】:

我觉得问这个有点傻,但是我已经用尽了我对 Flexbox 的了解,所以我希望也许其他人可以进来帮助我。

我的总体目标是让中间行中的两个项目拉伸以填充标题和项目之间的空间,我已经四处搜索,老实说无法弄清楚我应该做什么。我从最底部的CSS Tricks Guide 分叉了代码,并且我做了一些改动。我目前拥有的代码是(以全屏模式打开以使其更清晰):

body,
html {
  height: 100%;
}
.wrapper {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  justify-content: flex-start;
  -webkit-flex-flow: row wrap;
  flex-flow: row wrap;
  height: 100%;
  font-weight: bold;
  text-align: center;
}
.wrapper > * {
  padding: 10px;
  flex: 1 1 100%;
}
.header {
  background: tomato;
  height: 50px;
  flex: 1 1 100%;
}
.footer {
  background: lightgreen;
  height: 50px;
}
.main {
  text-align: left;
  align-self: stretch;
  background: deepskyblue;
}
.aside-1 {
  background: gold;
}
.aside-2 {
  background: hotpink;
}
@media all and (min-width: 600px) {
  .aside {
    flex: 1 auto;
  }
}
@media all and (min-width: 800px) {
  .main {
    flex: 3 0px;
  }
  .aside-1 {
    order: 1;
  }
  .main {
    order: 2;
  }
  .aside-2 {
    order: 3;
  }
  .footer {
    order: 4;
  }
}
body {
  padding: 2em;
}
<div class="wrapper">
  <header class="header">Header</header>
  <article class="main">
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
      Mauris placerat eleifend leo.</p>
  </article>
  <aside class="aside aside-1">Aside 1</aside>

  <footer class="footer">Footer</footer>
</div>

是否有可能在 flexbox 中实现这一目标无需更改 HTML,还是我应该寻找另一种方式来实现这一目标?

【问题讨论】:

  • @Ced 这是一个非常接近的副本,尽管微不足道的区别可以轻松实现,只需稍加思考即可。
  • @Jhecht 谢谢你的问题,我觉得这很好,这就是为什么当有人说这是骗子时我在评论部分发疯的原因。请检查我的答案,我花了很长时间。
  • 据我所知,,如果不更改标记是不可能得到这个结果的
  • @vals 由于页眉和页脚的高度是固定的,所以它是可行的 :) .... 可行!= 推荐
  • @LGSon 我的意思是,让 flex 做布局......当然你总是可以自己计算高度(如 kukkuz 回答,或你自己)

标签: html css flexbox


【解决方案1】:

当人们告诉你如何解决问题时,他们并没有告诉你为什么你没有得到预期的结果。我认为部分原因是他们中的大多数人都错过了实际问题。我发现这真的很有趣。

让我先解决一些问题:

Flex-direction::实际目的是指项目显示的方向。但是它不准确

现在假设如果方向设置为行,这意味着每个项目必须具有容器的高度,并且它们应该彼此相邻放置。换句话说,容器必须被视为一行,而项目是列。

.c{
  display: flex;
  width: 400px;
  height:100px;
}
.c1{
  flex-grow: 1;
  background:gold;

}
.c2{
  flex-grow: 1;
  background:red;
}
<div class="c">
    <div class="c1"></div>
    <div class="c2"></div>
</div>

我没有指定高度,项目填充了行的高度并像列一样相互堆叠。


当您指定高度时,项目将采用您定义的高度,但不会改变行的高度:

.c{
  display: flex;
  width: 400px;
  height: 100px;
}
.c1{
  flex-grow: 1;
  height: 40px;
  background:gold;

}
.c2{
  flex-grow: 1;
  background:red;
}
<div class="c">
    <div class="c1"></div>
    <div class="c2"></div>
</div>

红色立方体仍然产生垂直空间,因为行的高度没有改变。


flex grow:分配给不同项目的可用空间量。

.c{
    display: flex;
    width: 400px;
  }

.c1{
  flex-grow: 1;
  background:gold;
  }

.c2{
  flex-grow: 1;
  background:red;
  }
    <div class="c">
        <div class="c1">AAAAAAAAAAAAA</div>
        <div class="c2"></div>
    </div>

尽管具有相同的 flex-grow 值,但这两个项目的大小并不相同,这是因为空闲空间分布在它们之间,但黄色矩形开始时更大。


首先让我们使用 flex-wrap : wrap:

.c{
  display: flex;
  flex-wrap: wrap;
  border: 1px solid black;
  width: 400px;
  height:100px;
}
.c1{
  width:200px;
  background:gold;

}
.c2{
  width:200px;
  background:red;
}

.c3{
  width:100px;
  background:orange;

}
.c4{
  width:300px;
  background:green;
}
<div class="c">
    <div class="c1"></div>
    <div class="c2"></div>
    <div class="c3"></div>
    <div class="c4"></div>
</div>

正如我们所看到的,当我们超出项目开始的可用宽度时,有效地创建了另一行。


现在解决您的问题:

如果我们以上面的例子设置第一项的高度呢?让我们看看:

    .c{
      display: flex;
      flex-wrap: wrap;
      border: 1px solid black;
      width: 400px;
      height:100px;
    }
    .c1{
      width:200px;
      height: 30px;
      background:gold;

    }
    .c2{
      width:200px;
      background:red;
    }

    .c3{
      width:200px;
      background:orange;

    }
    .c4{
      width:200px;
      background:green;
    }
<div class="c">
  <div class="c1"></div>
  <div class="c2"></div>
  <div class="c3"></div>
  <div class="c4"></div>
</div>

就像在你的 sn-p 中一样。

让我们看另一个例子:

        .c{
          display: flex;
          flex-wrap: wrap;
          border: 1px solid black;
          width: 600px;
          height:100px;
        }
        .c1{
          width:400px;
          height: 35px;
          background:gold;

        }
        .c2{
          width:200px;
          background:red;
        }

        .c3{
          width:200px;
          background:orange;

        }
        .c4{
          width:200px;
          background:green;
        }
        .c5{
          width:200px;
          background:purple;
        }
    <div class="c">
      <div class="c1"></div>
      <div class="c2"></div>
      <div class="c3"></div>
      <div class="c4"></div>
      <div class="c5"></div>
    </div>
  1. 放置 400px X 35px 的黄色立方体并跨越 2 列,然后放置 200px 的红色立方体并跨越 1 列。

  2. 此时所有矩形的高度均为 0,除了第一个为 35px 的矩形。

  3. 剩余的垂直空间在行之间划分,以生成整个垂直空间。因此剩余的垂直空间是 100-35 = 65px。 分成 2 行 = 32.5。第一行得到 35 + 32.5,第二行得到 32.5px 高度。

另一个让事情更清楚的例子:

    .c, .d{
              display: flex;
              flex-wrap: wrap;
              border: 1px solid black;
              width: 600px;
              height:100px;
            }

            .c1{
              flex-shrink: 0;
              width:400px;
              height: 0px;
              background:gold;

            }
            .c2{
              width:200px;
              background:red;
            }

            .c3{
              width:200px;
              background:orange;

            }
            .c4{
              width:200px;
              background:green;
            }
            .c5{
              width:200px;
              background:purple;
            }


            .d1{
              width:400px;
              height: 50px;
              background:gold;

            }
            .d2{
              width:200px;
              background:red;
            }

            .d3{
              width:200px;
              background:orange;

            }
            .d4{
              width:200px;
              background:green;
            }
            .d5{
              width:200px;
              background:purple;
            }
First item has 0px height, the vertical space remaining (100px) is divided between the 2 rows. Both row have 50px height
        <div class="c">
          <div class="c1"></div>
          <div class="c2"></div>
          <div class="c3"></div>
          <div class="c4"></div>
          <div class="c5"></div>
        </div>

First item has 35px height, the vertical space remaining (65px) is divided between the 2 rows.
        <div class="d">
          <div class="d1"></div>
          <div class="d2"></div>
          <div class="d3"></div>
          <div class="d4"></div>
          <div class="d5"></div>
        </div>

要解决此问题,您可以使用calc() 来计算其他行的高度,就像其他人建议的那样。原因是没有更多的可用垂直空间可以共享。

            .c{
              display: flex;
              flex-wrap: wrap;
              border: 1px solid black;
              width: 600px;
              height:100px;
            }
            .c1{
              width:400px;
              height: 35px;
              background:gold;

            }
            .c2{
              width:200px;
              background:red;
            }

            .c3{
              height:calc(100% - 35px);
              width:600px;
              background:green;

            }
            
            
        <div class="c">
          <div class="c1"></div>
          <div class="c2"></div>
          <div class="c3"></div>
        </div>

【讨论】:

  • 这是一个非常棒的答案。
  • @Jhecht 啊哈我花在这上面的时间比我应该的要多,但这真的让我很感兴趣!大声笑
【解决方案2】:

想法是将它们包裹在容器周围并在该容器上使用flex-grow:1;,这将使容器填充页眉和页脚之间的空间..

然后在@media查询中,把这个容器的flex-direction改成row。这将使.mainaside 在大屏幕上并排出现。

body,
html {
  height: 100%;
}
.wrapper {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  justify-content: flex-start;
  flex-direction:column;
  height: 100%;
  font-weight: bold;
  text-align: center;
}
.wrapper > * {
  padding: 10px;
}
.header {
  background: tomato;
  height: 50px;
  flex-shrink:0;
}
.footer {
  background: lightgreen;
  height: 50px;
  flex-shrink:0;
}
.main {
  text-align: left;
  //align-self: stretch;
  background: deepskyblue;
  padding:10px;
}
.main p{
  margin:0;
  padding:0;
}
.aside-1 {
  background: gold;
}
.aside-2 {
  background: hotpink;
}
.container{
  width:100%;
  margin:0;
  padding:0;
  flex-grow:1;
  flex-shrink:0;
}
@media all and (min-width: 600px) {
  .aside {
    flex: 1 auto;
  }
}
@media all and (min-width: 800px) {
  .container{
    display:flex;
    flex-direction:row;
  }
  .main {
    flex: 3 0px;
    flex-grow:1;
    flex-shrink:0;
  }
  .aside-1 {
    order: 1;
    flex-grow:1;
    flex-shrink:0;
  }
  .main {
    order: 2;
  }
  .aside-2 {
    order: 3;
  }
  .footer {
    order: 4;
  }
}
body {
  padding: 2em;
}
<div class="wrapper">
  <header class="header">Header</header>
  <div class="container">
  <article class="main">
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
      Mauris placerat eleifend leo.</p>
  </article>
  <aside class="aside aside-1">Aside 1</aside>
    </div>
  <footer class="footer">Footer</footer>
</div>

【讨论】:

  • 有没有办法做到这一点不使用使用包装元素?
  • 我不认为有,因为有盒子必须增长。让我试试,给我 10 个。如果我能挥杆,我会告诉你的。
  • 非常感谢@kittyCat
  • 如果你能想出办法我会很感激,但如果不知道我很感激你的帮助。我将 kukkuz 标记为正确只是因为他确实设法在不更改 HTML 的情况下获得了一个工作示例,但正如评论中所解释的那样,除非绝对必要,否则我不喜欢使用 calc()(尽管项目最终可能需要使用它)。跨度>
  • @Jhecht 来吧伙计,你接受的答案和我的完全一样。他也使用了包装元素。无论如何,他的答案在 chrome 中也不起作用。
【解决方案3】:

当你使用 wrapping flexbox 时,不能填充 cross-axis 方向上的剩余空间 - 我猜你需要 flexbox

但您可以将其作为快速修复

  1. align-content: center 添加到flexbox(用于重置默认stretch 值)

  2. 使用calc 调整高度(已删除body 填充和边距以进行说明)

请看下面的演示:

body,
html {
  height: 100%;
}
.wrapper {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  justify-content: flex-start;
  -webkit-flex-flow: row wrap;
  flex-flow: row wrap;
  height: 100%;
  font-weight: bold;
  text-align: center;
  align-content: center; /* ADDED THIS */
}
.wrapper > * {
  padding: 10px;
  flex: 1 1 100%;
}
.header {
  background: tomato;
  height: 50px;
  flex: 1 1 100%;
}
.footer {
  background: lightgreen;
  height: 50px;
}
.main {
  text-align: left;
  align-self: stretch;
  background: deepskyblue;
  height: calc(50vh - 90px); /* ADDED THIS */
}
.aside-1 {
  background: gold;
  height: calc(50vh - 90px); /* ADDED THIS */
}
.aside-2 {
  background: hotpink;
}
@media all and (min-width: 600px) {
  .aside {
    flex: 1 auto;
  }
}
@media all and (min-width: 800px) {
  .main {
    flex: 3 0px;
  }
  .aside-1 {
    order: 1;
    height: calc(100vh - 160px); /* ADDED THIS */
  }
  .main {
    order: 2;
    height: calc(100vh - 160px); /* ADDED THIS */
  }
  .aside-2 {
    order: 3;
  }
  .footer {
    order: 4;
  }
}
body {
  /* padding: 2em;*/
  margin: 0; /* ADDED THIS */
}
<div class="wrapper">
  <header class="header">Header</header>
  <article class="main">
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
      Mauris placerat eleifend leo.</p>
  </article>
  <aside class="aside aside-1">Aside 1</aside>

  <footer class="footer">Footer</footer>
</div>

使用calc 不是很整洁,您可能想在此处使用嵌套flexbox(如果可以更改html):

  1. mainaside-1 添加一个wrapper 并使其在row 方向上成为一个wrapping flexbox

  2. flex: 1 添加到此包装器 以填充headerfooter 之间的垂直空间

请看下面的演示:

body,
html {
  height: 100%;
}
.wrapper {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  /*-webkit-flex-flow: row wrap;*/
  /*flex-flow: row wrap;*/
  flex-direction: column;
  height: 100%;
  font-weight: bold;
  text-align: center;
}
.wrapper > * {
  padding: 10px;
  /*flex: 1 1 100%;*/
}
.header {
  background: tomato;
  height: 50px;
  /*flex: 1 1 100%;*/
}
.footer {
  background: lightgreen;
  height: 50px;
}
.main {
  text-align: left;
  align-self: stretch;
  background: deepskyblue;
}
.aside-1 {
  background: gold;
  flex: 1 auto;/* ADDED THIS */
}
.aside-2 {
  background: hotpink;
}
.wrapper > section { /* ADDED THIS */
  display: flex; 
  flex-flow:row wrap;
  flex: 1;
  padding: 0;
  overflow: auto;
}
@media all and (min-width: 600px) {
  .aside {
    flex: 1 auto;
  }
}
@media all and (min-width: 800px) {
  .main {
    flex: 3 0px;
  }
  .aside-1 {
    order: 1;
  }
  .main {
    order: 2;
  }
  .aside-2 {
    order: 3;
  }
  .footer {
    order: 4;
  }
}
body {
  /*padding: 2em;*/
  margin: 0;
}
<div class="wrapper">
  <header class="header">Header</header>
  <section>
    <article class="main">
      <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
        Mauris placerat eleifend leo.</p>
    </article>
    <aside class="aside aside-1">Aside 1</aside>
  </section>
  <footer class="footer">Footer</footer>
</div>

【讨论】:

  • 到目前为止,这绝对是最好的答案。我正在摆弄我打算使用的实际 HTML / CSS 来看看这是否有效。
  • 评论我为什么将这个答案标记为已接受:它的第二个代码 sn-p 特别是最终最适合实际的 HTML——我仍在摆弄它(因为我必须重写项目中的一些其他 CSS)但效果最好。我希望喜欢 不理会HTML(就像第一个sn-p 一样),但我也喜欢避免使用calc(),除非有必要。非常感谢 kukkuz!
  • 在第二个演示中——使用 chrome——.aside-1 元素位于页脚后面。虽然将overflow: auto 添加到,wrapper &gt; * 表明它可以正确溢出。 .main, .aside-1, .aside-2 { overflow: auto; } 会为这两个示例产生相同的结果。
  • 我没有注意到由于我用来填充空间的内容的长度(没有足够长注意到它在页脚后面)
  • @kukkuz 我还在.main 元素中添加了overflow:auto,以确保背景颜色跟随文本(否则它们会在第一个渲染边界处停止)
【解决方案4】:

在阅读了所有其他答案后,我决定发布自己的答案。

我可能错过了已经发布的内容或误解了问题,但对我来说这应该是最简单的解决方案,无需更改任何标记。

如果这回答了您的问题,我将添加一个简短的解释为什么/如何工作。

html, body {
  margin: 0;
}
.wrapper {
  display: flex;
  flex-direction: column;
  height: 100vh;
}
.header {
  height: 50px;
}
.footer {
  height: 50px;
}
.main {
  text-align: left;
  flex: 1;
}

@media (min-width: 600px) {
  .aside {
    flex: 1;
  }
}
@media (min-width: 800px) {
  .wrapper {
    flex-direction: row;
    flex-wrap: wrap;
  }
  .header {
    flex-basis: 100%;
    order: -1;
  }
  .main {
    flex: 2;
  }
  .aside-1 {
    order: -1;
    height: calc(100% - 100px);
  }
  .footer {
    flex-basis: 100%;
  }
}



/*  for styling  */
.wrapper {
  font-weight: bold;
  text-align: center;
}
.wrapper > * {
  padding: 10px;
  box-sizing: border-box;
}
.header {
  background: tomato;
}
.footer {
  background: lightgreen;
}
.main {
  background: deepskyblue;
}
.aside-1 {
  background: gold;
}
<div class="wrapper">
  <header class="header">Header</header>
  <article class="main">
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
      Mauris placerat eleifend leo.</p>
  </article>
  <aside class="aside aside-1">Aside 1</aside>

  <footer class="footer">Footer</footer>
</div>

如果您能够更改标记,这是我的一个版本,代码库比其他人提供的要简单得多,而且页眉和页脚没有固定高度。

html, body {
  margin: 0;
}
.wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.innerwrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
}
.main {
  flex: 1;
  text-align: left;
}

@media (min-width: 600px) {
  .aside {
    flex: 1;
  }
}
@media (min-width: 800px) {
  .innerwrapper {
    flex-direction: row;
  }
  .aside-1 {
    order: -1;
  }
}



/*  for styling  */
.wrapper {
  font-weight: bold;
  text-align: center;
}
.wrapper > *:not(.innerwrapper),
.wrapper .innerwrapper > * {
  padding: 10px;
  box-sizing: border-box;
}
.header {
  background: tomato;
}
.footer {
  background: lightgreen;
}
.main {
  background: deepskyblue;
}
.aside-1 {
  background: gold;
}
<div class="wrapper">
  <header class="header">Header</header>
  
  <div class="innerwrapper">
    <article class="main">
      <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
      Mauris placerat eleifend leo.</p>
    </article>
  
    <aside class="aside aside-1">Aside 1</aside>
  </div>

  <footer class="footer">Footer</footer>
</div>

【讨论】:

  • 根据我的理解,它使用的东西与 kukkuz 的答案非常相似——使用 calc() css3 函数。
  • @Jhecht 是的,它确实如此,尽管与弹性盒列布局正确结合。请问为什么不更改标记?
  • 主要是虚荣,然后是好奇心,以及不必重写任何 jQuery 的温和尝试。
  • @Jhecht 虚荣心很好,让你保持警觉:) ...但是长时间站立可能会受伤。添加了一个 2:nd 示例,无论您是否选择我的答案,我都建议您选择它。
猜你喜欢
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-30
相关资源
最近更新 更多