图解CSS:Grid布局案例之构建杂志报刊类布局

发布于 大漠

一直以来,在 Web 布局中都是以方方正正的矩形向用户展示 UI 效果,而且众多 Web 开发者的意识中也是如此,Web 的布局是无法打破矩形排列的限制!但 Web 技术的发展速度是惊人的,每天都有新的东西出现在我们的眼前。就在这短短的几年时间内,用于 Web 布局的新特特别的多。换句话说,如果今天设计师跟你说:“亲,整一个类似杂志或报刊类的布局吧”!你会爽快的说 OK! 即,使用现在的新特性可以打破矩形框的限制,让你在 Web 上实现像杂志一样的排版布局。

杂志报刊类布局可能会用到的布局特性

虽然我们今天要聊的主题是使用 CSS Grid 来构建杂志报刊类布局,但这并不代表着,实现这类的布局仅用 CSS Grid 特性就可以。简单地说吧,如果我们要实现上图展示的布局效果,CSS Grid 只是给了我们一些独有的优势,那是因为像 Flexbox 、浮动之类的布局只是一维布局,而 CSS Grid 却不同,他是唯一一个支持两维布局的技术,可以同时在水平和垂直方向控制元素盒子的位置。

不过,要让 Web 布局效果更类似于杂志报刊的设计、排版效果,可能还会用到其他一些 CSS 特性,比如:

  • 多列布局,可以将同一元素里内容自动分成多栏
  • CSS Regions 和 Exclusions,可以很好的解决文本围绕图片的效果,只是目前支持的浏览器非常的少
  • CSS Shapes,可以让内容在任何不规则的容器中流动,也可以围绕着任意不规则的图形排列
  • CSS Clipping 和 Masking,可以裁剪出不规则的图形或形状,也可以让元素按不规则形状展示
  • CSS 书写模式和逻辑属性,可以让文本竖排,也可以按不同的书写(阅读)方式排列
  • 首字下沉,是杂志报刊类常见的一种效果,可以使用 initial-letters 轻易的实现首字下沉的效果
  • Web Fonts 和可变字体,可以让文本更具艺术效果,视觉更具冲击性

有关于这方面更详细的介绍,可以阅读《构建杂志布局可能会用到的CSS特性》一文。

今天的目标

我们今天的目标很明确,使用 CSS Grid 构建杂志报刊类布局,先从简单的开始,比如说实现下图的布局效果:

然后在进入稍微复杂一点的布局,如下图所示:

注意,实现上面的布局效果,CSS Grid 只是用于布局,其他的一些效果还是需要用到 CSS 的其他特性,比如多列布局,书写模式,首字下沉,Flexbox等。

目标一

目标一是 @JENSIMMONS 的 "实验室布局" 首页顶部的布局效果,相对来说是很简单的。实现该效果所需的 HTML 结构也很简单:

<!-- HTML -->
<div class="grid__container">
    <h1>The Experimental Layout Lab</h1>
    <h2>of Jen Simmons</h2>
    <div class="lists">
        <h3>The Conference Talks</h3>
        <ol>
            <li>
                <a href="#">Modern Layouts: Getting Out of Our Ruts</a>
            </li>
        </ol>
    </div>
    <ul class="workshop">
        <li>
            <a href="#">Layout Land Videos</a>
        </li>
    </ul>
    <p class="follow">Follow <a href="#">@jensimmons</a> on Twitter for more as it happens.</p>
</div>

在没有任何 CSS 下,效果很粗矿:

使用浏览器开发者工具的网格审查器,可以很快的分析出该网格的构成要素:

暂且忽略其他的效果,仅聊 Grid。从上图中,我们可以知道这是一个 5 x 5 (五行五列)的网格,如果把网格轨道选项也开启的话,可以知道网格轨道(行和列)的尺寸:

即,使用 grid-tempate-columnsgrid-template-rows 按上图所示轨道尺寸来定义每个网格轨道的尺寸:

.grid__container {
    display: grid;
    grid-template-columns: auto 1fr 1fr 1fr 0.5fr;
    grid-template-rows: auto 1fr 1fr auto auto;
    gap: 1rem;
}

正如上图所示,网格容器创建了,网格轨道尺寸和间距分配好了,接下来要做的是像 叠层布局Full-Bleed布局交叉布局 教程中介绍的类似,显式使用 grid-area(或其子属性 grid-columngrid-row)根据网格线数字索引号明确放置网格项目在网格容器中的位置:

CSS 代码如下:

h1 {
    grid-column: 1 / 4;
}

h2 {
    grid-area: 2 / 3 / 5 / 4;
}

.lists {
    grid-area: 4 / 1 / span 2 / 3;
}

.workshop {
    grid-area: 3 / 4 / 4 / 6;
}

.follow {
    grid-area: 5 / 3 / 6 / 6;
}

