就你小子还不会 Grid布局是吧?
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8bDS5yX4Oyq6iaxYS5ZyzOFKUU0eGa3ulw31DMfd8SgrcJwgIIvdn9yg/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p><p>CSS Grid 的功能远比我们想象的要强,很多人对 Gird 布局仅仅局限于了解或者一知半解,殊不知它是 CSS 语言中最牛逼的部分之一</p>
<p>但即使如此,我身边还是很多人一把 <code>display:flex</code>梭哈的人,我尝试和他们沟通,让他们上手体验 <code>grid</code>强大布局,而他们直接来句:“flex 又不是不行?”</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8XFic69ahyHy0FNOR4WjTnkylYSFaHPhDT9gEAGsCn3YPfvgQX0Z9saw/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>嘿?他 * 的还真就不行!</p>
<p>今天,我立志把 <code>CSS Grid</code> 讲透、讲明白,让你以后见到它就如同见到黑丝一样抓狂</p>
<blockquote>
<p>CSS Grid 虽然强大,但它存在部分兼容性的问题。自 2017 年以来,所有主要浏览器都支持它!</p>
<p>根据 caniuse 的说法,97.8% 的用户支持 CSS Grid^^,也就是说:浏览器基本上都兼容了</p>
</blockquote>
<h2>初识 Gird</h2>
<p>使用 <code>gird</code>布局十分简单,只需要将 <code>display</code>属性设置为 <code>grid</code>即可:</p>
<pre><code>.wrapper {
display: grid;
}
</code></pre>
<p>默认情况下,CSS Grid 的列是独占一行的,其宽度随父盒子大小</p>
<p>其工作原理如下:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8iadHuiaQrwLvGtx4Xd359unl5icIHmFGFwBGuL3ZAs5k3UAzkpsuJ9DRQ/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>在例子中,我们可以看的出:栅格父对象的高度不固定,由其子对象的数量和高度来决定。但是如果我们给父级网格一个固定的高度,而子级网格不设置高度呢?在这种情况下,总表面积被分成大小相等的行:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ806JtoIyDvl51yDiaCChYhhyGGHyXaOelZM3bEia4oOicbn25OqhAGZo9A/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<h2>Gird 网格</h2>
<p>我们上面提到,CSS Grid 在默认情况下是单列布局的,如果需要多列,可以使用 <code>grid-template-columns</code>属性:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8v3MC9HNiaogypibicm3xR51sibBxBHdb82x53QqMIyAnd69iacXUAboCCWg/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>通过传递两个值到 <code>grid-template-columns</code> - <code>25%</code>和 <code>75%</code>,将 CSS 网格算法将元素分成两列。</p>
<p>除了通过 <code>%</code>来设置子对象的宽度,还可以使用任何有效的 CSS 长度百分比值^^定义列,包括 <code>pixels</code>、 <code>rems</code>、<code>viewport units</code>等。此外,我们还可以访问一个新单位,即 <code>fr</code>单位:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8gFwgIkNBJuFDhia9vmRwkrGCDxwlEoGdTrgQR9yoXfoUia4UULT12ibOg/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p><code>fr</code>的计算类似分子与分母的计算,在例子中:</p>
<p>分母为 <code>4fr=1fr+3fr</code>,也就是我们把全部 fr 加起来则为分母的大小</p>
<p>分子为每列的 fr 大小,第一列分子为 <code>1fr</code>,第二列分子为 <code>3fr</code></p>
<p>这意味着总共有 4 个空间单位,也就是分母;第一列占用了可用空间的 1/4,而第二列占用了 3/4</p>
<p>Hold down!Hold down!信不信我反手就给你一锤子,你说的这个和百分比有啥区别?</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ88tYIHhyyUQZ0jrl4ZXhKDSkMSp3iciaJwI6PYeHCbASYJQJADjTKMZoA/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>别急别急,我们先看下面这个案例</p>
<p><strong>「尝试缩小此容器以查看差异」</strong></p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8Ql9H2WGJvymFJBAvWuUKRHeMnuNrBEdWsvw4zaticjdibppklvyrh2VQ/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>在这个案例中,我们可以发现:</p>
<pre><code>% 模式下:随着父容器的缩放,当子容器分配到的空间过小时,🍎的容器会被挤压
fr 模式下:即使父容器宽度再小,🍎的容器都不会被挤压,能保持正常展示
</code></pre>
<ul>
<li><code>%</code>单位的列宽是严格按照父容器大小来分配空间的</li>
<li><code>fr</code> 单位的列宽是灵活的,该列会基于父容器大小分配空间,但不会缩小到低于其最小内容的大小</li>
</ul>
<p>除此之外,当我们使用 <code>gap</code>属性时,<code>%</code>和 <code>fr</code>也会有表现差异</p>
<blockquote>
<p>gap 是什么属性?</p>
<p>gap 可以为网格中的所有列和行之间添加固定的空间</p>
</blockquote>
<p>当我们添加 <code>gap</code>时,试试百分比和分数之间切换时会有哪些差异:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8YnfTDmr2POHcNv3PTzU3doOdl3HNd4ItgqLQqbb9bO7zYA9j1rShsA/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>可以发现,使用 <code>%</code>时,子容器溢出了父容器之外,前面我说过:<code>%单位的列宽是严格按照父容器大小来分配空间的</code></p>
<p>因此使用 <code>%</code>单位时,在分配空间前:先是根父容器区域的大小计算出了子容器的大小,当我们添加 16px 的 <code>gap</code>时,空间不够用只能溢出父容器</p>
<p>而使用 <code>fr</code>单位,则是先减去 <code>gap</code>的大小,再将剩余的空间分配给其他网格列</p>
<h3>隐式和显式行</h3>
<p>当我们设置父容器 <code>grid-template-columns: 1fr 3fr;</code>,而子容器超过两个时,效果是怎么样的?</p>
<p>我们来试试</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8IyGVFZhcg2X1sL9ciayfy1NomMDibC94beyW6In17Qr2fPeJdR3x2xwA/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>嘿!和我们想要的预期效果一样,真的给我们换行去了,我们就是需要这么灵活的效果</p>
<p>除此之外,我们还可以显式地分配行的空间大小,可以使用 <code>grid-template-rows</code>属性来实现:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8FRk12ZVnI4w7Ymu6stiaqWxyyibR6qB8CwfkOM4qRB6kMxPriaZQ2nebQ/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>通过定义 <code>grid-template-rows</code>和 <code>grid-template-columns</code>,我们可以自由的分配行和列的空间大小</p>
<h3>repeat 实现重复分配</h3>
<p>假设我们要实现一个日历的效果</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8lNicoU1aETYjDD07F25T3W7Fc02dJJYF6qTkwZjgTpeSIOL64FgvGbg/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>经过上面的学习,我们想实现这样的布局并不难:</p>
<pre><code>.calendar {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}
</code></pre>
<p>吓死宝宝了,还好只是 7 列!</p>
<p>😈老板:不行,我现在要求 50 列、100 列的效果都做一遍,方便我对比效果,再决定选哪种方案</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8icMpQmuAN0UiabVpZZncia9JdQWWzD5V9NibqGib8JtDOF1ia0uPibAREKZfg/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>幸好!!Grid 的设计者考虑到了这个问题,我们可以通过 <code>repeat</code>来解决这个问题</p>
<pre><code>.calendar {
display: grid;
grid-template-columns: repeat(7, 1fr);
}
</code></pre>
<p>完整代码如下:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8NC9yKib5nBRh3qqsjmLeiaZAkvFudVAl9wSBTHo8XYIwao6Y8LibSct2Q/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<h2>子项分配</h2>
<p>相信大家都见过在地板上铺瓷砖</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ82HDaT0aw9wOHyID0XQVRFspMBhOQhuZcVWA3G06NpxlOfZqPtwO0Bw/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>今天,我们来开始学习如何铺瓷砖,以便我们在后期买房子的时候可以快速上手,🤬@#$%^&!</p>
<p>方向走错了,言归正传,<code>CSS Grid</code> 算法和铺地砖的方式十分相似:<code>将每个子项分配给第一个未占用的网格单元</code></p>
<p>不过,这里有一件很酷的事情:我们可以将我们的项目分配给我们想要的任何单元格!子级甚至可以跨越多行 / 多列。</p>
<p>下面是一个演示程序,展示了其工作原理。单击 / 按住并拖动以将子项放置在网格中</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8rrCsvISzJX64AMLiaZOIUBI8X6riasIEU53E59G1e5zPeGNAicIDUUibBQ/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>Grid 允许我们指定子对象应该占据哪些网格:<code>grid-row</code> 、<code>grid-column</code></p>
<p>如果我们希望子项占据单行或单列,我们可以通过其编号来指定它。将子项设置为位于第三列。<code>grid-column: 3</code></p>
<p>网格子项还可以跨多个行 / 列拉伸。此语法使用斜杠来描述 start 和 end:</p>
<pre><code>.child {
grid-column: 1 / 4;
}
</code></pre>
<p>乍一看,这看起来像一个分数,1/4。但是,在 CSS 中,斜杠字符不用于除法,而是用于分隔值组。在这种情况下,它允许我们在单个声明中设置 start 和 end 列。</p>
<p>它本质上是下面的简写:</p>
<pre><code>.child {
grid-column-start: 1;
grid-column-end: 4;
}
</code></pre>
<p><strong>「这里有个容易误导的理解:」</strong> 我们提供的数字基于列_行_,而不是列索引。</p>
<p>用下面的图片来理解最容易的:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8HL3KdWJoq07rOiapy0BzXROM77yFWOxf0iao20E3ExYMng9CaoY1TsPA/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>一个 4 列网格实际上有 5 列线。当我们为网格分配子项时,我们使用这些线来锚定它们。如果我们希望我们的子项跨越前 3 列,它需要从第 1 行开始,到第 4 行结束。</p>
<p>在像英语这样的从左到右的语言中,我们从左到右计算列数。然而,对于负行号,我们也可以按_相反_的方向从右到左计数。</p>
<pre><code>.child {
/* 右边第二列 */
grid-column: -2;
}
</code></pre>
<p>我们还可以混合正数和负数</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ80bib9FFPwV9QrhkcIuPMX2P3OTUOTDuyR6c7GN0SzMmIBxDfv4ibQHibA/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>请注意,子项跨越了 grid 的整个宽度,即使我们根本没有更改 <code>grid-column</code> 分配!</p>
<h3>网格区域</h3>
<p>终于要讲到 Gird 网格最牛逼的部分之一了😎</p>
<p>下面这张图片,展示了我们在网站建设中最常见的布局</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ879niaRazfrbsB91O4OnfKORg4VoZR5U23E6rthoBQVLpx7QWxricA4GQ/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>使用我们目前所学到的知识,我们可以像这样构建它:</p>
<pre><code>.grid {
display: grid;
grid-template-columns: 2fr 5fr;
grid-template-rows: 50px 1fr;
}
.sidebar {
grid-column: 1;
grid-row: 1 / 3;
}
.header {
grid-column: 2;
grid-row: 1;
}
.main {
grid-column: 2;
grid-row: 2;
}
</code></pre>
<p>这实现还不够完美,有一种更符合人体工程学的方法:网格区域。</p>
<p>这是它的样子:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8TkpLnB18ViavfuiacSe0HLCXbRpB820TB9RZWWFOrsuaypubcKjhww0g/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>和以前一样,我们使用 <code>grid-template-columns</code> 和 <code>grid-template-rows</code> 定义网格结构。但是,我们有了这个奇怪的声明:</p>
<pre><code>.parent {
grid-template-areas:
'sidebar header'
'sidebar main';
}
</code></pre>
<p><strong>「以下是其工作原理:」</strong> 我们正在绘制我们想要创建的网格,然后我们给每块网格划分区域并且命名</p>
<p>然后,我们不是给子节点分配 <code>grid-column</code> 和 <code>grid-row</code>,而是给它分配 <code>grid-area</code>!</p>
<p>当我们希望某个特定区域跨越多行或多列时,我们可以在模板中重复该区域的名称。在此示例中,“sidebar” 区域跨越两行,因此我们在第一列中为两个单元格编写 <code>sidebar</code>。</p>
<p><strong>「我们应该使用区域还是行 / 列?」</strong> 在构建这样的显式布局时,我真的很喜欢使用 areas。它允许我为我的网格分配赋予语义含义,而不是使用高深莫测的行 / 列数字。也就是说,当网格具有固定数量的行和列时,区域效果最佳。<code>grid-column</code> 和 <code>grid-row</code> 对于隐式网格很有用。</p>
<h3>键盘 Tab 问题</h3>
<p>当涉及到网格分配时,有一个很大的问题: <strong>「Tab 键顺序仍然基于 DOM 位置, 而不是网格位置。」</strong></p>
<p>用一个例子来解释会更容易。在下面的程序中,我设置了一组按钮,并使用 CSS Grid 对它们进行了排列:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_gif/lCQLg02gtibujdoiadhjqppgW58OaWVYQ82p5t0ibZgCjPuJPhaaaoHI1COxiaSsqh85kmTgcibIsh8YEk73gOUIDaQ/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1" alt="图片" /></p>
<p>在运行程序中,按钮似乎按顺序排列。通过从左到右、从上到下阅读,我们从 1 到 6。</p>
<p><strong>「如果使用的是带键盘的设备,请尝试按 Tab 键浏览这些按钮。」</strong> 可以通过单击左上角的第一个按钮(“One”)来执行此操作,然后按 <code>Tab</code> 一次移动一个按钮。</p>
<p>应该看到如下内容:</p>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/mmbiz_jpg/lCQLg02gtibujdoiadhjqppgW58OaWVYQ8ic8I0FbXkvVGrQUQsnRCGHbCkeCn5QnljpRwQFZupM7Erf5HQ6ibpI6A/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片" /></p>
<p>从用户的角度来看,焦点轮廓在页面上跳来跳去,没有韵律或理由。发生这种情况是因为按钮是根据它们在 DOM 中的显示顺序来聚焦的。</p>
<p>为了解决这个问题,我们应该在 DOM 中对网格子项重新排序,以便它们与视觉顺序相匹配,这样我就可以从左到右、从上到下使用 Tab 键。</p>
<blockquote>
<p><code>reading-order</code> CSS 属性</p>
<p>CSS 工作组意识到这是 CSS Grid 的一个缺陷。必须将 DOM 顺序与视觉顺序匹配,这与能够将子项分配给特定网格单元格的目的相悖!</p>
<p>修复工作正在进行中。将来,<code>reading-order</code> CSS 属性应该允许我们指示浏览器忽略 DOM 顺序,并按照元素在屏幕上出现的顺序聚焦元素。</p>
<p>遗憾的是,截至 2024 年 9 月,此属性尚未在任何浏览器中实现。</p>
</blockquote>
页:
[1]