https://blog.csdn.net/sinat_32582203/article/details/70257778
不久以前,所有的HTML页面布局都是通过table、float以及其他CSS属性完成的,但这些方法并不适合构建复杂的web页面。
于是,W3C推出了flexbox(弹性盒模型)——一种专门用于构建健壮的响应式页面的布局模式。使用flexbox可以很容易地对齐页面元素和内容,而它也是现在大多数web开发者首选的CSS系统。
现在,最佳HTML布局系统的称号又多了一个新的竞争者,它就是强大的CSS Grid,3月底,它就已经得到了Firefox 52和Chrome 57的原生支持,其他浏览器相信也会紧随其后。
一个基本布局测试
为了了解两种系统的布局方式,我们会分别用这两种系统构建同一个页面,一次使用flexbox(弹性盒模型),一次使用CSS Grid(栅格系统)。页面如下:
(一个精简的静态页面布局)
这种设计非常基础——包含一个居中容器,其中放置页头、主体部分、侧边栏和页脚。为了完成这个布局,我们需要解决这几个问题:
1. 对齐布局中的四个部分(页头、主体、侧边栏、页脚)。
2. 响应式设计(在小屏幕上侧边栏置于主体下方)。
3. 对齐页头内容——导航置于左侧,按钮置于右侧。
为了便于比较,我们一切从简,先从第一个问题开始。
挑战一:页面部分定位
Flexbox解决方案
我们首先使用flexbox解决这个问题,为容器添加display:flex
,并且垂直定位子元素,也即让每个部分纵向排列。
.container {
display: flex;
flex-direction: column;
}
现在我们来让主体部分和侧边栏靠在一起,由于我们已经设置其父容器为纵向,所以我们需要添加一个包装元素,来重新设置主体与侧边栏的定位方式。
<header></header>
<div class="main-and-sidebar-wrapper">
<section class="main"></section>
<aside class="sidebar"></aside>
</div>
<footer></footer>
然后我们将包装元素设置为flex容器(display:flex
)并将定位方式设置为横向(flex-direction:row
)。
.main-and-sidebar-wrapper {
display: flex;
flex-direction: row;
}
最后一步是设置主体与侧边栏的尺寸,我们将其尺寸设置为3:1,使用flex很容易完成这个目标。
.main {
flex: 3;
margin-right: 60px;
}
.sidebar {
flex: 1;
}
我们可以看到,flexbox完美地完成了这项工作,但是我们仍然需要添加大量的CSS属性和一个额外的HTML元素。接下来让我们看看CSS Grid是如何解决这个问题的。
CSS Grid解决方案
CSS Grid有多种使用方法,此处我们使用“栅格模板区域(grid-template-areas
)”语法,因为它看起来最适合完成这个任务。
首先来定义四个栅格区域,每个对应页面的一个部分。
<header></header>
<!-- 注意此处无包装元素 -->
<section class="main"></section>
<aside class="sidebar"></aside>
<footer></footer>
header {
grid-area: header;
}
.main {
grid-area: main;
}
.sidebar {
grid-area: sidebar;
}
footer {
grid-area: footer;
}
然后设置网格并且分配每个区域的位置。下面的代码可能乍一看很复杂,但一旦你了解了栅格系统它就会变得极易掌握。
.container {
display: grid;
/*在网格中定义列的数量和大小。
单位fr工作原理与flex类似:
fr列元素将按照其值共享同一行中的可用空间。
下面的代码表示有两列,第一列是第二列的三倍。*/
grid-template-columns: 3fr 1fr;
/*分配前面定义的网格区域。
第一行均为header。
第二行由main和sidebar共享。
第三行均为footer。*/
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
/*每个网格间距60px*/
grid-gap: 60px;
}
这样就完成了要求,布局将遵从上述结构,并且使用这种方式我们甚至不用处理内边距和外边距。
挑战二:响应式设计
Flexbox解决方案
这一步与前一步紧密联系在一起,对于flexbox来说我们必须改变包装元素的flex-direction
并且调整边距。
@media (max-width: 600px) {
.main-and-sidebar-wrapper {
flex-direction: column;
}
.main {
margin-right: 0;
margin-bottom: 60px;
}
}
由于我们的示例很简单,所以此处需要做的工作并不多,但在一个更复杂的布局中,就会有许许多多的内容需要重定义了。
CSS Grid解决方案
由于我们已经定义好了grid-areas
,所以我们只需要在媒体查询中对网格进行重排序即可。
@media (max-width: 600px) {
.container {
/* 在移动设备上重排序网格*/
grid-template-areas:
"header header"
"main main"
"sidebar sidebar"
"footer footer";
}
}
或者,我们也可以重新定义整个布局,如果你觉得这样可以更简洁些。
@media (max-width: 600px) {
.container {
/* 将页面重新定义为单列布局 */
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
}
挑战三:对齐页头组件
Flexbox解决方案
我们的页头中包括一些导航链接和一个按钮。我们希望将导航置左,按钮置右。导航中的链接必须相邻对齐。
<header>
<nav>
<li><a href="#"><h1>Logo</h1></a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
</nav>
<button>Button</button>
</header>
设置CSS样式:
header {
display: flex;
/*平铺页头内容*/
justify-content: space-between;
}
现在导航列表和按钮已经正确对齐了,剩下的任务就是使<nav>
中的元素水平移动了,最简单的方法是使用display:inline-block
,但是为了完全使用flexbox来完成这个任务,我们使用下面这个解决方案:
header nav {
display: flex;
/*项目位于容器的基线上*/
align-items: baseline;
}
仅有两行代码,还不错。接下来我们看看CSS Grid是如何解决的。
CSS Grid解决方案
为了分离导航和按钮,我们将<header>
设置为2列栅格,另外我们需要额外两行CSS定位它们各自的边界。
header{
display: grid;
grid-template-columns: 1fr 1fr;
}
header nav {
justify-self: start;
}
header button {
justify-self: end;
}
但此时<nav>
中的嵌入式链接,尚未正确对齐,因为CSS Grid中没有类似flexbox的baseline
(基线)选项。所以我们必须再定义一个子网格。
header nav {
display: grid;
grid-template-columns: auto 1fr 1fr;
align-items: end;
}
很明显CSS Grid在完成这项布局中存在一些问题,但也是意料之中的事——毕竟它主要是用来对齐容器的,而不是容器中的内容,它并不适合做最后的润色。
总结
如果你通读了全文,结论就很显然了——并不存在一个最好的布局系统,flexbox和CSS Grid有各自擅长的领域,完全可以一起使用,而非一个能够替代另一个。
对于没时间通读全文的读者,可以看一看最后的总结:
1. CSS Grid更适用于页面的整体架构,非常易于管理页面布局,甚至可以用于非常规、不对成设计中。
2. Flexbox擅长进行元素中内容的对齐,可以使用flex定位设计中的细节部分。
3. 使用CSS Grid进行2D布局(行和列)。
4. Flexbox更适合一维空间(仅行或列)。
5. CSS Grid和flexbox不是替代关系,两者完全可以搭配使用。