网格项目根据网格线名称,把相应的网格项目放置到指定位置。现在缺的只是一些美化方面的样式,比如说字体、字号、颜色等。也就是说,上面的代码,有关于网格方面的布局已完成,后面可能还会添加一些对齐相关的样式,即用于网格轨道、网格项目的对齐属性,如 justify-*align-**-content*-items*-self等:

  • justify-*
    • Flexbox 中主轴对齐(flex-direction的方向)
    • Flexbox 只支持 justify-content,不支持 justify-itemsjustify-self
    • Grid 中的内联轴(Inline Axis)对齐
  • align-*
    • Flexbox 中侧轴对齐
    • Grid 中的块轴对齐
  • *-content
    • Flex项目或网格轨道之间的空间分布
    • 没有多余的空间,这些属性什么也不做
  • *-items*-self
    • 网格区域内的对齐方式
    • 侧轴上的其他 Flex项目对齐

CSS 网格项目中的对齐方式也是根据“盒模型对齐规范”来执行:

  • 运用于“对齐项目到块方向列轴”的对齐属性有:align-itemsalign-self,其中 align-items 运用于网格容器上,align-self 运用于网格项目上
  • 运用于“对齐项目到文本方向行轴”的对齐属性有:justify-itemsjustify-self ,其中 justify-items 运用于网格容器上,justify-self 运用于网格项目上
  • 运用于“对齐项目轨道到块方向的列轴”的对齐属性有:align-content ,该属性运用于网格容器上
  • 运用于“对齐项目轨道到文本方向的行轴”的对齐属性有: justify-content ,该属性运用于网格容器上

也可以按下面这样的方式来划分:

  • 对齐网格项目:justify-itemsjustify-self 沿着行轴对齐网格项目,而 align-itemsalign-self 沿着列轴对齐网格项目,其中 justify-itemsalign-items 被运用于网格容器,而 justify-selfalign-self 被运用于网格项目
  • 对齐网格轨道:align-content 沿行轴对齐网格轨道,justify-content 沿着列轴对齐网格轨道,它们都被运用于网格容器

例如:

h2 {
    justify-self: end
}

为了节约时间,我直接复制了@JENSIMMONS 写的样式。

对于竖排文本,将会使用 CSS 书写模式中的 writing-mode: vertical-lr;,另外对于列表项,我们采用了一个新特性 @counter-style(自定义列表项符号风格)。最终看到的效果如下:

如果你希望让文本更具艺术范,还可以使用一些可变字体(艺术字体):

@font-face {
    font-family:'Decovar Regular24'; 
    src:url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/209981/Decovar-VF.ttf');
}

h1 {
    font-family: "Decovar Regular24", sans-serif;
    font-weight: 800;
    font-style: italic;
    font-variation-settings: "SSTR" 183, "INLN" 648, "TSHR" 460, "TRSB" 312, "TWRM" 638, "SINL" 557, "TOIL" 333, "TINL" 526, "WORM" 523;
}

最终效果如下:

目标二

目标二和目标一相比,多了两个特性,即 首字下沉多列布局。其他的和目标一用到的 CSS 特性是相同的。先上 HTML 结构吧:

<!-- HTML -->
<div class="grid__container">
    <h1>Powers&nbsp;of <span>Attraction</span></h1>
    <figure>
        <img src="" alt="" >
    </figure>
    <div class="des">
        <p>In the modern world...</p>
        <p>By Amanda McCrae</p>
    </div>
    <div class="content">
        <p>Lorem ipsum ...</p>
    </div>
</div>

从示例效果上来看,该示例只需要构建一个 3 x 2 (两行三列)的网格。和前面示例一样,使用 grid-template-*grid-area 明确放置网格项目,即可达到布局所需的效果:

.grid__container {
    display: grid;
    grid-template-columns: auto 1fr minmax(auto, 200px);
    grid-template-rows: minmax(400px, max-content) auto;
    grid-template-areas:
        "figure  des     title"
        "content content content";
    gap: 1rem;
    width: 100vw;
    min-height: 100%;
}

figure {
    grid-area: figure;
}

h1 {
    grid-area: title;
}

.des {
    grid-area: des;
}

.content {
    grid-area: content;
}

和上一个示例有所差异是,显式在网格容器中使用了grid-template-areas 定义网格区域名称,接着使用 grid-area 指定网格区域名称来放置网格项目。

另外,该示例和目标一不同之处,使用了 initial-letter 做首字下沉的效果,另外使用 column-count 做多列布局:

.content {
column-count: 3;
}

@supports (not (initial-letter: 5)) and (not (-webkit-initial-letter: 5)) {
    .content p:nth-of-type(1)::first-letter {
        float: left;
        font-size: calc(1.15rem * 6.25);
        line-height: 0.7;
        margin: 17px 12px 0 0;
    }
}

@supports (initial-letter: 5) or (-webkit-initial-letter: 5) {
    .content p:nth-of-type(1)::first-letter {
        initial-letter: 3;
    }
}

最终效果如下:

把上面两个示例使用到的相关特性结合在一起,就可以很容易构建出下面这个报纸布局的效果:

注意,该示例来自于 Codenpen 上的 @Olivia Ng

通过上面示例给我们带来的思路,可以借助这些 CSS 特性,比如,CSS Grid 和 Flexbox 来完在布局, CSS 书写模式 来改变文本的排列方向,特别是让文本竖排 和 CSS 可变字体 让文本有个性化的渲染 等可以构建出其他的一些 UI效果,比如音乐门标,电商中的优惠卷等:

@Adam Kuhn 在 Codepen 上就用这些特性写了一个这方面的案例

@Jakob Lewis 也用这些技术写了一个饭票的效果