内容布局(四):Grid布局

耽搁了好久一直没写 Grid 布局,主要是写布局的文章太累人😅。这期就朝花夕拾,写写 Grid layout 的入门教程。

Grid Basic

Grid layout 翻译过来叫网格布局,我先介绍一下 Grid 里的几个基本术语:

Grid Container

网格容器就是被设置为display: grid的元素,通俗来说就是所有网格的最外层:

.grid-container {
  display: grid;
}

Grid Items

网格项就是网格容器里的每一个子元素。如下所示,headerasidemainfooter就是grid-container的网格项。(p.s. 孙子元素不会受到祖先网格属性的影响)

<div class="grid-container">
  <header></header>
  <aside></aside>
  <main>
      <!-- doesn’t effected!!! -->
      <div class="grandson"></div>
      <!-- doesn’t effected!!! -->
  </main>
  <footer></footer>
</div>
container & items

Grid Columns

既然是网格,自然有列和行的概念,我们先说“列”。网格容器添加grid-template-columns属性便可激活列属性:下方示例中,我们把网格项排成了两列。实现上只需把两列的长度(200pxauto)从左至右枚举出来即可:

.grid-container {
  display: grid;
  grid-template-columns: 200px auto;
}
column

除了利用单位或 auto 来指定每一列的长度,我们也可以让列按一定比例排布。下方示例中,实现了左右两列 1:2 比例的布局——只需在grid-template-columns指定1fr2fr即可。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr;
}
Fractions

p.s. fr 是 franction 的缩写

Grid Rows

同理,grid-template-rows会激活行属性,也就是用来定义每一行的高度,属性同样可以是基本单位(px,rem,%),也可以是fr比例:

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr;
  grid-template-rows: 100px 200px;
}
Rows

Grid Gaps

若想为这些排布的 items 添加间距(槽),可以使用grid-gap属性。单独定制横轴或纵轴的间距,还有grid-column-gapgrid-row-gap这两个属性。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr;
  grid-template-rows: 100px 200px;

  grid-column-gap: 10px;
  grid-row-gap: 10px;
  /* or in simplified form */
  grid-gap: 10px;
}
Rows

Grid Cells & Gird Lines

grid-template-columnsgrid-template-rows排布后,横轴和纵轴交汇,就形成如下所示的单元格(grid cell)和标注为 1、2、3... 的网格线(grid line)。这里我提一下,cell 和 item 是不一样的概念:cell 是网格的基本单元,而 item 是可以横跨多个 cell 的 DOM 元素。

cell

Grid Layout

上文我们介绍了几个网格布局的基本术语;若是到此为止,那也顶多是加强版的 table 布局罢了。而网格布局的真正特别之处是在 grid cell 基础上的网格定位。

我们还是从传统布局的弊端说起,下图是一种很常见的页面布局。

Flex Layout

这种布局实现上很直白:先把整体分成三行,再把中间那行分成两列。HTML 便签大体如下所示:

<body>
  <header class="row"></header>
  <div class="row">
    <aside class="column-aside"></aside>
    <main class="column-main"></main>
  </div>
  <footer class="row"></footer>
</body>

实现很简单,就不写 CSS 了;只是在语义标签层面上,headerfooterasidemain 理应是同级;但为了布局方便不得不把 asidemain 做成了孙子节点,有点怪怪的。不过整体也没太大问题。如果再成换更复杂的布局呢,比如,回字形?

Hollow Square

用传统布局技术(如 flex)实现回字形,代码量会立马暴涨。更糟糕的是,这种排版将牺牲掉所有语义标签——你的关注点只会在各种层层嵌套的 div 上了。

Grid Position

网格布局能帮到什么呢?我前文也提到过,Grid items 可以横跨多个 Grid cells,就从这里入手。

我们再看看上面那个回字形布局,本质上不就是个九宫格嘛?我们用 repeat 方法给网格容器写一个 3×3 的 cell 九宫格:

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
}

最后只要把网格项 header 覆盖在第 1 和第 2 个 cell 上、aside 在 4 和 7 上、main 在 3 和 6、footer 在 8 和 9 上,即可完成布局。

Soduku

那网格布局怎么为网格项定位这些 cell 呢?用坐标呀!从 (grid-column-start, grid-row-start)(grid-column-end, grid-row-end) 所在的矩形区域来定位网格项的排布。横坐标值就是 Y 轴(Column Grid Line)所显示的数值,纵坐标就是 X 轴(Row Grid Line)所显示的数值,起始数值都是 1。

Position

上图所示,header 位于 (1,1)(3,2) 这块矩形区域内,我们为 header 添加如下 CSS 属性;header 便会自动定位到左上角那块粉红色区域了。

header {
  grid-column-start: 1;
  grid-row-start:  1;
  grid-column-end: 3;
  grid-row-end: 2;
}

其他几块区域的布局我就不写出来了,大家有兴趣的话自己算一下坐标即可。

