剑客
关注科技互联网

二维 grid 布局

so,first question? 啥是 grid 布局? grid 布局是针对 Web 布局的一个升级版,首先,回想一下,我们写 HTML 的时候,一个一个 div 像搭积木一样,完成我们最后的网页。当然,我们还需要使用 CSS 来配置我们每个 DOM 元素的具体位置,比如 navbar,sidebar 等等。有时候还要用各种 trick 才能满足我们想要的布局结果。但为啥总感觉不爽… 我就只想要这个元素放到指定位置而已,有这么难吗?

有的

当然,你可以使用 absolute 来完成,但这样造成的性能损耗我就不多说了,问题是,你调位置估计就要哭在哪。。。为啥? 太复杂了。。。按照图形学来说,如果有一个坐标让我布局,那就好了。 so, grid 就这样诞生了。经历了 flexbox 的一维布局,grid 我们就可以用一句话表达:

grid 是网页的二维布局方式

ok, let’s start。由于 grid 的支持性真的很渣。。。所以使用时需要额外开启实验室特性,在 Chrome 中,打开chrome://flags 开启实验特性即可。首先,我们来了解一下关于 grid 的基本概念。

grid 概念

grid 的内容其实和 table,flexbox 差不多。相当于两者的结合产物。通常,直接通过 display:grid; 来使用。最最基本的格式为:

<div class="container" style="display:grid;">
  <div class="item item-1"></div>
  <div class="item item-2"></div>
  <div class="item item-3"></div>
</div>

这里就包含了两个最基本的概念。

container 和 items

container 就是使用 display:grid 的 DOM。items 就是 container 包裹的一级子元素。记住:二级子元素就和 grid 没关系! 然后,剩下的就是和 table 类似的属性了。

line 和 cell

这个就比较好解释了,先看图吧:

这是 grid_line

二维 grid 布局

这是 grid_cell

二维 grid 布局

当然,还没完,接着就是 repeat cell 过后的理念。

track 和 area

track 相当于就是 行或者列。area 就是多个 cell 组成的面积。

这是 track

二维 grid 布局

这是 area

二维 grid 布局

grid 基本布局

grid 的强大之处在于,他可以将网页划分为很多小格子,而你可以将你的 DOM 随意的放在你想放的格子里面。还有一个必须要记住的点:

column, float, clear, 和 vertical-align 在 grid 布局中是没有效果的!

我们先来看个 demo: 请问,你能在 5min 之内实现下列布局吗?

二维 grid 布局

word哥。。。在没有接触到 grid 之前,我最先想到的就是使用 flexbox 来实现。而且需要 8 个 div。而且尼玛就 5min。要是遇到这样的面试题,我估计就直接喷面试官了。。。MDZZ。 但,面试官总会显现他蜜汁微笑说,这,不,是,很,简,单,吗? 是的,使用 grid 布局,真的很简单。看下实际代码也就几行:

// HTML
<div id="container">
    <div class="column-1">one</div>
    <div class="column-2">two</div>
    <div class="column-3">three</div>
    <div class="column-4">four</div>
    <div class="column-5">five</div>
</div>

// CSS 部分
body {
    min-width: 550px;

}
#container{
    height: 200px;
    display: grid;
    grid-template-columns:1fr 1fr 1fr 1fr;
    grid-template-rows:1fr 1fr 1fr;
    grid-template-areas:"one one two three"
    "four four two three"
    "five five five three";
}
.column-1{
    grid-area:one;
    background-color: #F8594C;
}
.column-2{
    grid-area:two;
    background-color: #FFA29B;
}
.column-3{
    grid-area:three;
    background-color: #318B98;
}
.column-4{
    grid-area:four;
    background-color: #E73123;
}
.column-5{
    grid-area:five;
    background-color: #ABE646;
}

完整的实例可以参考: grid 布局

可以说,grid 就是让你用张纸画几个网格,然后填充,然后网页就做好了。如果你想要动效的话,使用 animation 就 ok。啊~ 真简单。。。 接下来,我们来详细的看一下 grid 里面有哪些属性标签。权威指南请参考: MDN grid layout

