注册
web

学会Grid之后,我觉得再也没有我搞不定的布局了

说到布局很多人的感觉应该都是恐惧,为此很多人都背过一些很经典的布局方案,例如:圣杯布局双飞翼布局等非常耳熟的名词;


为了实现这些布局我们有很多种实现方案,例如:table布局float布局定位布局等,当然现在比较流行的肯定是flex布局


flex布局属于弹性布局,所谓弹性也可以理解为响应式布局,而同为响应式布局的还有Grid布局


Grid布局是一种二维布局,可以理解为flex布局的升级版,它的出现让我们在布局方面有了更多的选择,废话不多说,下面开始全程高能;



本篇不会过多介绍grid的基础内容,更多的是一些布局的实现方案和一些小技巧;



常见布局


所谓的常见布局只是我们在日常开发中经常会遇到的布局,例如:圣杯布局双飞翼布局这种名词我个人觉得不用太过于去在意;


因为这类布局最后的解释都会变成几行几列,内容在哪一行哪一列,而这些就非常直观的对标了grid的特性;


接下来我们来一起看看一些非常常见的布局,并且用grid来实现;


1. 顶部 + 内容


image.png


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
}

body {
display: grid;
grid-template-rows: 60px 1fr;
height: 100vh;
}

.header {
background-color: #039BE5;
}

.content {
background-color: #4FC3F7;
}

.header,
.content {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
</style>
</head>
<body>
<div class="header">Header</div>
<div class="content">Content</div>
</body>
</html>


2. 顶部 + 内容 + 底部


image.png


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
}

body {
display: grid;
grid-template-rows: 60px 1fr 60px;
height: 100vh;
}

.header {
background-color: #039BE5;
}

.content {
background-color: #4FC3F7;
}

.footer {
background-color: #039BE5;
}

.header,
.content,
.footer {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
</style>
</head>
<body>
<div class="header">Header</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
</body>
</html>


这里示例和上面的示例唯一的区别就是多了一个footer,但是我们可以看到代码并没有多少变化,这就是grid的强大之处;


可以看码上掘金的效果,这里的内容区域是单独滚动的,从而实现了headerfooter固定,内容区域滚动的效果;


实现这个效果也非常简单,只需要在content上加上overflow: auto即可;




3. 左侧 + 内容


image.png


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
}

body {
display: grid;
grid-template-columns: 240px 1fr;
height: 100vh;
}

.left {
background-color: #039BE5;
}

.content {
background-color: #4FC3F7;
}

.left,
.content {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}


</style>
</head>
<body>
<div class="left">Left</div>
<div class="content">Content</div>
</body>
</html>


这个示例效果其实和第一个是类似的,只不过是把grid-template-rows换成了grid-template-columns,这里就不提供码上掘金的示例了;



4. 顶部 + 左侧 + 内容


image.png


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
}

body {
display: grid;
grid-template-rows: 60px 1fr;
grid-template-columns: 240px 1fr;
height: 100vh;
}

.header {
grid-column: 1 / 3;
background-color: #039BE5;
}

.left {
background-color: #4FC3F7;
}

.content {
background-color: #99CCFF;
}

.header,
.left,
.content {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}

</style>
</head>
<body>
<div class="header">Header</div>
<div class="left">Left</div>
<div class="content">Content</div>
</body>
</html>


这个示例不同点在于header占据了两列,这里我们可以使用grid-column来实现,grid-column的值是start / end,例如:1 / 3表示从第一列到第三列;


如果确定这一列是占满整行的,那么我们可以使用1 / -1来表示,这样如果后续变成顶部 + 左侧 + 内容 + 右侧的布局,那么header就不需要修改了;



5. 顶部 + 左侧 + 内容 + 底部


image.png


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
}

body {
display: grid;
grid-template-areas:
"header header"
"left content"
"left footer";
grid-template-rows: 60px 1fr 60px;
grid-template-columns: 240px 1fr;
height: 100vh;
}

.header {
grid-area: header;
background-color: #039BE5;
}

.left {
grid-area: left;
background-color: #4FC3F7;
}

.content {
grid-area: content;
background-color: #99CCFF;
}

.footer {
grid-area: footer;
background-color: #6699CC;
}

.header,
.left,
.content,
.footer {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
</style>
</head>
<body>
<div class="header">Header</div>
<div class="left">Left</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
</body>
</html>


这个示例的小技巧是使用了grid-template-areas,使用这个属性可以让我们通过代码来直观的看到布局的样式;


这里的值是一个字符串,每一行代表一行,每个字符代表一列,例如:"header header"表示第一行的两列都是header,这里的header是我们自己定义的,可以是任意值;


定义好了之后就可以在对应的元素上使用grid-area来指定对应的区域,这里的值就是我们在grid-template-areas中定义的值;





码上掘金中的效果可以看到,左侧的菜单和内容区域都是单独滚动的,这里的实现方式和第二个示例是一样的,只需要需要滚动的元素上加上overflow: auto即可;



响应式布局


响应式布局指的是页面的布局会随着屏幕的大小而变化,这里的变化可以是内容区域大小可以自动调整,也可以是页面布局随着屏幕大小进行自动调整;


这里我就用掘金的页面来举例,这里只提供一个思路,所以不会像上面那样提供那么多示例;


1. 基础布局实现


移动端布局


image.png



以移动端的效果开始,掘金的移动端的布局就是上面的效果,这里我简单的将页面分为了三个部分,分别是headernavigationcontent


注:这里不是要100%还原掘金的页面,只是为了演示grid布局,具体页面结构和最后实现的效果会有非常大的差异,这里只会实现一些基础的布局;



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
}

