Media Query 我觉得已经讲到快烂掉了,搭配 Grid 说实在话也没有很不好做的地方。不过,由於 Grid 是「方格系统」,所以你必须要撇开之前使用 Float Position, Flexbox 的那种流向的思维,这是比较令人苦恼的。
像是 Bootstrap 5.1.x 可以打开 Grid(预设关闭),揪竟多少人会打开呢?让我们继续看下去...
最困难的点在於数(三声)数(四声)。
我就不复习 RWD 的事情了。一开始我们先复习一下 Grid 的定义方式,
.grid-layout {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(4, 1fr);
gap: 10px;
}
由於我们上面使用了弹性单位,所以这个 Grid 在任何尺寸底下,都会弹性的保持在 4x4 的网格系统内。这样是不是很棒?
你很棒,你全家都很棒!
换句话说,网格系统在使用弹性尺寸的设定下,无论任何尺寸都会保有最小可使用空间(min-content
)的设计。这样对於排版来说未必是一件好事。举例来说,如果我今天想要在 [2, 3]
这个位置上,让当中的元件强制换行,那麽要怎麽做?
假设我们在 4x4
的位置上,都恰恰好的放一个 1x1
的方块,
// 因为我不想占版面,所以用 SCSS 写一点回圈
@for $i from 1 through 4 {
@for $j from 1 through 4 {
.box-#{(($i - 1) * 4 + $j)} {
grid-column: #{$j} / #{($j + 1)};
grid-row: #{$i} / #{($i + 1)};
}
}
}
然後我们来找一下 [2, 3]
这个位置的方块是谁,
现在我们找到 [2, 3]
的元件之後,那麽我要怎麽让他 断行 呢?你可以开始找找 Google 或是 StackOverflow 看看有没有关於 grid layout break row
之类的结果。
你现在看到的这篇应该就是最佳解,不用找了。
首先必须澄清一件事情,网格系统里面没有所谓的 断行 这件事情。你所看到或是查询到跟断行操作很类似的作法,其实是利用 Auto-placement 的特性去做的。
所以,我们重新来看一次真正需要的事情什麽?
[2, 3]
的位置发生断行的动作。[3, 3]
之後的元件应该都继续往下放。好的,首先先提醒会产生的 副作用,
min-content
来填充。实际上该怎麽操作?
// 还记得 max-width 是数值以上?还是数值以下吗?
@media screen and (max-width: 768px) {
// 对了,[3, 3] 位置是 11 号的盒子
.box-11 {
grid-column: 1 / 2;
grid-row: 4 / 5;
}
// 然後後面的 12, 13, 14, 15, 16 全部都要改
// 然後後面的 12, 13, 14, 15, 16 全部都要改
// 然後後面的 12, 13, 14, 15, 16 全部都要改
}
有没有觉得很崩溃?
现在来解释为何用 Auto-replacement 可以做到 类似 的事情,先决条件是,你的网格系统不能强迫定义每个元件的网格位置,也就是说,你必须让他自然排列或使用相对位置排列,
.box-1 {
grid-column: 1 / 1;
grid-row: 1 / 1;
}
// 只设定第一个盒子,後面都不设定。
// 以上述的例子,甚至全部都不设定也可以。
如果我们要将 [2, 3]
这个位置後面的元件都换到下一行去,
@media screen and (max-width: 768px) {
// 对了,[2, 3] 位置是 10 号的盒子
.box-11 {
grid-column: span 3;
}
}
这样你就会得到这样的结果,
这就是普遍你能找到的所谓 断行 的解法,利用 Auto-placement 的规则,加上 span
关键字来让该位置的元件产生 跨栏 的动作,这样,自然的後面的元件就会因为栏位不够用的关系,被挤到下一行去。
说真的不叫做断行,而是 被断行。以现行的格线系统来看,如果不想要很麻烦的定义每个元件的位置,那麽你也只能这样做。或是使用命名方式的 grid-template-areas
来做也不是不行。
所以我才会说这是一个数数的工作,而且很要命的是很容易数错。
那麽,有没有比较好的作法?有的,但我有个前提,这是我自己觉得比较好的作法,如果觉得不对或是不好的,就不要用就好了,请不要留言骂我~
如果没问题请继续往下看。
一般情况来说,我们不太可能将整个页面设计都使用弹性尺寸来做,除非你的客户弹性很大(像是那个什麽石墨烯的裤子),不然通常还是会有需要固定尺寸,固定位置的需求。
以上述的例子来说,我们以样使用一个 4x4
的网格容器,并且定义了几个区块,
.grid-layout {
display: grid;
grid-template-columns: 200px repeat(3, 1fr);
grid-template-rows: 80px repeat(2, 1fr) 80px;
gap: 10px;
}
.header {
grid-column: 1 / 5;
grid-row: 1 / 2;
}
.sidebar {
grid-column: 1 / 2;
grid-row: 1 / 4;
}
.main {
grid-column: 2 / 5;
grid-row: 1 / 4;
}
.footer {
grid-column: 1 / 5;
grid-row: 3 / 4;
}
这样我们就会得到像是这样的结构,
接着,我们来思考一下 Media Query 该怎麽做?如果我们需要在小装置上,把 .sidebar
放到 .main
的下方,实际上的操作方式会是什麽?
首先,请记得网格所设定的固定尺寸是不会因为你的装置变小而有所变化,也就是说,上述的设定被套用到手机上,例如 iPhone 13 的尺寸下(装置 Viewport 宽度为 390px)的情况,那麽我们可以知道整个容器的弹性空间会被压缩。
也就是说,扣掉 .sidebar
本身固定的 200px
,再扣掉 gap
的 10px
之後,你现在的 .main
就只剩下 180px
可用,这是弹性空间所计算出来的剩余尺寸。然後在手机上就会出现侧边栏位比主要栏位还要大的情况。
回到 Media Query,到底该怎麽做会比较好?
// 首先,我们以 Mobile First 为出发点(个人喜好)
.header,
.sidebar,
.main,
.footer {
grid-column: span 4;
}
// 接着做一个大尺寸的 Mediq Query
@media screen and (min-width: 768px) {
.header {
grid-column: span 4;
}
.sidebar {
grid-column: unset;
grid-row: span 2;
}
.main {
grid-column: span 3;
grid-row: span 2;
}
.footer {
grid-column: span 4;
}
}
由上面的例子,你应该可以理解到格线系统里面没有 断行 的概念,全部都是一个矩型的矩阵在排位置,你可以把他想像成一个围棋的棋盘,想像你要摆放的东西,在什麽位置(座标)上面,涵盖了多大的范围。
那麽,我们来看看一个比较复杂的例子,倘若我们的元件排列没那麽单纯,又有顺序问题的情况下,怎麽样制作 Grid 呢(或者你直接用 Flexbox 搞不好更快)?
延续上述的例子,我们想要在 .main
的上下加上广告,但是在手机上,这个广告得出现在 .sidebar
的上下方,不想将 .main
夹在广告中间。
我们先来看手机的呈现方式,
然後给大家看一下 HTML 的内容,
<div class="grid-layout">
<div class="header">Header</div>
<div class="sidebar">Sidebar</div>
<div class="main">Main</div>
<div class="ads-1">ADs 1</div>
<div class="ads-2">ADs 2</div>
<div class="footer">Footer</div>
</div>
接着我们来看一下大尺寸的呈现结果,
看起来好像很完美,但实务上的操作其实挺累人的,我再强调一次,在网格系统中没有 断行 的概念,他只有 定位 跟 排序 可以做。
在小装置上,我的 CSS 以最少的设定大概是这样,
.grid-layout {
display: grid;
grid-template-columns: 200px repeat(4, 1fr);
grid-template-rows: 80px repeat(2, 1fr 20px) 80px;
gap: 10px;
}
.header,
.sidebar,
.main,
.ad-1,
.ad-2,
.footer {
grid-column: span 5;
order: 1;
}
.main {
order: 2;
}
.ads-1 {
order: 3;
}
.sidebar {
order: 4;
}
.footer,
.ads-2 {
order: 5;
}
接着换到比较大的装置,你应该有发现连网格系统的尺寸都有略微调整了,
@media screen and (min-width: 768px) {
.grid-layout {
grid-template-rows: 80px 60px repeat(3, 1fr) 80px;
}
.sidebar {
grid-column: unset;
grid-row: span 4;
order: 2;
}
.main {
grid-column: span 4;
grid-row: span 3;
order: 4;
}
.ads-1,
.ads-2 {
grid-column: span 2;
order: 3;
}
.footer {
order: 5;
}
}
没有。都是在玩拼图。
在格线系统中,其实并不像 Flexbox 会有那麽多关於文件流要考虑的点,不能说没有,只能说是相对的少,而且要考量的点也不一样。扣除掉使用绝对定位(position: absolute
)所带来的状况以外,在先前的 Flexbox 并不需要考虑定位问题,这是相对的差异。
与其说是 Mediq Query 来做 RWD,倒不如说是利用 Media Query 然後把 整个画面换掉(重做) 的感觉。不相信的话,你可以去搜寻 css grid with media queries 之类的,然後就一堆人告诉你怎麽样用 Media Query 去换整个 Grid Layout 等等的操作。
等一下,先不要。
一般来说,把 整个画面换掉 的事情应该是属於 AWD(Adaptive Web Design)的范畴。最一开始的初衷应该是 规划出一个不会整个换掉的 Grid Layout 才是重点。
总结来说,如果要在网格系统规划 Media Query 的话,以下诚心建议:
既然都要用 Flexbox,为何不一开始就用?
虽然说 Grid 好像用起来很潮,不过要考虑的地方其实蛮多的。目前现行的诸多套件,基本上还是把他当作 类 Flexbox 来操作,但,其实没人在乎吧。
谁在乎谁痛苦。
目录与小节:
[CSS] Flex/Grid Layout Modules, part 1
部落格同步放送:
[CSS] Flex/Grid Layout Modules, part 16
<<: ISO 27001 资讯安全管理系统 【解析】(二十四)
理解js单执行绪&非同步运行机制 由於js为单执行绪,也就是一次只处理一件事情并依序执行,但...
终於要到了铁人赛的尾声了,笔者一直想在最後几篇来了解一下React,所以趁现在JavaScript应...
之前我们在范例练习React时,都是引用CDN的方式来建立开发环境,今天要介绍的是Create Re...
还记得我们前两天学的方法吗?结合昨天学的阵列,阵列也可以用在方法里传递吗? 当然可以罗!我们就先来看...
周日一堆韩国综艺要看....好忙! 上一篇Maximum Subarray解题,最後答案有稍作修改。...