flex与grid响应式布局中的子容器滚动条问题
最近在用grid布局写一些简单的响应式页面页面,遇到一个问题,就是我们的全局用grid布局或者flex布局中,遇到某个子元素的宽度或者高度是页面剩下的空间(flex是flex-grow:1的空间,grid是1fr的空间),但是这个元素空间又需要有滚动条的出现,即该元素中有很多子元素需要以滚动条的形式查看内容。
出现的问题:grid中即使设置了overflow:auto也还是不会出现滚动条,并且该元素被子内容撑高了,高度不再是剩余空间。
例如我们想要这种效果:(区域内有滚动条)
但是实际上会出现这种效果:(区域被撑高,没有滚动条)
该效果为header宽度或者高度固定,其余为剩余空间利用。
解决办法:grid中每一层都加上overflow:auto,层层传递,如果有一层没有overflow将不能正常出现预期效果,注意如果设置了1fr的容器不要设置height:100%,否者会出现滚动条异常
html代码:
<body>
<div class="system-header">system-header</div>
<div class="system-main">
<div class="main-header">main header</div>
<div class="main-content">
<div class="content-header">
content header
</div>
<div class="content-article">
<div class="article-header">this is header</div>
<div class="face-info">
<div class="face-header">face header</div>
<div class="face-list">
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
<div class="itemBox"></div>
</div>
</div>
</div>
</div>
</div>
</body>
grid布局中css代码:
<style>
html {
height: 100%;
}
body {
height: 100%;
overflow: hidden;
display: grid;
grid-template-rows: 40px 1fr;
}
.system-header {
background: lightgreen;
}
.system-main {
display: grid;
grid-template-columns: 60px 1fr;
overflow: auto;
}
.main-header {
background: lightsalmon;
}
.main-content {
display: grid;
grid-template-rows: 40px 1fr;
overflow: auto;
}
.content-header {
background: yellowgreen;
}
.content-article {
border: 1px solid #ccc;
display: grid;
overflow: auto;
margin-top: 20px;
grid-template-columns: 1fr 250px;
}
.article-header {
background: #c00;
}
.face-info {
display: grid;
grid-template-rows: 30px 1fr;
overflow: auto;
}
.face-header {
background: violet;
}
.face-list {
border: 10px solid lightblue;
overflow: auto;
}
.itemBox {
width: 100%;
height: 100px;
border: 1px solid #c00;
box-sizing: border-box;
}
</style>
flex布局利用flex-direction来改变方向,设定固定大小的header一个固定值不能缩放,然后内容块用flex-grow:1来实现,并且只需要在需要有滚动条的区域用overflow即可
flex实现的css代码:
<style>
html {
height: 100%;
}
body {
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
}
.system-header {
height: 84px;
flex-shrink: 0;
background: lightgreen;
}
.system-main {
flex-grow: 1;
display: flex;
}
.main-header {
width: 154px;
flex-shrink: 0;
background: lightsalmon;
}
.main-content {
flex-grow: 1;
display: flex;
flex-direction: column;
}
.content-header {
background: yellowgreen;
height: 50px;
flex-shrink: 0;
}
.content-article {
flex-grow: 1;
border: 1px solid #ccc;
display: flex;
margin-top: 20px;
}
.article-header {
background: #c00;
width: auto;
flex-grow: 1;
}
.face-info {
width: 350px;
flex-shrink: 0;
display: flex;
flex-direction: column;
}
.face-header {
height: 130px;
flex-shrink: 0;
background: violet;
}
.face-list {
flex-grow: 1;
border: 10px solid lightblue;
overflow: auto;
}
.itemBox {
width: 100%;
height: 100px;
border: 1px solid #c00;
box-sizing: border-box;
}
</style>
由于想测试多种情况嵌套了很多层次,每个层次都是使用grid或者flex来创建一个元素宽或高固定,另一个元素宽高分配剩余空间。也可以grid,flex混合着用都也能正常。
混合使用的情况:这种响应式也可以混合着使用,如果需要子元素正常出现滚动条,其中的是grid父元素一样需要overflow:auto。并且是flex的父元素也需要添加overflow:auto属性。
在这个问题上使用两种情况的利弊:
grid利弊:使用grid需要给层层嵌套元素添加overflow:auto属性比较繁琐。但是可以使用grid-template-columns:100px 1fr;这种形式来一次性给子元素分配空间来布局。
flex利弊:使用flex可以不用给每个嵌套的元素使用overflow:auto属性,但是每个使用了flex的子元素需要手动分配空间,固定元素需要写宽或高属性,并且设置flex-shrink:0;得到剩余空间的元素需要写flex-grow:1属性。
两种方法都可以使用,具体选择可以看个人情况。另外grid布局在ie上的支持很不友好,ie11大部分属性不能使用。而flex可以在ie11上正常显示,根据实际情况选择。
后续补充:
在后面的实践过程中使用flex处理超出内容的时候出现一点意外,那就是在某些情况下也不能正常显示滚动条,处理方法,一层一层的往其祖先元素添加overflow属性(overflow:hidden或者overflow:auto都可以,但是超出元素的直接父元素必须是overflow:auto),直到正常显示其滚动条为止,一般来说嵌套了多少层就需要只是少一两层都需要添加该属性。
下面举个例子:想试验的话可以把里面的overflow属性删除
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{
box-sizing:border-box;
}
.wrap{
width:800px;
height:400px;
border:1px solid #c00;
display:flex;
flex-direction: column;
}
header{
flex:0 0 80px;
border:1px solid #c00;
}
main{
border:1px solid #000;
display:flex;
}
.left{
flex:0 0 120px;
border:1px solid #c00;
}
.right{
border:1px solid #000;
display:flex;
flex-direction:column;
overflow:auto;
}
.nav{
flex: 0 0 24px;
border:1px solid #c00;
}
.twoLayer{
border:1px solid #000;
display:flex;
flex-direction: column;
overflow:auto;
}
.nav2{
flex:1 0 24px;
border:1px solid #c00;
}
.threeLayer{
border:1px solid #000;
display:flex;
flex-direction:column;
overflow:auto;
}
.nav3{
flex: 0 0 24px;
border:1px solid #c00;
}
.fourLayer{
border:1px solid #000;
overflow:auto;
}
.box{
width:2000px;
height:2000px;
background:#ccc;
}
</style>
</head>
<body>
<div class="wrap">
<header></header>
<main>
<div class="left"></div>
<div class="right">
<nav class="nav">nav1</nav>
<div class="twoLayer">
<nav class="nav2">nav2</nav>
<div class="threeLayer">
<nav class="nav3">nav3</nav>
<div class="fourLayer">
<div class="box">i am box element</div>
</div>
</div>
</div>
</div>
</main>
</div>
</body>
</html>
这次的例子滚动区域全是剩余空间,还有flex中direction为column和row的交叉使用,几乎涵盖所有情景,所以如果出现不能正常显示滚动条的情况那就逐层加overflow属性吧,可以在调试工具中试验加几层正常合适,如果不想调试就都加吧