带有顶部和侧边栏的页面填充 flexbox 布局不太有效
Page-filling flexbox layout with top and side bars not quite working
我试图实现的布局是这样的,正好填满浏览器的整个视口:
[----fixed height top "menu bar"----]
/-----\/----------------------------\
|fixed|| |
|width|| both ways stretchy content |
|side || |
|bar || |
\-----/\----------------------------/
我几乎可以正常工作了,但我还没有弄清楚如何指定水平排列的框垂直填充 它们可用的 space,而不是 页面的高度。按照目前的情况,只要侧边栏中的内容足够长以使其获得滚动条,我最终会在整个页面上增加一个垂直滚动条,该滚动条正好滚动顶部栏的高度,这不是什么我要。
以下 1998 年风格的演示页面说明了这个问题。它实际上生成了我在 Safari 9 中想要的布局,但不是 Chrome 或 Firefox。
注意这些额外的约束,演示已经满足这些约束并且必须保留:
可以在水平方向排列任意数量的固定宽度或弹性框。
每个侧栏或主要内容都有一个 overflow-y: auto
垂直滚动条。这也必须有效(即,长内容不得使整体 flexbox 布局超过视口大小)。一些侧边栏本身在垂直方向上使用了 flexbox 布局。
90%-10%的布局不适合该目的。也不允许剪辑某些内容。我遇到此布局问题的全部原因是应用程序应该 使用屏幕的每个像素来显示有用的信息或控件, 因此任何额外的白色 space 或剪裁的内容都是不受欢迎。
<!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 上获得的布局的屏幕截图:
不太清楚您到底想要什么,请告诉我,以便我能安排。您提到了视口中的内容。所以我用了 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>
更新
在评论中反复讨论后,我们得出了解决方案。这是一个简单的修复,但并不容易发现。
答案归结为:
在原始代码中,水平框被包裹在具有flex: 1 1 auto
.
的容器中
要使布局正常工作,容器需要 flex: 1 1 0
(或简称 flex: 1
)。
原始代码导致视口上出现垂直滚动条 window 因为 flex: 1 1 auto
根据内容大小或高度属性调整项目大小。
调整后的代码导致布局完全适合视口,因为 flex: 1 1 0
根据 flex 容器中的自由 space 调整项目的大小。
Flexbox 规范在 7.1.1. Common Values of flex.
部分有更详细的介绍
I have it nearly working, but I haven't figured out how to specify that the horizontally-arranged boxes vertically fill the space available to them rather than the height of the page. As it currently stands, whenever the content in the sidebar is long enough to cause it to gain a scroll bar, I end up with an additional vertical scrollbar on the entire page which scrolls by exactly the height of the top bar, which is not what I want.
Each side bar or main content has an overflow-y: auto
vertical scrollbar [which must be preserved].
您有两个弹性项目:#topbar
和 #main
。
#topbar
的高度根据内容,padding
和border
(没有指定高度)。
#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/
这是钝器object的方法。它可以快速、轻松和有效地完成工作,但它会占用屏幕的较低部分。换句话说,overflow: hidden
剪切垂直滚动条所在的区域。
解决方案 #2
解决此问题的另一种方法是在弹性项目之间分配 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); }
感谢 ,我找到了适用于演示和实际应用的解决方案。
关键规则是:不要在 flexbox 内的任何地方使用 height: 100%;
或 width: 100%;
。使用 flex-grow
使内容扩展以适合其容器,即使这意味着将 .subwindow
元素的内容转换为之前不存在的 flexbox 布局。
此外,不要在有弹性的东西上设置 flex-basis: auto
(直接或通过 flex
快捷方式)。而是使用 flex-basis: 0%
(或任何零长度),这是由 flex: <number>;
隐式完成的,并让增长负责填充容器。如果您绝对遵循第一条规则,我仍然不确定这是否有必要,但它似乎在不完美的情况下有所帮助。
修改后的演示(现在显示 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>
我试图实现的布局是这样的,正好填满浏览器的整个视口:
[----fixed height top "menu bar"----]
/-----\/----------------------------\
|fixed|| |
|width|| both ways stretchy content |
|side || |
|bar || |
\-----/\----------------------------/
我几乎可以正常工作了,但我还没有弄清楚如何指定水平排列的框垂直填充 它们可用的 space,而不是 页面的高度。按照目前的情况,只要侧边栏中的内容足够长以使其获得滚动条,我最终会在整个页面上增加一个垂直滚动条,该滚动条正好滚动顶部栏的高度,这不是什么我要。
以下 1998 年风格的演示页面说明了这个问题。它实际上生成了我在 Safari 9 中想要的布局,但不是 Chrome 或 Firefox。
注意这些额外的约束,演示已经满足这些约束并且必须保留:
可以在水平方向排列任意数量的固定宽度或弹性框。
每个侧栏或主要内容都有一个
overflow-y: auto
垂直滚动条。这也必须有效(即,长内容不得使整体 flexbox 布局超过视口大小)。一些侧边栏本身在垂直方向上使用了 flexbox 布局。90%-10%的布局不适合该目的。也不允许剪辑某些内容。我遇到此布局问题的全部原因是应用程序应该 使用屏幕的每个像素来显示有用的信息或控件, 因此任何额外的白色 space 或剪裁的内容都是不受欢迎。
<!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 上获得的布局的屏幕截图:
不太清楚您到底想要什么,请告诉我,以便我能安排。您提到了视口中的内容。所以我用了 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>
更新
在评论中反复讨论后,我们得出了解决方案。这是一个简单的修复,但并不容易发现。
答案归结为:
在原始代码中,水平框被包裹在具有
flex: 1 1 auto
. 的容器中
要使布局正常工作,容器需要
flex: 1 1 0
(或简称flex: 1
)。原始代码导致视口上出现垂直滚动条 window 因为
flex: 1 1 auto
根据内容大小或高度属性调整项目大小。调整后的代码导致布局完全适合视口,因为
flex: 1 1 0
根据 flex 容器中的自由 space 调整项目的大小。
Flexbox 规范在 7.1.1. Common Values of flex.
部分有更详细的介绍I have it nearly working, but I haven't figured out how to specify that the horizontally-arranged boxes vertically fill the space available to them rather than the height of the page. As it currently stands, whenever the content in the sidebar is long enough to cause it to gain a scroll bar, I end up with an additional vertical scrollbar on the entire page which scrolls by exactly the height of the top bar, which is not what I want.
Each side bar or main content has an
overflow-y: auto
vertical scrollbar [which must be preserved].
您有两个弹性项目:#topbar
和 #main
。
#topbar
的高度根据内容,padding
和border
(没有指定高度)。
#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/
这是钝器object的方法。它可以快速、轻松和有效地完成工作,但它会占用屏幕的较低部分。换句话说,overflow: hidden
剪切垂直滚动条所在的区域。
解决方案 #2
解决此问题的另一种方法是在弹性项目之间分配 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); }
感谢
关键规则是:不要在 flexbox 内的任何地方使用 height: 100%;
或 width: 100%;
。使用 flex-grow
使内容扩展以适合其容器,即使这意味着将 .subwindow
元素的内容转换为之前不存在的 flexbox 布局。
此外,不要在有弹性的东西上设置 flex-basis: auto
(直接或通过 flex
快捷方式)。而是使用 flex-basis: 0%
(或任何零长度),这是由 flex: <number>;
隐式完成的,并让增长负责填充容器。如果您绝对遵循第一条规则,我仍然不确定这是否有必要,但它似乎在不完美的情况下有所帮助。
修改后的演示(现在显示 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>