带有嵌套 flexbox 和滚动的整页
Full page with nested flexbox and scrolling
我正在尝试使用 flexbox 进行我认为是相当标准的全屏布局,但它的行为方式并不符合我的要求。我的目标是:
- 自动调整 topbar/footer 高度和侧边栏宽度(根据内容调整大小,不固定大小)
- Topbar/footer 占满宽度且永不滚动
- 侧边栏占满高度,但如果内容较大,则只能垂直滚动
- 内容占用剩余部分 width/height,但如果内容较大,可以双向滚动
- Sidebar/Content 相互独立滚动(不需要时隐藏滚动条)
- 主要内容区域通常显示为带滚动条的常规文档,但有时我希望它也有一些嵌套的侧边栏和剩余高度滚动子面板。
* {
box-sizing: border-box;
}
html, body {
margin: 0;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
background-color: lightgreen;
}
.vcontainer {
flex-grow: 1;
display: flex;
flex-direction: row;
min-height: 0;
}
.sidebar {
overflow-y: auto;
background-color: yellow;
}
.content {
flex-grow: 1;
overflow: auto;
background-color: lightblue;
}
.footer {
background-color: pink;
}
<div class="page">
<nav class="topbar">
top bar
</nav>
<div class="vcontainer">
<nav class="sidebar">
side<br/>side<br/>side
</nav>
<main class="content">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</main>
</div>
<footer class="footer">
footer
</footer>
</div>
上面的内容对于完整的文档滚动变体很好用(尽管神奇的是将 min-height
添加到 vcontainer
;在此之前它不起作用)——蓝色区域占据剩余 space,如果内容太长则可滚动。
在不改变外部样式的情况下(或者至少不以破坏上述场景的方式改变它),我希望能够 有时 放入一些 content
本质上有一个额外的动态高度顶栏和一个不会触发主要内容滚动条的滚动子部分。
* {
box-sizing: border-box;
}
html, body {
margin: 0;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
background-color: lightgreen;
}
.vcontainer {
flex-grow: 1;
display: flex;
flex-direction: row;
min-height: 0;
}
.sidebar {
overflow-y: auto;
background-color: yellow;
}
.content {
flex-grow: 1;
overflow: auto;
background-color: lightblue;
}
.footer {
background-color: pink;
}
.contentcontainer {
display: flex;
flex-direction: column;
min-height: 0;
}
.contentsub {
margin: 1rem;
overflow-y: scroll;
flex-grow: 1;
background-color: orange;
}
<div class="page">
<nav class="topbar">
top bar
</nav>
<div class="vcontainer">
<nav class="sidebar">
side<br/>side<br/>side
</nav>
<main class="content">
<div class="contentcontainer">
<div>
some additional heading content
</div>
<div class="contentsub">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</div>
<div>
some additional footer content
</div>
</div>
</main>
</div>
<footer class="footer">
footer
</footer>
</div>
在这种情况下,我想要的是蓝色区域没有滚动条,而是橙色区域可以滚动,被额外的 header/footer 包围并且大小可以填充剩余的 space。理想情况下,即使 contentsub
不是 contentcontainer
的直接子元素,但在到达可滚动元素之前有更多的环绕元素和边框等,这也应该有效。我更喜欢“纯 flexbox”的解决方案,但如果有更好的方法,那么我会洗耳恭听。但是,我确实想避免使用 javascript。
经过一些调整后我得到了这个:
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
background-color: lightgreen;
}
.vcontainer {
flex-grow: 1;
display: flex;
flex-direction: row;
min-height: 0;
}
.sidebar {
overflow-y: auto;
background-color: yellow;
}
.content {
flex-grow: 1;
overflow: auto;
background-color: lightblue;
}
.footer {
background-color: pink;
}
.contentcontainer {
height: 100%;
}
.contentsub {
max-height: max(40%, 2rem);
margin: 1rem;
overflow-y: scroll;
background-color: orange;
}
<div class="page">
<nav class="topbar">
top bar
</nav>
<div class="vcontainer">
<nav class="sidebar">
side<br/>side<br/>side
</nav>
<main class="content">
<div class="contentcontainer">
<div>
some additional heading content
</div>
<div class="contentsub">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</div>
<div>
some additional footer content
</div>
</div>
</main>
</div>
<footer class="footer">
footer
</footer>
</div>
网格方法:
* {
box-sizing: border-box;
}
html,
body,
.page {
height: 100%;
margin: 0;
}
.topbar {
grid-area: header;
background-color: lightgreen;
}
.sidebar {
grid-area: sidebar;
overflow-y: auto;
background-color: yellow;
}
.content {
grid-area: content;
display: flex;
flex-flow: column nowrap;
overflow: auto;
background-color: lightblue;
}
.footer {
grid-area: footer;
background-color: pink;
}
.contentsub {
flex-grow: 1;
margin: 1rem;
overflow-y: scroll;
background-color: orange;
}
@media (min-width: 30rem) {
.page {
display: grid;
grid-template-areas: "header header" "sidebar content" "footer footer";
grid-template-columns: 1fr 9fr;
}
}
<div class="page">
<header class="topbar">
top bar
</header>
<aside class="sidebar">
side<br/>side<br/>side
</aside>
<main class="content">
<div>
some additional heading content
</div>
<div class="contentsub">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</div>
<div>
some additional footer content
</div>
</main>
<footer class="footer">
footer
</footer>
</div>
我正在尝试使用 flexbox 进行我认为是相当标准的全屏布局,但它的行为方式并不符合我的要求。我的目标是:
- 自动调整 topbar/footer 高度和侧边栏宽度(根据内容调整大小,不固定大小)
- Topbar/footer 占满宽度且永不滚动
- 侧边栏占满高度,但如果内容较大,则只能垂直滚动
- 内容占用剩余部分 width/height,但如果内容较大,可以双向滚动
- Sidebar/Content 相互独立滚动(不需要时隐藏滚动条)
- 主要内容区域通常显示为带滚动条的常规文档,但有时我希望它也有一些嵌套的侧边栏和剩余高度滚动子面板。
* {
box-sizing: border-box;
}
html, body {
margin: 0;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
background-color: lightgreen;
}
.vcontainer {
flex-grow: 1;
display: flex;
flex-direction: row;
min-height: 0;
}
.sidebar {
overflow-y: auto;
background-color: yellow;
}
.content {
flex-grow: 1;
overflow: auto;
background-color: lightblue;
}
.footer {
background-color: pink;
}
<div class="page">
<nav class="topbar">
top bar
</nav>
<div class="vcontainer">
<nav class="sidebar">
side<br/>side<br/>side
</nav>
<main class="content">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</main>
</div>
<footer class="footer">
footer
</footer>
</div>
上面的内容对于完整的文档滚动变体很好用(尽管神奇的是将 min-height
添加到 vcontainer
;在此之前它不起作用)——蓝色区域占据剩余 space,如果内容太长则可滚动。
在不改变外部样式的情况下(或者至少不以破坏上述场景的方式改变它),我希望能够 有时 放入一些 content
本质上有一个额外的动态高度顶栏和一个不会触发主要内容滚动条的滚动子部分。
* {
box-sizing: border-box;
}
html, body {
margin: 0;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
background-color: lightgreen;
}
.vcontainer {
flex-grow: 1;
display: flex;
flex-direction: row;
min-height: 0;
}
.sidebar {
overflow-y: auto;
background-color: yellow;
}
.content {
flex-grow: 1;
overflow: auto;
background-color: lightblue;
}
.footer {
background-color: pink;
}
.contentcontainer {
display: flex;
flex-direction: column;
min-height: 0;
}
.contentsub {
margin: 1rem;
overflow-y: scroll;
flex-grow: 1;
background-color: orange;
}
<div class="page">
<nav class="topbar">
top bar
</nav>
<div class="vcontainer">
<nav class="sidebar">
side<br/>side<br/>side
</nav>
<main class="content">
<div class="contentcontainer">
<div>
some additional heading content
</div>
<div class="contentsub">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</div>
<div>
some additional footer content
</div>
</div>
</main>
</div>
<footer class="footer">
footer
</footer>
</div>
在这种情况下,我想要的是蓝色区域没有滚动条,而是橙色区域可以滚动,被额外的 header/footer 包围并且大小可以填充剩余的 space。理想情况下,即使 contentsub
不是 contentcontainer
的直接子元素,但在到达可滚动元素之前有更多的环绕元素和边框等,这也应该有效。我更喜欢“纯 flexbox”的解决方案,但如果有更好的方法,那么我会洗耳恭听。但是,我确实想避免使用 javascript。
经过一些调整后我得到了这个:
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
background-color: lightgreen;
}
.vcontainer {
flex-grow: 1;
display: flex;
flex-direction: row;
min-height: 0;
}
.sidebar {
overflow-y: auto;
background-color: yellow;
}
.content {
flex-grow: 1;
overflow: auto;
background-color: lightblue;
}
.footer {
background-color: pink;
}
.contentcontainer {
height: 100%;
}
.contentsub {
max-height: max(40%, 2rem);
margin: 1rem;
overflow-y: scroll;
background-color: orange;
}
<div class="page">
<nav class="topbar">
top bar
</nav>
<div class="vcontainer">
<nav class="sidebar">
side<br/>side<br/>side
</nav>
<main class="content">
<div class="contentcontainer">
<div>
some additional heading content
</div>
<div class="contentsub">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</div>
<div>
some additional footer content
</div>
</div>
</main>
</div>
<footer class="footer">
footer
</footer>
</div>
网格方法:
* {
box-sizing: border-box;
}
html,
body,
.page {
height: 100%;
margin: 0;
}
.topbar {
grid-area: header;
background-color: lightgreen;
}
.sidebar {
grid-area: sidebar;
overflow-y: auto;
background-color: yellow;
}
.content {
grid-area: content;
display: flex;
flex-flow: column nowrap;
overflow: auto;
background-color: lightblue;
}
.footer {
grid-area: footer;
background-color: pink;
}
.contentsub {
flex-grow: 1;
margin: 1rem;
overflow-y: scroll;
background-color: orange;
}
@media (min-width: 30rem) {
.page {
display: grid;
grid-template-areas: "header header" "sidebar content" "footer footer";
grid-template-columns: 1fr 9fr;
}
}
<div class="page">
<header class="topbar">
top bar
</header>
<aside class="sidebar">
side<br/>side<br/>side
</aside>
<main class="content">
<div>
some additional heading content
</div>
<div class="contentsub">
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
<p>some actual content</p>
</div>
<div>
some additional footer content
</div>
</main>
<footer class="footer">
footer
</footer>
</div>