body {
display: grid;
grid-template-areas:
"header"
"navigation"
"content";
grid-template-rows: 60px 48px 1fr;
height: 100vh;
}

.header {
grid-area: header;
background-color: #039BE5;
}

.navigation {
grid-area: navigation;
background-color: #4FC3F7;
}

.content {
grid-area: content;
background-color: #99CCFF;
}


.header,
.navigation,
.content {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}

</style>
</head>
<body>
<div class="header">Header</div>
<div class="navigation">Navigation</div>
<div class="content">Content</div>
</body>
</html>

iPad布局


image.png



这里是需要借助媒体查询来实现的,在媒体查询中只需要调整一下grid-template-rowsgrid-template-columns的值即可;


由于这里的效果是上面一个的延伸,为了阅读体验会移除上面相关的css代码,只保留需要修改的代码;



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>

.right {
display: none;
background-color: #6699CC;
}

@media (min-width: 1000px) {
body {
grid-template-areas:
"header header"
"navigation navigation"
"content right";
grid-template-columns: 1fr 260px;
}

.right {
grid-area: right;

display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
}
</style>
</head>
<body>
<div class="header">Header</div>
<div class="navigation">Navigation</div>
<div class="content">Content</div>
<div class="right">Right</div>
</body>
</html>

PC端布局


image.png



和上面处理方式相同,由于Navigation移动到了左侧,所以还要额外的修改一下grid-template-areas的值;


这里就可以体现grid的强大之处了,我们可以简单的修改grid-template-areas就可以实现一个完全不同的布局,而且代码量非常少;


为了居中显示内容,我们需要在左右两侧加上一些空白区域,可以简单的使用.来实现,这里的.表示一个空白区域;


由于内容的宽度基本上是固定的,所以留白区域简单的使用1fr进行占位即可,这样就可以平均的分配剩余的空间;



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
@media (min-width: 1220px) {
body {
grid-template-areas:
"header header header header header"
". navigation content right .";
grid-template-columns: 1fr 180px minmax(0, 720px) 260px 1fr;
grid-template-rows: 60px 1fr;
}
}
</style>
</head>
<body>
<div class="header">Header</div>
<div class="navigation">Navigation</div>
<div class="content">Content</div>
<div class="right">Right</div>
</body>
</html>

完善一些细节


QQ录屏20231210000552.gif



最终的布局大概就是上图这样,这里主要处理的各个版块的间距和响应式内容区域的大小,这里的处理方式主要是使用column-gap和一个空的区域进行占位来实现的;


这里的column-gap表示列与列之间的间距,值可以是pxemrem等基本的长度属性值,也可以使用计算函数,但是不能使用弹性值fr


空区域进行占位留间距其实我并不推荐,这里只是演示grid布局可以实现的一些功能,具体的实现方式还是要根据实际情况来定,这里我更推荐使用margin来实现;


完整代码如下:



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
}

body {
display: grid;
grid-template-areas:
"header header header"
"navigation navigation navigation"
". . ."
". content .";
grid-template-columns: 1fr minmax(0, 720px) 1fr;
grid-template-rows: 60px 48px 10px 1fr;
column-gap: 10px;
height: 100vh;
}

.header {
grid-area: header;
background-color: #039BE5;
}

.navigation {
grid-area: navigation;
background-color: #4FC3F7;
}

.content {
grid-area: content;
background-color: #99CCFF;
}

.right {
display: none;
background-color: #6699CC;
}

@media (min-width: 1000px) {
body {
grid-template-areas:
"header header header header"
"navigation navigation navigation navigation"
". . . ."
". content right .";
grid-template-columns: 1fr minmax(0, 720px) 260px 1fr;
}

.right {
grid-area: right;

display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
}

@media (min-width: 1220px) {
body {
grid-template-areas:
"header header header header header"
". . . . ."
". navigation content right .";
grid-template-columns: 1fr 180px minmax(0, 720px) 260px 1fr;
grid-template-rows: 60px 10px 1fr;
}
}

.header,
.navigation,
.content {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}

</style>
</head>
<body>
<div class="header">Header</div>
<div class="navigation">Navigation</div>
<div class="content">Content</div>
<div class="right">Right</div>
</body>
</html>

简单复刻版




码上掘金上的效果来说已经完成了大部分的布局和一些效果,目前来说就是还差一些交互,还有一些细节上的处理,感兴趣的同学可以自行完善;



异型布局


异性布局指的是页面中的元素不是按照常规的流式布局进行排版,又或者说不规则的布局,这里我简单的列出几个布局,来看看grid是如何实现的;


1. 照片墙


image.png


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
margin: 0;
padding: 0;
background: #f2f3f5;
overflow: auto;
}

