【问题标题】:Page-filling flexbox layout with top and side bars not quite working带有顶部和侧边栏的页面填充 flexbox 布局不太有效
【发布时间】:2016-01-24 09:06:41
【问题描述】:

我想要实现的布局是这样的,正好填满了浏览器的整个视口:

[----fixed height top "menu bar"----]
/-----\/----------------------------\
|fixed||                            |
|width|| both ways stretchy content |
|side ||                            |
|bar  ||                            |
\-----/\----------------------------/

我几乎可以使用它,但我还没有弄清楚如何指定水平排列的框垂直填充它们可用的空间而不是页面的高度。就目前而言,只要侧边栏中的内容足够长以使其获得滚动条,我最终会在整个页面上添加一个额外的垂直滚动条,该滚动条正好滚动到顶部栏的高度,这不是什么我要。

以下 1998 年风格的演示页面说明了这个问题。它实际上在 Safari 9 中生成了我想要的布局,但不是 Chrome 或 Firefox。

注意这些附加约束,这些约束已经被演示满足并且必须保留:

  • 水平方向上可能有任意数量的固定宽度或可拉伸的盒子。

  • 每个侧边栏或主要内容都有一个overflow-y: auto 垂直滚动条。这也必须有效(也就是说,长内容不能使整个 flexbox 布局超过视口大小)。一些侧边栏本身在垂直方向使用 flexbox 布局。

  • 90%-10% 的布局不适合此目的。也不允许剪辑某些内容。我有这个布局问题的全部原因是应用程序应该使用屏幕的每个像素来显示有用的信息或控件,所以任何额外的空白或剪辑的内容都是不可取的。

    李>

<!doctype html>
<html style="height: 100%;">
<title>Flexbox test</title>
<style type="text/css">
#parent-of-topbar {
  height: 100%;  box-sizing: border-box; margin: 0;
  background: #FCC;

  display: flex; flex-direction: column;
}
#topbar {
  padding: .2em;
  background: white;
  border: solid black;
  border-width: 0 0 .3em 0;
  color: black;
  flex: 0 0 auto;
}
#main {
  display: flex; flex-direction: row;
  
  flex: 1 1 auto;
  max-height: 100%; 
}
.subwindow {
  overflow-x: clip;
  overflow-y: auto;
  max-height: 100%;

  border: 3px outset #CCC;
  background: linear-gradient(to right, #CCC 0%,#AAA 100%);
}
.fixed {
  flex: 0 0 auto;
  width: 10em;
}
.stretchy {
  flex: 1 1 auto;
  width: 100%;
}
</style>

<body id="parent-of-topbar">
  <div id="topbar">top bar content</div>
  <div id="main">
    <div class="subwindow stretchy">stretchy part</div>
    <div class="subwindow fixed">
      fixed sidebar 1; this should be scrollable, not stretch the content
      <details open><div style="font-size: 3em;">spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam</div></details>
    </div>
    <div class="subwindow fixed">
      2nd fixed sidebar
    </div>
  </div>
</body>

这是我想要实现的布局的屏幕截图,通过硬编码维度伪造:

这是当前演示在 Chrome 上的布局截图:

【问题讨论】:

  • 你的问题有点不清楚。第一段似乎提出了三个不同的问题。
  • @Michael_B 已编辑 — 我已经分离出“这是我已经拥有的,不能被提议的解决方案破坏”部分。怎么样?
  • 好的,谢谢。但是只有 Safari 9 可以正确呈现上面的代码,对吗?在我的 PC 上使用 Chrome 或 FF 不起作用?
  • 嗯,“正确”的意思是它得到了我想要的结果。我不知道哪个在正确实施规范。
  • 您可以选择将#main.subwindow 上的max-height: 100% 更改为height: calc(100% - 18px)。 18px 是固定顶栏的计算高度。

标签: css flexbox


【解决方案1】:

更新

在 cmets 中来回折腾后,我们想出了解决方案。这是一个简单的修复方法,但发现起来并不容易。

答案归结为:

  • 在原始代码中,水平框被包裹在具有flex: 1 1 auto的容器中。

  • 要使布局正常工作,容器需要有flex: 1 1 0(或简称flex: 1)。

  • 原始代码导致视口窗口出现垂直滚动条,因为flex: 1 1 auto 根据内容大小或高度属性调整项目大小。

  • 调整后的代码使布局能够整齐地适应视口,因为flex: 1 1 0 根据 flex 容器中的可用空间调整项目大小。

DEMO

flexbox 规范在7.1.1. Common Values of flex 部分中有更详细的说明。


我几乎可以使用它,但我还没有弄清楚如何指定水平排列的框垂直填充它们可用的空间而不是页面的高度。就目前而言,只要侧边栏中的内容足够长以使其获得滚动条,我最终会在整个页面上添加一个额外的垂直滚动条,该滚动条正好滚动到顶部栏的高度,这不是什么我要。

每个侧边栏或主要内容都有一个overflow-y: auto 垂直滚动条[必须保留]。

您有两个弹性项目:#topbar#main

#topbar 的高度基于内容,paddingborder(没有指定高度)。

#main 的高度是 max-height: 100%(在 Chrome 和 FF 上,计算为 height: 100%)。

当您将这两个高度相加时,总和超过了应用于其容器的height: 100% (#parent-of-topbar)。这就是 body 上垂直滚动条的原因。

解决方案 #1

解决此问题的最简单方法是使用overflow: hidden,同时保留内容框上的垂直滚动条。

将此添加到 CSS 中:

body { height: 100%; overflow: hidden; }

演示:http://jsfiddle.net/mwfkLu8b/

这是一个钝力对象方法。它可以快速、轻松、有效地完成工作,但会占用屏幕的下部。换句话说,overflow: hidden 剪切了垂直滚动条所在的区域。

解决方案 #2

解决问题的另一种方法是在 flex 项之间分配 100% 的高度,它也保留内容框上的垂直滚动条,但不剪切任何内容。

试试这个:

* { box-sizing: border-box; } /* new */

body { height: 100%; } /* new */

#topbar {
    padding: .2em;
    background: white;
    border: solid black;
    border-width: 0 0 .3em 0;
    color: black;
    flex: 0 0 auto;
    height: 10%; /* new */
}

#main {
    display: flex;
    flex-direction: row;
    flex: 1 1 auto;
    /* max-height: 100%; */
    height: 90%; /* new */ 
}

