引言
我一直都用了Bootstrap和jQuery来开发WordPress,直到2021年了,总觉得jQuery这种东西应该被移除了吧,于是开始考虑自己实现了一些常用的jQuery命令,如add/removeClass、slideUp/Down、事件代理等等。后来一想,既然jQuery都移除了,那么Bootstrap是不是也可以移除了?毕竟只用它的栅格系统来布局而已。于是萌生了自己编写一个布局系统的想法。
网络上有很多人也在列举“你不需要基于 CSS Grid 的栅格布局系统”的理由,也有人发表“传统写法无法发挥 CSS Grid 的全部优势,至少用以往的组合类方式是无法做到的”观点。确实,Grid的Area命名这一块纯CSS很难做到,但如果我只是为了移除Bootstrap而选择一种更先进的布局系统的话,那也是完全可以有的。
本文描述了使用SASS预处理器实现Grid布局CSS框架的一种思路,并不是讲解Grid布局如何使用的教程,如果你还不知道Grid是布局是什么,请阅读《MDN:CSS Grid Layout》
解决的问题
之所以我想要在开发WordPress的时候移除Bootstrap,还是因为它对“列”的设置太死板了。Bootstrap每行可以排列12、6、4、3、2、1个元素,然而在实际应用中,4个会太少,6个会太多,偏偏想要每行排列5个怎么办?
这个问题在flex布局也是一样的存在,都需要重新计算宽度。然而在Grid中就简单多了,只要设置 grid-template-columns 就可以了。
想要的效果
开发前,我通常会反向思考,如果有这么一个框架,它怎么用起来方便?然后再根据使用的方式去开发。
基础效果
根据上面提到想要解决的问题,因此我希望使用的方法是这样的:
-
在包裹器上设置列数(cols-n)
-
内部的元素上设置元素宽度(col-n)
<!-- 包裹器设置共6列 -->
<div class="cols-6">
<!-- 占1列宽度 -->
<div class="col-1">列元素</div>
<!-- 占2列宽度 -->
<div class="col-2">列元素</div>
<!-- 占3列宽度 -->
<div class="col-3">列元素</div>
</div>
<div class="cols-8">
<!-- 从轨道2~轨道4均为该列 -->
<div class="col-start-2 col-end-4">列元素</div>
<!-- 从轨道6~轨道7均为该列 -->
<div class="col-start-6 col-end-7">列元素</div>
</div>
响应式支持
Bootstrap的响应式写法是 col-md-6 这样把响应点写在中间的方式,经常在看代码的时候会看得眼花缭乱,于是我在实现Grid布局的时候就考虑把它提到前面来做
Bootstrap方式 | 我想要的方式 |
---|
col-sm-7 | sm:col-7 |
col-md-6 | md:col-6 |
<!-- 包裹器默认6列,md及以上显示8列 -->
<div class="cols-6 md:cols-8">
<div class="col-1">列元素</div>
<div class="col-2">列元素</div>
<!-- 默认3个列宽度,md及以上占4个列宽度 -->
<div class="col-3 md:col-2">列元素</div>
</div>
那么开始吧
由于我们有响应式,首先我们先创建一个Array来存放所有的样式,方便最后根据响应式分界点编译
$gridCSS:();
包裹器设置总列数
考虑使用“cols-n”的方式来标记包裹器的列,考虑最多允许12列此处使用grid-template-columns属性
$gridCSS: join($gridCSS, (cols-0: (display:grid, grid-template-columns: none)) );
@each $item in (1,2,3,4,5,6,7,8,9,10,11,12) {
$gridCSS: join($gridCSS, (cols-#{$item}: (display:grid, grid-template-columns:"repeat(#{$item}, 1fr)")) );
}
包裹器设置间距
在Grid中间距是用gap来实现的,为了方便,我考虑用“g-n”的方式来标记此处使用 gap 属性:
-
四周间距标记:g-n
-
水平间距标记:gx-n
-
垂直间距标记:gy-n
* 间距默认有0~50的整十像素
@each $item in (0,10,20,30,40,50) {
$gridCSS: join($gridCSS, (g-#{$item}: (gap:"#{$item}px")) );
$gridCSS: join($gridCSS, (gx-#{$item}: (column-gap:"#{$item}px")) );
$gridCSS: join($gridCSS, (gy-#{$item}: (row-gap:"#{$item}px")) );
}
子元素设置占用列宽
和包裹器设置总列数类似,子元素最多允许12列此处使用“col-n”来标记它
@each $item in (1,2,3,4,5,6,7,8,9,10,11,12) {
$gridCSS: join($gridCSS, (col-#{$item}: (grid-column:"span #{$item} / span #{$item}")) );
}
子元素设置起止轨道
子元素除了使用上面的 col-n 来标记列宽外,还可以设置起止轨道来定义宽度并且还能定义位置。此处我们使用下面标记来定义它
-
列起始轨道:col-start-n
-
列终止轨道:col-end-n
-
行起始轨道:row-start-n
-
行终止轨道:row-end-n
@each $item in (1,2,3,4,5,6,7,8,9,10,11,12,13) {
$gridCSS: join($gridCSS, (col-start-#{$item}: (grid-column-start:#{$item})) );
$gridCSS: join($gridCSS, (col-end-#{$item}: (grid-column-end:#{$item})) );
$gridCSS: join($gridCSS, (row-start-#{$item}: (grid-row-start:#{$item})) );
$gridCSS: join($gridCSS, (row-end-#{$item}: (grid-row-end:#{$item})) );
}
至此,Grid基本的内容就设置好了。我们把刚才定义的 $gridCSS
渲染出来
@each $className, $classStyle in $gridCSS {
.#{$className} {
@each $styleKey, $styleVal in $classStyle {
@each $val in $styleVal {
#{$styleKey} : #{$val}
}
}
}
}
响应式
设置定义响应分界点,并基于分界点生成媒体查询
$breakpoints: (576px,768px,992px,1200px);
$medias: (
"xxs": "(max-width: #{nth($breakpoints,1) - 1px})",
"xs": "(min-width: #{nth($breakpoints,1)})",
"sm": "(min-width: #{nth($breakpoints,2)})",
"md": "(min-width: #{nth($breakpoints,3)})",
"lg": "(min-width: #{nth($breakpoints,4)})"
);
渲染出响应式媒体查询部分,顺手把container也加上吧,更方便使用
.container {
width: 100%;
margin-left: auto;
margin-right: auto;
}
$mediaIndex: 1;
@each $mediaName, $mediaRange in $medias {
@media #{$mediaRange} {
@each $className, $classStyle in $gridCSS {
.#{$mediaName}\:#{$className} {
@each $styleKey, $styleVal in $classStyle {
@each $val in $styleVal {
#{$styleKey} : #{$val}
}
}
}
}
@if ($mediaIndex >= 2){
.container {
max-width: #{nth($breakpoints, $mediaIndex - 1)}
}
}
}
$mediaIndex: $mediaIndex + 1;
}
至此,一个简单的Grid布局就基本完成了。本文提供了一个基本的Grid布局实现思路,还可以在此基础上扩展成自己更顺手的工具。
如何使用
例如:要生成一个7列的布局,子元素之间间隔30像素;第一个子元素占用3列,第二个子元素占用剩下的全部。并且在手机屏幕上,它们都水平排列。就可以这样写:
<div class="container cols-7 g-30">
<div class="col-7 sm:col-3">第一个子元素</div>
<div class="col-7 sm:col-4">第二个子元素</div>
</div>
下载?
本文并没有提供任何下载,前面的代码示例已经将SASS代码的步骤全部展示出来了,你只需要根据自己的使用习惯手动编译一遍(或直接编译)就可以使用了,这里做了个Codepen示例: