#1 自定义栅格系统&响应式布局

原文连接

一.如何构建自己的栅格系统

  1. grid design
  2. how your grid behaves at different viewports
  3. whether to use HTML OR CSS grid systems

1.building your grid system

8步建立自己的栅格系统:

  1. 选择一个栅格系统规范: css grid, Flextbox, 还是floats
  2. 设置 box-sizingborder-box
  3. 创建 grid container
  4. 计算 column-width(列宽)
  5. 决定 gutter(间隔) 位置
  6. 创建debug grid
  7. 制作布局差异(make layout variations)
  8. 使布局变得响应式

二.具体步骤

对应上面的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。就好像这个容器没有包含元素一样。所以我们要清除浮动

#1 自定义栅格系统&响应式布局_第1张图片
.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属性,这个间距放在右边或者左边,由你决定。我们假设放在右边:

#1 自定义栅格系统&响应式布局_第2张图片
.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,这样可以阻止浏览器给盒子添加的子像素,导致盒子移动到下一行的情况,即:

#1 自定义栅格系统&响应式布局_第3张图片
.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一样,这个方法将列间距放在列的一边。假设放在右边:


#1 自定义栅格系统&响应式布局_第4张图片
.grid-item {
    /* 宽度属性 */
    padding-right: 20px;
    float: left;
}

发现宽度和方法1中的不同了吗?因为我们将box-sizing设置为了 'border-box', 现在宽度计算包括padding值。

这种情况,3列中的2列快读要大于最后一列的宽度,这样会导致怪异的CSS计算情况出现,建议永远不要尝试这种方法,可能出现很丑的界面

方法3:split gutters(using margin)

这个方法将列间距放在列的两边,这样代码看起来像这样:

#1 自定义栅格系统&响应式布局_第5张图片
.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值直接包含在盒子里面:

#1 自定义栅格系统&响应式布局_第6张图片
.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-sidebarmargin-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作为布局规则,主要有以下几个知识点:

  1. 设置box-sizing,容器宽度使用 max-width
  2. 使用 calc() 函数计算列宽(注意IE8-不能使用)
  3. 常见的4种列间距的使用方法,最常用的就是使用margin平分列间距
  4. 使用sass的辅助函数 percentage 来进行宽度计算
  5. 使用 media query 实现响应式布局
  6. 注意使用浮动时,注意清除浮动
  7. 当然还有捎带提及了SMACSS命名方法

你可能感兴趣的:(#1 自定义栅格系统&响应式布局)