原文连接
一.如何构建自己的栅格系统
- grid design
- how your grid behaves at different viewports
- whether to use HTML OR CSS grid systems
1.building your grid system
8步建立自己的栅格系统:
- 选择一个栅格系统规范: css grid, Flextbox, 还是floats
- 设置
box-sizing
为border-box
- 创建 grid container
- 计算 column-width(列宽)
- 决定 gutter(间隔) 位置
- 创建debug grid
- 制作布局差异(make layout variations)
- 使布局变得响应式
二.具体步骤
对应上面的8条
1.选择规范
CSS Grid最好用,但是浏览器的支持太差,选择使用Flexbox或者Floats。 flexbox和floats之间其实差异很小,下面为了通常情况,选择floats来布局。
2.设置box-sizing
box-sizing有3种: content-box, padding-box, border-box, 设置为border-box是最常用的, 设置方法如下
html {
box-sizing: border-box
}
*,
*:before,
*:after {
box-sizing: border-box
}
3. 设置栅格容器
每个栅格都有一个容器来决定栅格的最大宽度,一般可以命名为 .l-wrap
, 使用 .l
表示 layout, 这种命名规范称之为 SMACSS.
设置如下:
.l-wrap {
max-width: 1140px;
margin-right: auto;
margin-left: auto;
}
强烈推荐使用 em
| rem
这样的相对单位,对于响应式布局可以增强可访问性和响应能力, 下面例子为了简洁,还是会使用pixels作为单位。
4.计算列宽
我们上面说过使用 floats 来布局,创建列(columns) 和 列间距(gutter)我们由使用下面5个属性(使用flexbox则属性更多一点):
- width
- margin-right
- margin-left
- padding-right
- padding-left
通过上面的介绍,可以大致写出如下html(使用Jade):
.l-wrap
.three-col-grid
.grid-item Grid item 1
.grid-item Grid item 2
.grid-item Grid item 3
从这个html,我们可以知道一行总共有3列,并且没有额外的div用来充当gutters,这意味着:
- 我们列通过
width
属性 - 我们通过
margin
或者padding
属性来创建列间距
如果我们同时考虑columns 和 gutters 会使情况变得复杂,我们先假设没有列间距的情况。
我们知道整个栅格最大宽度为1140px,这也意味着3个小栅格每个宽度为 1140px/3=380px
.three-col-grid .grid-item {
width: 380px;
float: left;
}
当我们在浏览器中改变浏览器大小时,发现视窗小于1140px时,栅格会重新占据下一行,这不是我们想要的,所以我们不能使用 px 当作单位,所以我们改用百分比来当作单位:
.three-col-grid .grid-item {
width: 33.33333%;
float: left;
}
有一点要注意的是: 当一个容器中的所有子元素都是浮动的时候,容器的高度会坍塌(height collapses), 这个现象称之为 float collapse
。就好像这个容器没有包含元素一样。所以我们要清除浮动
.three-col-grid:after {
display: table;
clear: both;
content: '';
}
如果使用sass的话:
@mixin clearfix {
&:after {
display: table
clear: both;
content: '';
}
}
// 使用
.three-col-grid {@include clearfix}
// sass表示
@mixin clearfix
&:after
display: table
clear: both
content: ''
.three-col-grid
+clearfix
5.决定列间距的位置
上面我们可以知道,可以使用 margin 或者 padding 来创建列间距,有4种情况:
- 使用margins,间距放在同一边
- 使用padding, 间距放在同一边
- 使用margins, 间距等分的放在2边
- 使用paddings, 间距等分的放在2边
从这开始事情将变得复杂,你需要计算列宽依据你选择上面的哪一种方式。
方法1:one-sided gutters(using margin)
这个方法使用margin属性,这个间距放在右边或者左边,由你决定。我们假设放在右边:
.grid-item {
/* 需要重新计算width 属性 */
margin-right: 20px;
float: left;
}
这里有个问题,就是列宽我们使用的是百分比, 而margin使用的是pixels,单位不一致,我们不能同时进行计算。
这在以前是不能计算的,现在我们可以使用CSS 提供的 calc
函数(注意不支持IE8-和opera mini) 来混合计算不同的单位,浏览器会自动帮助我们计算最后渲染出来的宽度值。
.grid-item {
width: calu((100% - 20px * 2) / 3);
/* 其他属性 */
}
最后我们需要移除最右边的grid item 的 margin-right
.grid-item:last-child {
margin-right: 0;
}
大多时候,移除最右边盒子的外边距的同时,一般需要将 float 设置为 right,这样可以阻止浏览器给盒子添加的子像素,导致盒子移动到下一行的情况,即:
.grid-item:last-child {
margin-right: 0;
float: right;
}
这样对一行的情况已经OK了,对于多行的情况,我们需要移除每一行最右边的盒子的外边距,可以使用 nth-child()
:
.grid-item:nth-child(3n+3) {
margin-right: 0;
float: right;
}
方法2:one-sided gutters(using paddings)
和方法1一样,这个方法将列间距放在列的一边。假设放在右边:
.grid-item {
/* 宽度属性 */
padding-right: 20px;
float: left;
}
发现宽度和方法1中的不同了吗?因为我们将box-sizing
设置为了 'border-box', 现在宽度计算包括padding值。
这种情况,3列中的2列快读要大于最后一列的宽度,这样会导致怪异的CSS计算情况出现,建议永远不要尝试这种方法,可能出现很丑的界面。
方法3:split gutters(using margin)
这个方法将列间距放在列的两边,这样代码看起来像这样:
.grid-item {
/* 宽度属性 */
margin-right: 10px;
margin-left: 10px;
float: left;
}
利用 calc()
计算列宽:
.grid-item {
/* 注意这里列宽要比第一种情况小 */
width: calc((100% - 20px * 3) / 3);
margin-right: 10px;
margin-left: 10px;
float: left;
}
这样就可以了,没有其余的步骤需要去做了,多行也是一样,也不用特意设置很行最后一个盒子的样式了
方法4: split gutters(using padding)
这个方法和方法3差不多,但是宽度计算更简单了,因为padding值直接包含在盒子里面:
.grid-item {
width: 33.3333%;
padding-right: 10px;
padding-left: 10px;
float: left;
}
注意使用这个方法,需要在.grid-item
里面在添加一层div,使得2盒子之间的界限更加的清晰,即:
.l-wrap
.three-col-grid
// 需要多添加一层div.grid-inner
// 使得各个grid-item之间的间隙更加的明显
.grid-item: .grid-inner Grid item
.grid-item: .grid-inner Grid item
.grid-item: .grid-inner Grid item
.grid-item: .grid-inner Grid item
.grid-item: .grid-inner Grid item
.grid-item: .grid-inner Grid item
查看codepen代码
选择哪一种方法?
如果要选的话,我会选择列间距放两边而不是把列间距放一边的方法, 因为这样CSS更简单。另外更偏向于使用margin作为列间距,因为代码会更加的干净, 即方法3最为理想。但是方法4使用padding计算更加简单,下面会使用padding来作介绍。
6.创建调试栅格
当开始创建栅格时,创建一个控制栅格用于调试对于布局帮助很大,这样可以帮助你正确的创建栅格。
目前只有一个蹩脚的调试栅格,就是创建HTML元素,添加一些CSS。codepen
HTML:
.l-wrap
.fixed-gutter-grid
.column
.column
.column
.column
.column
.column
.column
.column
.column
.column
.column
.column
CSS(使用margins分开式列间距,即上面的方法3):
.l-wrap {
max-width: 1140px;
margin-right: auto;
margin-left: atuo;
}
.column {
width: calc((100% - 20px * 12) / 12);
height: 80px;
margin-left: 10px;
margin-right: 10px;
background: rgba(0, 0, 255, 0.25);
float: left;
}
7.创建布局变形
下一步就是根据内容创建布局变形,这也正是栅格系统最耀眼的地方。可以创建给布局一个合理的名字,而不必要写多个栅格class。
例如,加入你有个栅格系统只用于guest articles,这个布局分布为 2-7-3
,这个guest-article 布局为:
.l-guest-article
.l-guest.grid-item: .grid-inner item 1
.l-main.grid-item: .grid-inner item 2
.l-sidebar.grid-item: .grid-inner item 3
每列宽度为 100% / 12 = 8.333%, 因此.l-guest
为 8.333% * 2, 其余栅格依次求出宽度, 可以使用预处理语言(不如sass) 的percentage
函数来代替手动计算
即:
.l-grid-article
+clearfix
.l-guest
width: percentage(2/12)
.grid-inner
background-color: pink
.l-main
width: percentage(7/12)
.grid-inner
background-color: yellow
.l-sidebar
width: percentage(3/12)
.grid-inner
background-color: blue
// 将共同部分提取出来
.grid-item
padding-right: 10px
padding-left: 10px
float: left
.grid-inner
display: flex
justify-content: center
align-items: center
height: 80px
text-align: center
栅格系统变种codepen
8.使布局变得响应式
最后一步就是让布局变得响应式, 可以根据下图方法:
可以看出l-guest-articlehtml标记不改变,完全由CSS来控制布局, 当使用CSS来做响应式布局时,强烈建议移动优先原则,这样写的代码更加的简洁
1.移动布局:
.l-guest-article
.l-guest /* 这里什么都不用写*/
.l-main
margin-top: 20px
.l-side-bar
margin-top: 20px
我们什么也不用做,因为组件默认的会占满父元素宽度,我们可以给上下盒子之间添加一些外边距
2.平板布局:
对于这种布局,假定我们的临界点(breakpoint)为700px.
-
.l-guest
占据 4/12 -
.l-main
和.l-sidebar
占据8/12
我们应当将 .l-main 中的 margin-top
移除, 因为它和 .l-guest在同一行。
另外如果我们设置 .l-sidebar为8列,它会自动在第2行上,因为第1行没有多余的空间了。我们可以使用 margin-right
或者 float: right
让它在右边。
如下(别忘记容器清除浮动):
.l-guest-article
+clearfix
.l-guest
@media(min-width: 700px)
width: percentage(4/12)
float: left
.l-main
margin-top: 20px
@media(min-width: 700px)
width: percentage(8/12)
margin-top: 0
float: left
.l-sidebar
margin-top: 20px
@media(min-width: 700px)
width: percentage(8/12)
float: right
3.桌面布局
假设临界点为1200px,这个和前面介绍的布局方式一致,为 2-7-3
值得注意的是,别忘记移除 .l-sidebar
的 margin-top
.l-guest-article
+clearfix
.l-guest
@media (min-width: 700px)
width: percentage(4/12)
float: left
@media (min--width: 1200px)
width: percentage(2/12)
.l-main
margin-top: 20px
@media (min-width: 700px)
width: percentage(8/12)
margin-top: 0
float: left
@media (min-width: 1200px)
width: percentage(7/12)
.l-sidebar
margin-top: 20px
@media (min-width: 700px)
width: percentage(8/12)
float: right
@media (min-width: 1200px)
width: percentage(3/12)
margin-top: 0
具体效果 响应式设计
总结
通过这篇文章,我们学习了如何自定义栅格系统,以float作为布局规则,主要有以下几个知识点:
- 设置box-sizing,容器宽度使用
max-width
- 使用 calc() 函数计算列宽(注意IE8-不能使用)
- 常见的4种列间距的使用方法,最常用的就是使用margin平分列间距
- 使用sass的辅助函数
percentage
来进行宽度计算 - 使用
media query
实现响应式布局 - 注意使用浮动时,注意清除浮动
- 当然还有捎带提及了SMACSS命名方法