【问题标题】:Vertically centered nested flex box垂直居中的嵌套弹性盒
【发布时间】:2016-08-16 18:02:35
【问题描述】:

我正在尝试实现具有三个垂直部分的简单布局:

  1. 页面顶部的小标题。
  2. 主要内容,必要时展开以使页脚保持在页面底部。
  3. 页面底部的页脚。

主要内容部分应进一步分为两部分:一个带有输入框和一个按钮的非常小的表单,以及一个显示一些表格数据的最大 5 行表格。表格应根据需要占用尽可能多的垂直空间,小表格应位于剩余垂直空间的中心。

我尝试过使用弹性盒子,但有些地方我做错了;我无法将微小的形式垂直居中在可用空间中。这是我迄今为止所做的简化版本(最好全屏查看):

body {
  margin:0;
  min-height:100vh;
  display:flex;
  flex-direction:column;
  align-items:center;
}

main {
  flex:1;
  display:flex;
  flex-direction:column;
}

main>form {
  flex:1;
}
<body>
  <header>header</header>
  <main>
    <form>
      <h1>Form with inputs</h1>
      <label>Inputs</label>
      <input type="text">
      <button>Button</button>
    </form>
    <div>
      <h1>Other content</h1>
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
      </ul>
    </div>
  </main>
  <footer>footer</footer>
</body>