body {
display: grid;
grid-template-columns: repeat(12, 100px);
grid-auto-rows: 100px;
place-content: center;
gap: 6px;
height: 100vh;
}

.photo-item {
width: 200px;
height: 200px;
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}

</style>
</head>
<body>

</body>
<script>
function randomColor() {
return '#' + Math.random().toString(16).substr(-6);
}

let row = 1;
let col = 1;
for (let i = 0; i < 28; i++) {
const div = document.createElement('div');
div.className = 'photo-item';
div.style.backgroundColor = randomColor();
div.style.gridRow = `${row} / ${row + 2}`;
div.style.gridColumn = `${col} / ${col + 2}`;

document.body.appendChild(div);
col += 2;
if (col > 11) {
row += 1;
col = row % 2 === 0 ? 2 : 1;
}
}
</script>
</html>


这是一个非常简单的照片墙效果,如果不使用grid的话,我们大概率是会使用定位去实现这个效果,但是换成grid的话就非常简单了;


而且代码量是非常少的,这里就不提供码上掘金的 demo 了,感兴趣的同学可以将代码复制下来自行查看效果;



2. 漫画效果


image.png




在漫画中有很多类似这种不规则的漫画框,如果使用定位的话,那么代码量会非常大,而且还需要计算一些位置,使用grid的话就非常简单了;


可以看到这里还有一个气泡文字显示的效果,按照页面书写顺序,气泡是不会显示的,这里我们可以使用z-index来实现,这里的z-index值越大,元素就越靠前;


而且气泡文字效果也是通过grid来进行排版的,并没有使用其他的布局来实现,代码量也并不多,感兴趣的同学可以自行查看;



3. 画报效果


image.png




在一个画报中,我们经常会看到文字和图片混合排版的效果,由于这里直接使用的是渐变的背景,而且我的文字都是随意进行排列的,没有什么规律,所以看起来会比较混乱;


在画报效果中看似文字排版非常混乱不规则,但是实际上设计师在设计的时候也是会划分区域的,当然用定位也是没问题的,但是使用grid的话就会简单很多;


我这里将页面划分为12 * 12区域的网格,然后依次对不同的元素进行单独排列和样式的设置;



流式布局


流式布局指的是页面的内容会随着屏幕的大小而变化,流式布局也可以理解为响应式布局;


但是不同于响应式布局的是,流式布局的布局不会像响应式布局那样发生变化,只是内容会随着轴进行流动;


通常这种指的是grid-template-columns: repeat(auto-fit, minmax(0, 1fr))这种;


直接看效果:


QQ录屏20231210222012.gif




这里有两个关键字,一个是auto-fit,还有一个是auto-fill,在行为上它们是相同的,不同的是它们在网格创建的不同,



image.png



就像上面图中看到的一样,使用auto-fit会将空的网格进行折叠,可以看到他们的结束colum的数字都是6;


像我们上面的实例中不会出现这个问题,因为我们使用了响应式单位fr,只有使用固定单位才会出现这个现象;


感兴趣的同学可以将minmax(200px, 1fr)换成200px尝试;



对比 Flex 布局


在我上面介绍了这么多的布局场景和案例,其实可以很明显的发现一件事,那就是我使用grid进行的布局基本上都是大框架;


当然上面也有一些布局使用flex也是可以实现的,但是我们再换个思路,除了flex可以做到上面的一些布局,float布局、table布局、定位布局其实也都能实现;


不同的是float布局、table布局、定位布局基本上都是一些hack的方案,就拿table布局来说,table本身就是一个html标签,作用就是用来绘制表格,被拿来当做布局的一种方案也是迫不得已;


web布局发展到现在的我们有了正儿八经可以布局的方案flex,为什么又要出一个grid呢?


grid的出现绝对不是用来替代flex的,在我上面的实现的一些布局案例中,也可以看到我还会使用flex


我个人理解的是使用grid进行主体的大框架的搭建,flex作为一些小组件的布局控制,两者搭配使用;


flex能实现一些grid不好实现的布局,同样grid也可以实现flex实现困难的布局;


本身它们的定位就不痛,flex作为一维布局的首选,grid定位就是比flex高一个维度,它的定位是二维布局,所以他们之间没有必要进行对比,合理使用就好;


总结


上面介绍的这么多基于grid布局实现的布局方案,足以看出grid布局的强大;


grid布局的体系非常庞大,本文只是梳理出一些常见的布局场景,通过grid布局去实现这些布局,来体会grid带来的便利;


可能需要完全理解我上面的全部示例需要对grid有一定的了解才可以,但是都看到这里了,不妨去深挖一下;


grid布局作为一项强大的布局技术,有望在未来继续发展,除了我上面说到的布局,grid还有很多小技巧来实现非常多的布局场景;


碍于我的见识和文笔的限制,我这次介绍grid肯定是有很多不足的,但是还是希望这篇文章能为你对于布局相关能有新的认识;


作者:田八
来源:juejin.cn/post/7310423470546354239

0 个评论

要回复文章请先登录注册