最近在整理前端知识体系,怎么可以少了布局这一环呢?先问大家一个问题,如果让css只保留一种布局,留下来解决前端布局问题?你会选择那个布局呢?如果问我,我会选择 网格布局
,根据二八原则,网格布局基本上可以帮助我解决 80% 的布局场景
,颇有一套布局打遍天下布局的气势,因此非常值得一探究竟。
学习本文,你将会学会:
- 网格布局的基本使用方式,如果已经有基本了解,建议略过
- 网格布局 媒体查询 来解决响应式问题
对于一名前端研发来讲,如果说不会做布局,那可能由于一个画家不会构图,这是非常致命的,但是布局的方式多种多样,只说最为常见的几种,这个是在mdn文档上的排头部的一些。
代码语言:javascript复制display: block;
display: inline;
display: inline-block;
display: flex;
display: inline-flex;
display: grid;
display: inline-grid;
display: flow-root;
布局模式 | 使用场景 | 擅长解决的布局问题 | 不擅长解决的布局问题 | 优势 | 劣势 |
---|---|---|---|---|---|
block | 段落、容器、导航栏 | 垂直布局、容器尺寸控制 | 水平布局复杂性、内联元素布局 | 易于理解和使用、强大的宽高控制 | 布局较为僵硬、不适合复杂布局 |
inline | 文本、图像 | 水平布局、内联元素间的排列 | 垂直边距不生效、大小控制 | 与文本流自然融合 | 无法设置宽高、边距和填充有限制 |
inline-block | 按钮、小部件 | 内联元素的宽高控制 | 大型布局、自动布局 | 结合了inline和block的特点 | 对齐问题、间隙问题 |
flex | 导航栏、卡片布局、复杂的一维布局 | 一维布局、对齐、分布空间 | 二维布局的复杂场景 | 强大的对齐能力、灵活的空间分配 | 学习曲线相对较高 |
inline-flex | 小型的、内联的复杂布局 | 内联元素的复杂布局 | 大型的二维布局 | flex的优点,但适用于内联环境 | 与flex相同,不适合大型的二维布局 |
grid | 复杂的页面布局、表格布局 | 二维布局、对齐、模板区域 | 旧浏览器不兼容 | 强大的二维布局能力、精确布局控制 | 学习曲线高、兼容性问题 |
inline-grid | 内联的复杂布局 | 内联元素的二维布局 | 与grid相同 | grid的优点,但适用于内联环境 | 与grid相同,不适合大型的二维布局 |
flow-root | 清除浮动、局部BFC | 创建新的块格式化上下文 | 复杂布局 | 清除内部浮动不影响外部布局 | 相对较新,可能有兼容性问题 |
这里面的布局的示例就不一样去些demo围观了,,简单的demo可以在 官方网站上https://developer.mozilla.org/en-US/docs/Web/CSS/display 进行查看。
网格布局的基本使用
创建一个简单的网格容器:
代码语言:javascript复制.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px; // 这里也可以写成gap
}
这里,.container
是一个包含三个等宽列的网格容器,grid-gap
设置了网格线之间的间隙,1fr
表示一个份(份子),所以这个表达的意思就是将一行分为3份,每块占1份,repeat(3,1rf)
===1fr 1fr 1fr
。
使用行和列来布局项目:
代码语言:javascript复制.item {
grid-column: 1 / 3;
grid-row: 1;
}
.item
将占据从第一列到第三列之前的空间(即两列宽),并位于第一行。
创建具有不同大小列的网格:
代码语言:javascript复制.container {
display: grid;
grid-template-columns: auto 1fr 2fr;
}
第一列根据内容自动调整大小,第二列占据剩余空间的1份,第三列占据剩余空间的2份。
使用minmax
来设置灵活的网格尺寸:
.container {
display: grid;
grid-template-columns: repeat(3, minmax(100px, 1fr));
}
每列至少100px宽,但可以伸展以占据更多的空间,也就是最大就是1份,。
创建一个自适应数量的列:
代码语言:javascript复制.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
这将创建尽可能多的列,每列至少150px宽,但不会超过可用空间。
对齐网格项:
代码语言:javascript复制.item {
justify-self: start;/* 水平对齐到网格区域的起始边缘 */
align-self: end;/* 垂直对齐到网格区域的末端边缘 */
}
可以控制单个网格项在其网格区域内的对齐方式。
使用命名网格线:
代码语言:javascript复制.container {
display: grid;
grid-template-columns: [start] 1fr [middle] 2fr [end];
}
.item {
grid-column: start / middle;
}
这里,网格线被命名
为start
、middle
和end
,.item
从start
延伸到middle
。
创建网格模板区域:
代码语言:javascript复制.container {
display: grid;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
这样可以定义一个具有头部、侧边栏、内容和页脚区域的布局,这个也是下面的一个打的demo将会讲解的具体例子的基础,本文会基于此并结合媒体查询做一个响应式布局的案例,让你感受一下 grid 媒体查询的厉害之处。
响应式网格:
代码语言:javascript复制@media (max-width: 600px) {
.container {
grid-template-columns: 1fr;
}
}
当屏幕宽度小于600px时,网格将只有一列,这里就是媒体查询结合网格的初步应用,为我们下述的demo打下基础。
网格➕媒体查询,实现响应式
假设,我们的最终实现的目标是这样的一个网页:
- 在页面比较窄的情况下,呈现出一个
flex
布局的样式,direction
为column
。但实际上,我们还是使用grid layout实现哈。 - 在页面稍微变宽点的时候,呈现中间部分显示效果。
- 如果页面在宽到一定程度的时候就,变成右侧部分的显示效果。
怎么做到这个的呢?我给你一个初始的代码:
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
.wrapper {
display: grid;
gap: 20px;
grid-template-areas:
"header"
"nav"
"content"
"sidebar"
"ad"
"footer";
}
.main-head {
grid-area: header;
background-color: bisque;
border: 1px solid rgb(185, 107, 107);
border-radius: 5px;
padding: 2px 5px;
}
.content {
grid-area: content;
background-color: bisque;
border: 1px solid rgb(185, 107, 107);
border-radius: 5px;
padding: 2px 5px;
}
.main-nav {
grid-area: nav;
background-color: bisque;
border: 1px solid rgb(185, 107, 107);
border-radius: 5px;
padding: 2px 5px;
}
.main-nav ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.side {
grid-area: sidebar;
background-color: bisque;
border: 1px solid rgb(185, 107, 107);
border-radius: 5px;
padding: 2px 5px;
}
.ad {
grid-area: ad;
background-color: bisque;
border: 1px solid rgb(185, 107, 107);
border-radius: 5px;
padding: 2px 5px;
}
.main-footer {
grid-area: footer;
background-color: bisque;
border: 1px solid rgb(185, 107, 107);
border-radius: 5px;
padding: 2px 5px;
}
</style>
</head>
<body>
<div class="wrapper">
<header class="main-head">The header</header>
<nav class="main-nav">
<ul>
<li><a href="">Nav 1</a></li>
<li><a href="">Nav 2</a></li>
<li><a href="">Nav 3</a></li>
</ul>
</nav>
<article class="content">
<h1>Main article area</h1>
<p>
In this layout, we display the areas in source order for any screen
less that 500 pixels wide. We go to a two column layout, and then to a
three column layout by redefining the grid, and the placement of items
on the grid.
</p>
</article>
<aside class="side">Sidebar</aside>
<div class="ad">Advertising</div>
<footer class="main-footer">The footer</footer>
</div>
</body>
</html>
这个呈现的效果将会是:
此时,无论如何拉伸,我们始终会看到这样的布局效果,不会改变,此时,我们加入一下媒体查询相关的代码,类似于做一些根据楼几增加样式的事情。
代码语言:javascript复制@media (min-width: 500px) {
.wrapper {
grid-template-columns: 1fr 3fr;
grid-template-areas:
"header header"
"nav nav"
"sidebar content"
"ad footer";
}
nav ul {
display: flex;
justify-content: space-between;
}
}
此时,我们发现布局变了,这里我们做了些啥呢?
@media (min-width: 500px)
在500像素以上时,上下文内样式生效。- 通过
grid-template-areas
,来控制了表格中行列的摆放。 - 通过
grid-template-columns: 1**fr** 3**fr**;
,控制了siderbar和 内容区域的比例。 - 将导航栏变为了
flex
布局
所以,我们看到了网页的变化成了随着宽度的变化到超过 500px时,变成这种展示效果了。继续:
代码语言:javascript复制@media (min-width: 700px) {
.wrapper {
grid-template-columns: 1fr 4fr 1fr;
grid-template-areas:
"header header header"
"nav content sidebar"
"nav content ad"
"footer footer footer";
}
nav ul {
flex-direction: column;
}
}
我们看到了上述的效果,就这样,非常轻松实现了网络的响应式布局,发现网格这种命名区域
的方式,对于布局响应式来说,不是唯一的方式,但是可以说是一种比较清晰,而且有简洁的布局方式。
总结
毫不避讳的讲,网格布局有他的局限性,即兼容性
可以从mdn官网看到,grid支持2017年以后的浏览器版本,IE是肯定不支持的,因此在做选型的时候,如果产品无需支持IE,且用户群体较为时尚,可以考虑grid全量,毕竟这种方式写出的响应式布局代码,整体唯一性来看,会比较好。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!