Grid Areas

除上面这种二维坐标定位的方式,CSS 网格布局还提供了一种更无脑的定位方式——grid-template-areas——可以为网格设置区域模版,比如上面的回字形布局模版就如下所示:

.grid-container {
  display: grid;
  grid-template-areas:
    "h h m"
    "a . m"
    "a f f";
}

这个模版我写得很简单,解释一下:就是由九个字符及空格所示意的九宫格模版。以左上角 h h 为例,两个相邻的 h 组成了一个所谓的“命名网格区”,表示网格区名为 h 的网格项将会被排布在第 1、2 两个 cell 上。amf 分别是另外三个网格项的标识符;中间的 . 是一个空白区域的占位符,我本人习惯用这个字符,大家尽可以挑选自己喜欢的占位符。

之后,我们再为 headerasidemainfooter 分别设置映射区域——grid-area,这四个网格项就自动排布到各自模版位上去了。

header { grid-area: h; }
aside { grid-area: a; }
main { grid-area: m; }
footer { grid-area: f; }

再回头看一下网格布局的 HTML,语义标签不需要为布局做任何改变。这是较传统布局的重大改进,HTML 结构和 UI 终于实现了分离。

<body class="grid-container">
  <header></header>
  <aside></aside>
  <main></main>
  <footer></footer>
</body>

Grid Kiss

grid-template-areas 还需要为各个网格项命名模版区域,模版能不能自己帮我们映射到相应的 html tag 或是 class 上去呢?这样写起来似乎更省事。

嗯,还真有人想到了这一点——一个叫 postcss-grid-kisspostcss 插件。Grid-kiss 为我们实现了一种很有趣的 CSS 布局方案:让所有的布局变成一幅“简笔画”:

.grid-container {
  grid-kiss:
    "+-------------+  +-----+"
    "|   header    |  |     |"
    "+-------------+  |     |"
    "+-----+          |main |"
    "|     |          |     |"
    "|aside|          +-----+"
    "|     | +--------------+"
    "|     | |    footer    |"
    "+-----+ +--------------+"
    ;
}

它的实现就是把这副文本流图转化成 grid 语法树。有一句广告说的好,“Grid-kiss,布局从未如此简单”

IE support

最后再说一下 IE,早在 E10 的时候它就已经支持网格布局了——还是挺超前的。只可惜 IE 的 Grid 语法别树一帜,未被大众认可;方法与现代 Grid 一比,更相形见绌了。那 IE 上要怎么使用网格布局呢?我们还是得依靠 PostCSS——CSS 里的 Babel,它有个叫 autoprefixer 的插件可以帮我们完成 Modern Grid 到 IE Grid 的转换;这里(Autoprefixer online)还有一个在线的转换网站,有兴趣的朋友可以试一下。

若你已经使用现代 JS 框架(如 Vue、React),它们的脚手架大多内置了 postcss 和 autoprefixer,基本上就是无配置使用。上面的 grid-kiss,也只要给 postcss 配置加个插件,亲测 IE11 可用。至于 IE 的 Grid 语法,就让它随风消逝在历史的长河之中吧。

小结

上次看了篇文章,提到 CSS Grid 已是一种很大众化的前端技术。但我身边的 team,只能说很少很少很少有人使用。我猜原因有多种:

  • 熟练掌握 CSS 的开发人员本身就很少,大家形成了一种“默契”——不要增加认知复杂度
  • 技术革新太快,一开始想着“让子弹飞一会儿”,但是之后就再也没人提起了
  • 传统认知中后端重于前端,很多团队也无心推动前端升级

当然,这些种种我们也应理解,毕竟这只是一种布局技巧,在一个产品的范畴中占不了太多分量;甚至于技术本身,只要别太烂,也并不是决定产品成败的关键。所以嘛,对于新技术也,能用则用,不能用也不要太过执着;做人嘛,最重要的是开心。

相关

文章同步发布于an-Onion 的 Github。码字不易,欢迎点赞。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • CSS Grid(网格) 布局(又称为 “Grid(网格)” ),是一个二维的基于网格的布局系统它的目标是完全改变...
    诺CIUM阅读 1,287评论 0 3
  • Grid 是CSS中最强大的布局系统。它是2-Dimensional System,这意味着它可以同时处理列和行....
    邢烽朔阅读 2,499评论 0 5
  • 网格线(Grid Line) 构成网格结构的分界线。它们既可以是垂直的(“列网格线(column grid lin...
    晚溪呀阅读 1,028评论 0 0
  • 1:基本布局 Grid 布局是二维的基于网格的布局系统,它可以同时处理列和行(这是对比flex弹性盒模型布局而言)...
    前白阅读 809评论 0 1
  • 简介 CSS网格布局(又名“网格”)是一个二维的基于网格的布局系统,其目的只在于完全改变我们设计基于网格的用户界面...
    礼知白阅读 641评论 0 0