演示:http://jsfiddle.net/mwfkLu8b/1/

如果#topbar需要固定高度,那么可以用像素和calc等于100%。

#topbar { height: 40px; }
#main { height: calc(100% - 40px); }

演示:http://jsfiddle.net/mwfkLu8b/2/

【讨论】:

  • 分布垂直高度是我想要的,但它应该以 flex 增长/收缩的方式分布,而不是使用一组加起来为 100 的高度%。但是如果我找不到更好的方法,我肯定会使用calc 的方法。
  • (您的解决方案 #1 不适合该应用程序 - 它可能会切断 .subwindows 中的数据或其他“侧边栏”内容。这需要准确布局。)
  • 您当然可以从弹性项目中完全删除height 属性,并改用flex-basisjsfiddle.net/mwfkLu8b/3
  • 啊哈!使其工作的关键部分是为可伸缩内容指定 zero(不是 auto)的 flex-basis,这是由 flex: 1; 隐式完成的。为了得到这个,我不得不深入研究你的答案所做的事情。
  • Kevin 我可能需要一两天时间来修改这个答案,但我会解决的。很高兴您解决了问题。
【解决方案2】:

感谢Michael_B's answer and comments,我找到了适用于演示以及我的实际应用程序的解决方案。

关键规则是:不要在 flexbox 内的任何地方使用 height: 100%;width: 100%;。使用 flex-grow 使内容扩展以适应其容器,即使这意味着将 .subwindow 元素的内容转换为以前没有的 flexbox 布局。

此外,不要在有弹性的东西上设置flex-basis: auto(直接或通过flex 快捷方式)。而是使用flex-basis: 0%(或任何零长度),这是由flex: &lt;number&gt;; 隐式完成的,并让生长负责填充容器。如果您绝对遵循第一条规则,我仍然不确定这是否有必要,但它似乎在不完美的情况下有所帮助。

修改后的演示(现在显示了一个 100% 类似于我的实际应用程序的主面板,这是另一个复杂因素):

<!doctype html>
<html style="height: 100%;">
<title>Flexbox test</title>
<style type="text/css">
#parent-of-topbar {
  height: 100%;  box-sizing: border-box; margin: 0;
  background: #FCC;

  display: flex; flex-direction: column;
}
#topbar {
  padding: .2em;
  background: white;
  border: solid black;
  border-width: 0 0 .3em 0;
  color: black;
}
#main {
  display: flex; flex-direction: row;
  
  flex: 1;
}
.subwindow {
  overflow-x: clip;
  overflow-y: auto;

  border: 3px outset #CCC;
  background: linear-gradient(to right, #CCC 0%,#AAA 100%);
  
  display: flex;
  flex-direction: column;
}
.fixed {
  flex: 0 auto;
  width: 10em;
}
.stretchy {
  flex: 1;
}
</style>

<body id="parent-of-topbar">
  <div id="topbar">top bar content</div>
  <div id="main">
    <div class="subwindow stretchy">
      <div style="background: #CFC; flex: 1; vertical-align: middle; text-align: center;">stretchy content</div>
    </div>
    <div class="subwindow fixed">
      fixed sidebar 1; this should be scrollable, not stretch the content
      <details open><div style="font-size: 3em;">spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam</div></details>
    </div>
    <div class="subwindow fixed">
      2nd fixed sidebar
    </div>
  </div>
</body>

【讨论】:

    【解决方案3】:

    不完全清楚您到底想要什么,所以请告诉我,以便我能适应。您提到了视口中的内容。所以我使用了vh and vw

    html {
      box-sizing: border-box;
      font: 400 16px/1.5 small-caps"Trebuchet MS";
    }
    *,
    *:before,
    *:after {
      box-sizing: inherit;
      margin: 0;
      padding: 0;
      border: 0 solid transparent;
      outline: 0;
      text-indent: 0;
    }
    body {
      background: #FCC;
      color: #000;
      position: relative;
      display: flex;
      flex-direction: column;
      height: 95vh;
      width: 100vw;
    }
    #topbar {
      padding: .2em;
      background: white;
      border: solid black;
      border-width: 0 0 2px 0;
      color: black;
      line-height: 1.4;
      max-height: 32px;
      flex: 2 0 32px;
    }
    #main {
      display: flex;
      flex-direction: row;
      flex: 1 0 auto;
      max-height: 100%;
    }
    .subwindow {
      overflow-x: clip;
      overflow-y: auto;
      max-height: 110%;
      outline: 3px outset #CCC;
      background: linear-gradient(to right, #CCC 0%, #AAA 100%);
    }
    .fixed {
      width: 10em;
    }
    .stretch {
      flex: 1 0 10em;
      width: 100%;
    }
    details > div {
      font-size: 3em;
    }
    <!doctype html>
    <html>
    
    <head>
      <meta charset="utf-8">
      <title>Flexbox test</title>
    
    </head>
    
    <body>
      <header id="topbar">Header</header>
      <main id="main">
        <section class="subwindow stretch">
          <h3>Section 1</h3>
          <h4>Expanding Section</h4>
        </section>
        <section class="subwindow fixed">
          <h3>Section 2</h3> 
          <h4>Scrolling Section</h4>
          <details open>
            <div>spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam</div>
          </details>
        </section>
        <section class="subwindow fixed">
          <h3>Section 3</h3>
          <h4>Static Section</h4>
        </section>
      </main>
    </body>

    【讨论】:

    • 当我在 Chrome 中查看此内容时,只要侧边栏内容高于视口,我就会在两个方向上看到页面滚动条。两者都不应该;唯一出现的滚动条应该在“sidebar 1”元素内。
    • 更新了标题 4vh 和 html 95vh
    • 顶栏需要固定 (em) 高度,而不是视口的百分比。将其视为一排按钮/链接/状态显示,而不是页面标题——它应该与阅读/点击所需的大小一样大,而不是更大。
    • #topbar 最初 AFAIK 没有任何高度。为了语义,我将其更改为&lt;header&gt;,它只是一个花哨的&lt;div&gt;。计算的样式最初是 19 像素,而我的字体设置为 32 像素 (line-height: 2)。那么您通常会将顶部栏设置在什么位置? 2em 还是 3em?
    • 是的,与单行文本内容一样高的默认行为是我们想要的。如果它是包裹它会更高。
    猜你喜欢
    • 2013-04-17
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 2014-08-19
    • 2016-06-07
    • 1970-01-01
    相关资源
    最近更新 更多