我尝试了justify-contentalign-contentalign-itemsalign-self 的多种组合,但我尝试的越多,我似乎就越不明白自己在做什么:-(

任何这样做的人都可以向我提供任何关于我做错了什么的提示吗?

编辑:如果我可以为某些元素使用固定高度,我可能会做这样的事情(这也说明了我所追求的,最好全屏查看):

* {
  box-sizing:border-box;
}
      
html {
  height:100%;
}
  
body {
  margin:0;
  height:100%;
  position:relative;
}

header {
  height:40px;
  background-color:#E6ECC1;
}

main {
  height:calc(100% - 80px);
  background-color:#dfd;
}

h1 {
  margin:0;
  padding:10px 0;
}

main>form {
  height:calc(100% - 150px);
  background-color:#C1E4EC;
}

main>form:before {
  content:"";
  display:inline-block;
  height:100%;
  vertical-align:middle;
}

main>form>div {
  display: inline-block;
  vertical-align: middle;
  width: calc(100% - 4px);
  text-align: center;
}

main>div {
  padding:0 20px;
  height:150px;
  position:absolute;
  bottom:40px;
}

footer {
  position:absolute;
  height:40px;
  width:100%;
  bottom:0;
  background-color:#fdd;
}
<body>
  <header>header</header>
  <main>
    <form>
      <div>
        <h1>Form with inputs</h1>
        <label>Inputs</label>
        <input type="text">
        <button>Button</button>
      </div>
    </form>
    <div>
      <h1>Other content</h1>
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
      </ul>
    </div>
  </main>
  <footer>footer</footer>
</body>

我认为我可以使用两个嵌套的弹性盒子更干净地实现这一点;一个为顶部的页眉、底部的页脚和一个可以增长以填充其间所有可用空间的中间部分提供空间的外部部分,以及一个将外部中间部分分成两部分的内部部分;底部的一个具有恒定但未知的高度,顶部的一个占据了中间部分的所有剩余空间。这个块的内容,比在大屏幕上查看页面时的可用区域要小得多,应该在可用区域中水平和垂直居中。

当我只使用外部弹性框(我原来的 sn-p 中的 &lt;body&gt; 元素)时,内容在页眉和页脚之间垂直居中。但是当我尝试拆分中间部分(我原来的 sn-p 中的 &lt;main&gt; 元素)时,表单被向上推。就好像外框 flex:1 元素的高度对其子元素不可用。

非常感谢,祝你有美好的一天。

【问题讨论】:

    标签: css flexbox


    【解决方案1】:

    您的居中(对齐/对齐内容)不是继承的,因此您必须为每个 flex-container 重新声明它。

    body {
      margin: 0;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    header {
      background: green
    }
    main {
      flex: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background: pink;
    }
    main>form {
      background: orange;
    }
    <body>
      <header>header</header>
      <main>
        <form>
          <h1>Form with inputs</h1>
          <label>Inputs</label>
          <input type="text">
          <button>Button</button>
        </form>
        <div>
          <h1>Other content</h1>
          <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
          </ul>
        </div>
      </main>
      <footer>footer</footer>
    </body>

    【讨论】:

    • 谢谢@Paulie_D,虽然这不是我所追求的。我正在尝试让橙色部分扩大占用所有可用的粉红色空间(将“其他内容”向下推),同时将“带输入的表单”组保持在橙色区域的中心。有什么想法吗?
    【解决方案2】:

    我感谢所有回答的人,尽管答案并没有完全符合我的要求。最后,我通过将表单包装在一个额外的 div 中来管理我所追求的,我应用了 flex 属性:

    body {
      margin: 0;
      background-color: #F3F3F3;
      display: flex;
      flex-direction: column;
      height: 100vh;
    }
    
    header {
      background-color: #fdd;
    }
    
    main {
      flex: 1;
      display: flex;
      flex-direction: column;
    }
    
    div.form {
      background-color: #dfd;
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      padding-bottom: 20px;
    }
    
    div.other {
      background-color: #fdb;
      padding: 0 10vw;
    }
    
    footer {
      background-color: #ddf;
    }
    <body>
      <header>header</header>
      <main>
        <div class="form">
          <form>
            <h1>Form with inputs</h1>
            <label>Inputs</label>
            <input type="text">
            <button>Button</button>
          </form>
        </div>
        <div class="other">
          <h1>Other content</h1>
          <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
          </ul>
        </div>
      </main>
      <footer>footer</footer>
    </body>

    我希望这可以帮助将来遇到类似问题的其他人!

    【讨论】:

    • 嗯...我刚刚向下滚动了 sn-p :-(
    【解决方案3】:
    1. 去掉align-items: center;,因为它将块元素变成内联块,改用text-align: center

    1. htmlbody 都需要定义 height100%

    2. 如果您希望main 中的form 占用大部分空间,则只需将flex: 1 应用于它。

    工作简化演示:

    html, body {margin: 0; padding: 0; height: 100%; text-align: center;}
    
    body { width: 100%; display:flex; flex-direction:column; }
    
    header { padding: 1em; background: lightblue; }
    
    footer { padding: 1em; background: gray; }
    
    main { flex:1; display:flex; flex-direction:column; background: lightyellow; overflow: auto;}
    
    main > form { border-bottom:1px dashed gold; flex:1; }
    
    #data { padding: 1em; }
    
    main ul  { margin: 0; padding: 0; display: inline-block }
    <header>header</header>
    <main>
      <form>
        <h1>Form with inputs</h1>
        <label>Inputs</label>
        <input type="text">
        <button>Button</button>
      </form>
      <div id="data">
        <h1>Other content</h1>
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
        </ul>
      </div>
    </main>
    <footer>footer</footer>

    jsFiddle:https://jsfiddle.net/azizn/hLse4wa7/

    【讨论】:

    • 感谢您的回答,Aziz,尽管我不确定我是否理解您的建议。 1) 我认为一旦容器被声明为 display:flex,孩子们的内联性和/或阻塞性就无关紧要了。 2)我明确使用基于视口的高度(100vh)。这不是从任何祖先继承的,因此不需要在任何祖先中声明。或者是吗? 3)但我希望表格占据大部分空间,而不是表格;这就是为什么我将它应用于表单。尽管如此,还是感谢您花时间帮助我。祝你有美好的一天!
    • @CarvoLoco 你好。 (1) 显然,如果您设置align-items: center,盒子模型的宽度将减小为内容(而不是块),是的,如果您尝试设置任何display 值,它将不起作用。这与 flex 模型的工作方式有关,我不确定为什么,但您可以自己尝试(我还在我的答案中附上了它的外观图片)。 (2) 你说得对。 100vh 就足够了,但是您可能需要检查浏览器兼容性。 (3) 那是一个误解,更新了我的答案。也祝你有美好的一天!