grid 标签讲解

grid 的标签可以细分为两类:一类是属于 container,一类是数据 items。 各有:

  • container:

    • grid-template-columns
    • grid-template-rows
    • grid-template-areas
    • grid-template
    • grid-auto-columns
    • grid-auto-rows
    • grid-auto-flow
    • grid
    • grid-column-gap
    • grid-row-gap
    • grid-gap
    • justify-items
    • align-items
    • justify-content
    • align-content
  • items:

    • grid-column-start
    • grid-column-end
    • grid-row-start
    • grid-row-end
    • grid-column
    • grid-row
    • grid-area
    • justify-self
    • align-self

看起来蛮多的,不过细分下来就几个: template,auto,gap,布局(content/items) 这里,我们就按上面的分类来讲解。首先是 container 分类部分:

container

template

container 中的 template 有三种(还有一个是综合标签):columns,rows,areas。我们先来看下 columns 和 rows。

grid-template-columns/rows

基本格式为:

grid-template-columns: <track-size> ... | <line-name> <track-size> ... | subgrid;
 grid-template-rows: <track-size> ... | <line-name> <track-size> ... | subgrid;

也就是说,该标签中属性还是蛮多的。我们简单介绍一下:

  • track-size:不论是 column 还是 row,都是用来定义行高/列宽。取值可以为 px,%,auto,fr。重点说一下 auto 和 fr。 auto 和 其他两个属性结合起来才有效,表示自动充满剩下的空间。 fr 就是 free space 的意思,用来表示是否均分剩下的空间。
  • line-name:用来设置行/列 line 的名称。这个结合 item 中的 grid-row 有效。不设置的话,默认为 1,2,3,4…
  • subgrid:嵌套 grid 时有效。暂不在讨论的范围之内。

看实例吧: 设置如下属性值:

.container{
  grid-template-columns: 40px 50px auto 50px 40px;
  grid-template-rows: 25% 100px auto;
}

可以得到:

二维 grid 布局

相当于每个值都代表行/列宽,百分数的值相对于 container 的宽度来的。继续,我们加上 line-name 来试一试:

.container{
  grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
  grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}

二维 grid 布局

感觉定义了 line-name 之后,会有点复杂。我们可以这样记忆,值抽象为就是行/列,左右两侧就是线。这样感觉是不是好一点了? fr 的话,就比较简单了,均分操作:

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

另外, css 还提供了一个 repeat 函数,来帮助我们快速书写同样格式的样式:

// 使用 repeat
grid-template-columns: repeat(3, 20px [col-start]) 5%;

// 等同于
 grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%;

另外,我们还可以使用简写形式,将 columns 和 rows 写在一起。

// 基本格式就是: row / column / area
grid-template:repeat(4,1fr) / repeat(3,1fr);

接下来是 grid-template-areas 。该属性通常和 items 中的 grid-area 结合一起使用。

grid-template-areas

他的基本格式为:

grid-template-areas: "<grid-area-name> | . | none | ..."
                       "..."

记住,areas 写的时候,注意是可以分行写的,这点极其重要。因为这可以对应于每个网格的 name 。基本取值为:

  • grid-area-name:相当于给每个 cell 取名字,比如 header,footer,body 等等。
  • . : 将该单元格设置空值。就是啥也没有的意思。连名字也没有,那么就相当于将该 cell 设为 empty。
  • none:是真的啥也没有,当和 grid_name 混合使用时,和 . 没啥太大的区别。但关键在于,他通常用于单独定义的。

记住,该属性必须和 item 中的 grid-area 才有效果,具体的使用就是我上面的 demo:

#container{
    height: 200px;
    display: grid;
    grid-template-columns:1fr 1fr 1fr 1fr;
    grid-template-rows:1fr 1fr 1fr;
    grid-template-areas:"one one two three"
    "four four two three"
    "five five five three";
}
.column-1{
    grid-area:one;
    background-color: #F8594C;
}
.column-2{
    grid-area:two;
    background-color: #FFA29B;
}
...

