前端开发者学堂 - fedev.cn

CSS变量创建网格系统

发布于 大漠

今天要聊的网格系统不是CSS Grid Layout,而要聊的是类似960gs。到止前为止类似于960gs的网格系统成熟的系统有很多套了。

实现Grid系统的方案

如果忽略CSS Grid Layout特性,所讲的Grid系统都是源自于960gs。而实现这种网格系统所用的方案至今天而言主要实现方式有:

  • 固定网格系统
  • 流式网格系统

固定网格系统:固定网格系统所说的就是网格的列宽、列数、列间距都是固定的值,比如使用的是px值。

流式网格系统:流式(也称之为自适应网格系统),也就是网格的列宽,列间距都是使用的百分比,而列数是固定的值,最常见的和固定网格一样,是12列。但一般情况,流式网格系统都会给网格容器设置一个最大宽度(max-width)。

而实现网格系统的方法目前为之最为常见的是使用float或者flexbox两种。其中先进的一点的是采用CSS处理器来实现。

计算Grid系统的公式

这里所说的网格系统,共实现具有一定的数学公式:

scw = (100 – (m * (mc – 1))) / mc

其对应描述如下:

  • scw:指的是单列宽度
  • m:指的是列间距
  • mc:最大列数(一般是12

根据上面的公式,可以转换出计算其他列的列宽的公式:

cw = (scw * cs) + (m * (cs – 1))
  • cw:列宽度
  • scw:单列宽度
  • cs:列数(1~12)
  • m:列间距

根据上述公式,不难算出网格的各参数值。下面来看两种网格计算方式,以及其得到的相关参数值。

固定网格系统

假设网格系统总共列数为12列,列间距为20px(也就是padding-leftpadding-right各为10px,当然也可以是单方面的,比如padding-left或者padding-right),网格容器的宽度为1180px。根据上述公式和相关的网格参数,可以计算出各列的宽度:

每列宽度:

scw = (100 – (m * (mc – 1))) / mc
/*
 * 网格容器总宽度 1180
 * 网格间距m = 20
 * 网格列数mc = 12
 */
scw = (1180 - (20 * (12 - 1))) / 12
scw = (1180 - 20 * 11) / 12
scw = (1180 - 220) / 12
scw = 960 / 12
scw = 80

再根据:

cw = (scw * cs) + (m * (cs – 1))

可以计算出每列的宽度

  • cw = ?
  • scw = 80
  • cs = 1 ~ 12
  • m = 20

如此来可以计算出:

cs = 1 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 1 + 20 * (1 - 1) = 80
cs = 2 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 2 + 20 * (2 - 1) = 180
cs = 3 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 3 + 20 * (3 - 1) = 280
cs = 4 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 4 + 20 * (4 - 1) = 380
cs = 5 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 5 + 20 * (5 - 1) = 480
cs = 6 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 6 + 20 * (6 - 1) = 580
cs = 7 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 7 + 20 * (7 - 1) = 680
cs = 8 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 8 + 20 * (8 - 1) = 780
cs = 9 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 9 + 20 * (9 - 1) = 880
cs = 10 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 10 + 20 * (10 - 1) = 980
cs = 11 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 11 + 20 * (11 - 1) = 1080
cs = 12 => cw = (scw * cs) + (m * (cs – 1)) = 80 * 12 + 20 * (12 - 1) = 1180

根据上述公式,配合Sass可以得到各列的宽度:

[class*="m--"]{ 
    padding-right: $gutter;
    padding-left: $gutter;
    @for $i from 1 through 12 {
        &.m--#{$i} {
            width: (80 * $i + 20 * ($i - 1)) * 1px;
        }
    }
}

流式网格系统

流式网格系统也称之为自适应网格系统,目前众多网格系统采用的都是流式网格系统,根据固定网格系统中所采用的计算公式,很容易计算出各列的列宽。

scw = (100 – (m * (mc – 1))) / mc
  • scw = 单列宽度
  • m = margin (1.6%)
  • mc = 列数 (12)

假设单列列宽为6.86666666667%,根据对应的计算公式:

cw = (scw * cs) + (m * (cs – 1))
  • cw = 列宽
  • scw = 单列宽度 (6.86666666667%)
  • cs = 列数 (1-12)
  • m = margin (1.6%)

