不久以前,所有 html 页面的布局还都是通过 tables、floats 以及其他的 CSS 属性来完成的。面对复杂页面的布局,却没有很好的办法。
然而 Flexbox 的出现,便轻松的解决了复杂的 web 布局。它是一种专注于创建稳定的响应式页面的布局模式,并可以轻松地正确对齐元素及其内容。如今已是大多数 Web 开发人员首选的 CSS 布局方式。
现在,又出现了一个构建 HTML 最佳布局体系的新竞争者。(冠军头衔正在争夺中…)它就是强大的 CSS Grid 布局。直到本月月底,它也将在 Firefox 52 和 Chrome 57 上得到原生支持,相信不久也会得到其他浏览器兼容性的支持。
要了解这两个体系构建布局的方式,我们将通过相同的 HTML 页面,利用不同的布局方式 (即 Flexbox 与 CSS Grid)为大家区分。
同时,你也可以通过文章顶部附近的下载按钮,下载演示项目进行对比,或者通过在线演示来察看它们:
简版静态页面布局
该页面的设计相对比较简单 – 它是由一个居中的容器组成,在其内部则包含了标头、主要内容部分、侧边栏和页脚。接下来,我们要完成同时保持 CSS 和 HTML 尽可能整洁的挑战事项:
如你所见,为了便于比较,我们将所有事项从简处理。那么,让我们从第一个挑战事项开始吧!
我们将从 Flexbox 解决方案开始。我们将为容器添加
来指定为 Flex 布局,并指定子元素的垂直方向。
- display: flex
- .container {
- display: flex;
- flex-direction: column;
- }
现在我们需要使主要内容部分和侧边栏彼此相邻。由于 Flex 容器通常是单向的,所以我们需要添加一个包装器元素。
- <header>
- </header>
- <div class="main-and-sidebar-wrapper">
- <section class="main">
- </section>
- <aside class="sidebar">
- </aside>
- </div>
- <footer>
- </footer>
然后,我们给包装器在反向添加
和
- display: flex
属性。
- flex-direction
- .main-and-sidebar-wrapper {
- display: flex;
- flex-direction: row;
- }
最后一步,我们将设置主要内容部分与侧边栏的大小。通过 Flex 实现后,主要内容部分会比侧边栏大三倍。
- .main {
- flex: 3;
- margin-right: 60px;
- }
- .sidebar {
- flex: 1;
- }
如你所见,Flex 将其很好的实现了出来,但是仍需要相当多的 CSS 属性,并借助了额外的 HTML 元素。那么,让我们看看 CSS Grid 如何实现的。
针对本项目,有几种不同的 CSS Grid 解决方法,但是我们将使用 网格模板区域 语法来实现,因为它似乎最适合我们要完成的工作。
首先,我们将定义四个网格区域,所有的页面各一个:
- <header>
- </header>
- <!-- Notice there isn't a wrapper this time -->
- <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;
- }
然后,我们会设置网格并分配每个区域的位置。初次接触 Grid 布局的朋友,可能感觉以下的代码会有些复杂,但当你了解了网格体系,就很容易掌握了。
- .container {
- display: grid;
- /* Define the size and number of columns in our grid.
- The fr unit works similar to flex:
- fr columns will share the free space in the row in proportion to their value.
- We will have 2 columns - the first will be 3x the size of the second. */
- grid-template-columns: 3fr 1fr;
- /* Assign the grid areas we did earlier to specific places on the grid.
- First row is all header.
- Second row is shared between main and sidebar.
- Last row is all footer. */
- grid-template-areas:
- "header header"
- "main sidebar"
- "footer footer";
- /* The gutters between each grid cell will be 60 pixels. */
- grid-gap: 60px;
- }
就是这样! 我们现在将遵循上述结构进行布局,甚至不需要我们处理任何的 margins 或 paddings 。
这一步的执行与上一步密切相关。对于 Flexbox 解决方案,我们将更改包装器的
属性,并调整一些 margins。
- flex-direction
- @media (max-width: 600px) {
- .main-and-sidebar-wrapper {
- flex-direction: column;
- }
- .main {
- margin-right: 0;
- margin-bottom: 60px;
- }
- }
由于网页比较简单,所以我们在媒体查询上不需要太多的重写。但是,如果遇见更为复杂的布局,那么将会重新的定义相当多的内容。
由于我们已经定义了网格区域,所以我们只需要在媒体查询中重新排序它们。 我们可以使用相同的列设置。
- @media (max-width: 600px) {
- .container {
- /* Realign the grid areas for a mobile layout. */
- grid-template-areas:
- "header header"
- "main main"
- "sidebar sidebar"
- "footer footer";
- }
- }
或者,我们可以从头开始重新定义整个布局。
- @media (max-width: 600px) {
- .container {
- /* Redefine the grid into a single column layout. */
- grid-template-columns: 1fr;
- grid-template-areas:
- "header"
- "main"
- "sidebar"
- "footer";
- }
- }
我们的标头包含了导航和一个按钮的相关链接。我们希望导航朝左对齐,按钮向右对齐。而导航中的链接务必正确对齐,且彼此相邻。
- <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>
我们曾在一篇较早的文章中使用 Flexbox 做了类似的布局: 响应式标头最简单的制作方法 。这个技术很简单:
- header {
- display: flex;
- justify-content: space-between;
- }
现在导航列表和按钮已正确对齐。下来我们将使
内的 items 进行水平移动。这里最简单的方法就是使用
- <nav>
属性,但目前我们需要使用一个 Flexbox 解决方案:
- display:inline-block
- header nav {
- display: flex;
- align-items: baseline;
- }
仅两行代码就搞定了! 还不错吧。接下来让我们看看如何使用 CSS Grid 解决它。
为了拆分导航和按钮,我们要为标头定义
属性,并设置一个 2 列的网格。同时,我们还需要两行额外的 CSS 代码,将它们定位在相应的边界上。
- display: grid
- header{
- display: grid;
- grid-template-columns: 1fr 1fr;
- }
- header nav {
- justify-self: start;
- }
- header button {
- justify-self: end;
- }
至于导航中的内链 - 这是我们使用 CSS grid 最好的布局展示:
虽然链接为内链形式,但它们不能正确的对齐。由于 CSS grid 不具备基线选项(不像 Flexbox 具备的
属性),所以我们只能再定义一个子网格。
- align-items
- header nav {
- display: grid;
- grid-template-columns: auto 1fr 1fr;
- align-items: end;
- }
CSS grid 在此步骤中,存在一些明显的布局上的缺陷。但你也不必过于惊讶。因为它的目标是对齐容器,而不是内部的内容。所以,用它来处理收尾工作,或许不是很好的选择哦。
如果你已经浏览完整篇文章,那么结论不会让你感到意外。事实上,并不存在最好的布局方式。Flexbox 和 CSS grid 是两种不同的布局形式,我们应该根据具体的场景将它们搭配使用,而不是相互替代。
对于那些跳过文章只想看结论的朋友(不用担心,我们也这样做),这里是通过实例比较后的总结:
感谢你的阅读。若你有所收获,欢迎点赞与分享。
来源: http://www.tuicool.com/articles/ieM3YjE