整体效果如: grid-template-area

gap

grid 中 gap 相关的有两个:grid-column-gap,grid-row-gap。这很好理解,就是用来设置行/列间隙。基本格式也是很简单:

grid-column-gap: <line-size>;
  grid-row-gap: <line-size>;
  • line-size:基本 web 中的长度单位都可以使用,比如 px,vh,em,rem,auto 等等。不过比较遗憾的是,他不能设置每一个行/列间隔的大小。

比如:

.container{
  grid-column-gap: 10px;
  grid-row-gap: 15px;
}

二维 grid 布局

另外还有一个综合单位就是: grid-gap。它其实就是上面两个的综合。基本形式为:

grid-gap: <grid-column-gap> <grid-row-gap>;

接下来我们来看一下 auto 系列。

auto

auto 包含的内容和 gap 差别不大,不过,他包含的是 3 个 tag:

grid-auto-columns: <track-size> ...;
grid-auto-rows: <track-size> ...;
grid-auto-flow: row | column | row dense | column dense

我们先说一下前两个: grid-auto-columns,grid-auto-rows 这两个属性,主要是用来弥补当元素放的位置超出 grid 时,在外部虚拟生成行/列的大小值。感觉有点难懂。。。这个的主要应用场景同样需要和 item 中的两个属性值:grid-column,grid-row 结合使用。这两个是干嘛的?他们是根据网格的线来设置元素的位置。 比如:

// 这个 container 只有 2x2 的布局结构
.container{
  grid-template-columns: 60px 60px;
  grid-template-rows: 90px 90px
}

想这样:

二维 grid 布局

现在将一个 item-b 放到 2×5 的右下角位置上。即为这样:

二维 grid 布局

然后设置 grid-column 和 grid-row 可以为:

grid-column: 5 / 6;  // 第 5 条到第 6 条竖线之间
grid-row: 2 / 3;  // 第 2 条到第 3 条横线之间

但这样的问题是,他虽然确实占了,但是那个 cell 是 0x0 的,相当于没有。。。那有啥用。所以,为了更加灵活的设置, grid 推出的 auto 系列,就有用了。这里,我们可以设置:

grid-auto-columns: 60px;
// 为啥不设 row? 
// 因为根本就没超过 row 的范围。。。

ok,现在就变为一下的格式:

二维 grid 布局

当然,如果你设置超出了 row 的话,那就适合 grid-auto-rows 即可。现在看一个比较拗口的属性:

grid-auto-flow

它主要是用来设置多余元素在剩下位置的排列顺序,重置排序。基本格式为:

// row 为默认值
grid-auto-flow: row | column | row dense | column dense
  • row:设置剩下的元素按照行顺序一次填充,如果超出,自动增加行。
  • column:设置剩下元素按照列顺序依次填充,如果超出,自动增加列。
  • dense:强制剩下元素从第一个还未排的 cell 开始。

现假设,我们有个 3×3 的布局: 初始样式为:

二维 grid 布局

看一下 CSS:

// 这里设置的 3x3 布局。然后将第一个 item 放在第二个 cell 位置
    #container{
        height: 200px;
        display: grid;
        grid-template:repeat(3,1fr) / repeat(3,1fr);
        grid-auto-flow:row;
    }
    .column-1{
        grid-column:2;
        background-color: #F8594C;
    }
    .column-2{
        background-color: #FFA29B;
    }
    //...

然后,剩下的就会依次排开。Ok,现在我们切换为 column,他排列方式就变为:

二维 grid 布局

然后我们再加上 dense 。最后的结果( column dense )就变为:

二维 grid 布局

感觉,这个属性还是挺复杂的,关键它的插入算法的机理并没有太清楚,而且也还在草案道中,所以,我们简单了解就好,不深究了。

最后就是 4 个定位布局的属性了。

  • justify-items
  • align-items
  • justify-content
  • align-content

items/content

items 相关是用来控制 cell 里面内容的分布位置和 flexbox 中的 align-items/justify-content 类似。

justify-items