上面看到的示例采用的布局方式是Flexbox方式。当然,古老一点的,采用的是浮动布局多。在这篇文章咱位就不做这方面的阐述。

当然,更为强大的一些的网格布局(目前一些主流的网格系统),都使用了媒体查询,对网格系统做了一些响应式的设计。让网格在不同的断点效果都比较完美,如果你对这方面的网格框系统感兴趣的话,可以查阅相关的代码。

CSS变量创建网格系统

如果你耐心的把文章看到这里,可以说你对网格系统的制作有了一定的了解。那么从这里开始,我们回到今天文章的主题部分:CSS变量创建网格系统

在介绍CSS变量制作网格系统之前,先简单的了解一下CSS的变量相关的内容。CSS变量又称之为CSS自定义属性,在CSS中通过下面这样的方式来声明CSS变量:

:root{
    --color: #0C3934;
    --bg: #F8EBEE;
    --gutter: 10px;
    --columns: 12;
}

然后通过下面的方式来调用CSS声明的变量:

.m--1 {
  --column-width: 1;
}

这里简单的介绍了如何声明CSS的变量和调用已声明的CSS变量。如果你对这方面感兴趣,可以先阅读《深入学习CSS自定义属性(CSS变量)》一文。

到此,你对CSS自定义变量有了一定的了解,接下来看如何通过CSS变量来制作一个CSS网格系统。根据前面介绍的网格制作原理,可以先定义相关的网格参数,当然用CSS的变量来定义:

:root{
    --color: #0C3934;
    --bg: #F8EBEE;

    /* Grid */
    --gutter: 10px; /*列间距*/
    --columns: 12; /*列数*/
}

对于网格的基本布局,同样可以通过Flexbox布局来实现:

.container {
    max-width: 1140px;
    margin: 3em auto;
    padding: var(--gutter);
}

*{
    box-sizing: border-box;
}

.row{
    display: flex;
    flex-wrap: wrap;
    margin: 0 calc(var(--gutter) - ( var(--gutter) * 2) ) 20px;
}

[class*="m--"]{ 
    padding-right: calc(var(--gutter));
    padding-left: calc(var(--gutter));
    flex-basis: calc((100% / var(--columns)) * var(--column-width)); 
}

上面的代码就不做详细的介绍了。有关于这方面的使用可以阅读《深入学习CSS自定义属性(CSS变量)》一文。当然,其中还运用了CSS的calc()函数。如果你从未接触过calc()相关的内容,可以点击这里阅读

所设我们的网格是一个12列的网格,常规情况之下,都会使用.m--*(当然很多时候会使用col-*或者span-*方式),其中*表示的是网格1~12。这也不是千篇一律,如果你的网格列数不到12或者不止12列时,那么他最大的值就是表示网格最多的列数。

使用CSS变量制作网格系统,不需要像以前一样,使用那么复杂的计算公式。在CSS变量制作网格系统,可以根据网格的列数来声明网格列宽。比如我们的示例中:

.m--1 {
    --column-width: 1;/*列宽是一列*/
}
.m--2 {
    --column-width: 2;/*列宽是两列+一个列间距*/
}

以此类推,可以借助Sass的@for循环,很容易实现网格1列至12列的列宽:

[class*="m--"]{ 
    padding-right: calc(var(--gutter));
    padding-left: calc(var(--gutter));
    flex-basis: calc((100% / var(--columns)) * var(--column-width)); 
  
    @for $i from 1 through 12 {
        &.m--#{$i} {
            --column-width: $i;
        }
    }
}

最后你看到效果如下:

上面示例是通过声明列数来实现一个完美的网格系统。其实还可以通过声明列宽来制作网格系统。比如:

:root {
    --grid-width: 20%;
    --color-primary: #2980b9;
    --color-secondary: #c0392b;
    --color-accent: #16a085;
    --font-size: 18px;
}

调用的时候:

.four-cols {
    --grid-width: 25%;
}
.three-cols {
    --grid-width: 33%;
}

更详细的代码可以看下面的示例:

总结

文章从平始制作一个固定网格系统和流式网格系统着手,引入了怎么通过CSS变量制作一个网格系统。从上面的示例对比来讲,通过CSS变量制作一个网格系统,让我们变得更为简单,而且再也不需要通过复杂的数学公式来计算网格系统中每列的列宽。如果你感兴趣的话,可以自己动手尝试一下怎么使用CSS变量来制作一个网格系统。