justify-items 是用来控制 item 水平布局。基本格式为:

// stretch 是默认值
justify-items: start | end | center | stretch;

那它的实际效果是啥呢? 看几张图,估计就明白了。

justify-items: start;

效果为:

二维 grid 布局

justify-items: center;

效果为:

二维 grid 布局

剩下的 end 和 stretch 我就不赘述了。如果不是 stretch,它都是根据你元素中的文本内容进行自适应宽度的。 在 item 中使用 justify-self 可以控制独立 item 的布局位置。

align-items

align-items 就是用来控制 item 垂直布局。基本格式为:

// stretch 是默认值
align-items: start | end | center | stretch;

它的效果和 justify-items 很类似,同样看几个 demo:

align-items: start;

效果图为:

二维 grid 布局

上下的我就不多说了。并且,在 item 中使用 align-self 可以控制独立 item 的布局位置。

剩下的还有两个:justify-content,align-content

content 相关它俩做的工作差不多,和上述两个 tag 最大的区别在于,它们是用来控制整个 container 的布局。怎么说呢? 当使用 grid-template-rows/columns 设置行高/列宽时,如果全部使用的都是 px 并没有填充满时,那么contaienr 就会有一个块空出来。所以,为了解决这个问题,grid 就提出了 justify-content,align-content 这两个 tag。 基本格式为:

// start 为默认值
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;	
align-content: start | end | center | stretch | space-around | space-between | space-evenly;

这里,针对 justify-content 进行下讲解,另外一个是相似的只是排列方向是按纵向来进行排列的。先假设,我们通过 grid-template-columns 设置的 container 如下图:

二维 grid 布局

分别添加属性测试:

justify-content: end;

放后

二维 grid 布局

justify-content: center;

放前

二维 grid 布局

justify-content: stretch;

拉伸

二维 grid 布局

justify-content: space-around;

该属性的意思是,将多余的 space 均匀分给每一个 grid-item(左右都有)。

space-around

二维 grid 布局

justify-content: space-between;

该属性的意思是,将多余的 space 均匀的分在 grid-item 之间,不包括前后。

space-between

二维 grid 布局

justify-content: space-evenly;

该属性的意思是,将多余的 sapce 均匀的分在 grid-item 之间,包括前后。

space-evenly

二维 grid 布局

基本上关于 container 的标签就已经说完了。下面我们来看看 items 相关(可少了。。。)

items

items 中的标签有 3 类:line,area,布局

line

在 grid 布局中,定位一个 DOM 的位置,有两种方式,一种是靠 grid-line,比如,指定你从哪一根开始,另外一种是靠 area,比如,将一个 DOM 放在 1,2,3 cell 中。这里,关于 grid-line 布局的设置属性有两个:行/列

grid-column: grid-column-start / grid-column-end;
grid-row:grid-row-start / grid-row-end;

里面基本的取值可以为:

<number> | <name> | span <number> | span <name> | auto

比如:

grid-column:1/3; // 将 DOM 放在 第一行到第三行之间。
  • number:指定第几根线,来决定放的位置。
  • name:根据 grid-template-columns 中命名的 grid-line-name 来决定放的位置。
  • span <number>/<name>:相当于到…为止。通常结合 number 时,效果才能体现出来,比如: 1/span 2 。表示从第 1 根开始,到过 2 根线位置。最后就是 1/3

比如:

grid-column:1 / col4-start;
grid-row: 2/span 2;

二维 grid 布局

area

通过 area 布局的标签就一个: grid-area 基本格式为:

grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
  • name:根据 grid-template-areas 设置的 cell 的别名。比如:header,foooter 等。
  • row-start/…/column-end: 和上面的 grid-column 一致。用线来框出具体的范围。

例如:

grid-area: header;
// 或者为:
grid-area: 1 / col4-start / last-line / 6

布局

在 container 中提到过,使用 justify-self,align-self 即可实现在 cell 中,content 的排列位置。常用取值为:

justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;

具体的实现方式在 container 中我已经说过了,这里就不赘述了。

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址