Skip to content

前言

实现一个UI库都具备的栅格系统,用于快速实现一个响应式的布局,栅格系统有如下特性

  • 具备一个row容器和一系列的col单元格,当然,col单独存在时也需要能正常展示
  • 24个单元格,更加精细化的展示,同时还需要能够在单元格之间有空隙
  • 单元格除了正常的排列外还需要具备偏移和排序功能
  • 响应式布局也是必不可少的
  • 新的框架也要是一个能够利用新特性的来实现栅格的,拥抱新特性

具体实现

基于float

首先实现一个简单的row,row根据不同设备大小定义,宽度100%

less
.clearfix {
    &:after {
        content: '';
        display: block;
        clear: both;
    }
}
.row {
    .clearfix();
    width: 100%;
    box-sizing: border-box;

    @unit-count: 24;
    @unit-width: (100% / @unit-count)
    .col {
        float: left;
        box-sizing: border-box;
    }
    each(range(@unit-count), {
        .col-@{value} {
            width: (@unit-width * @value)
        }
    })
}

添加上间隔,假设间隔添加为12px,而且间隔还需要是首尾无间隔,中间的间隔相同

less
.col {
    margin-right: 12px;
    &:last-child {
        margin-right: 0;
    }
}

// 也可以按照下面写
.col {
    padding-left: 6px;
    padding-right: 6px;

    &:first-child {
        padding-left: 0;
    }
    &:last-child {
        padding-right: 0;
    }
}

栅格系统的偏移指的是在原有位置上平移,如果有重复会直接覆盖。排序会使最终的效果按照css不是html实现,我们定义通过col-offset-4 表示在原有的位置上向右偏移4个单元格。定义col-push-4表示从第四个单元格开始布局

less
.col {
    position: relative;
}
each(range(@unit-count), {
    .col-offset-@{value} {
        // 偏移的关键通过相对定位 不会影响到其他
        left: @value * @unit-width;
    }
    .col-push-@{value} {
        // 排序的关键是marigin,通过margin会影响到后面所有的
        margin-left: @value * @unit-width;
    }
})

bootstrap实现栅格系统

主要是参考bootstrap的栅格系统,bootstrap栅格系统由container、row和col组成。规定col必须包含在row中,row可以包含在container或者另一个col中。

less
@media-sizes: {
    sm: 768px
    md: 992px;
    lg: 1200px;
    xs: 1920px;
}
@media (min-width: @media-sizes[sm]) {
    // 总是在两边空出一定间隔,避免撑满
    .container {
        width: @media-sizes[sm] - 18px; // 750px;
    }
}

@media (min-width: @media-sizes[md]) {
    .container {
        width: @media-size[md] - 22px;
    }
}

@media (min-width: @media-sizes[lg]) {
    .container {
        width: @media-size[md] - 30px;
    }
}

.container {
    // 额外增加了15px的间隔
    padding-left: 15px;
    padding-right: 15px;
    margin-left: auto;
    margin-right: auto;

    .row {
        // 抵消到container额外增加的padding的
        margin-left: -15px;
        margin-right: -15px;
    }

    .col {
        // 因为这个地方总是增加了15的padding,为了方便col本身也作为container 容器使用, 也能实现间隔
        padding-left: 15px;
        padding-right: 15px;
    }
}

基于flex实现栅格系统

bootstrap栅格系统的神,目前bootstrap4 和 bootstrap5采用的方式就是flex的方式实现栅格,整理借鉴一下。

less
.row {
    display: flex;
    flex-wrap: wrap;
}
.col {
    flex: 0 0 auto
}
each(range(@unit-count), {
    .col-@{value} {
        width: @unit-width * @value
    }
})

迁移到ui框架

前面我们的设计都是在style上面作文章,实际栅格系统这种东西也就是style,没有交互,迁移到UI框架需要开放一些定制能力,比如栅格的间隔大小,栅格的个数,这个是单纯的样式系统不能实现的

总结

踩坑总结

  1. 在less中使用计算时,有时会碰到变量不计算的问题(被处理成了宏,直接替换了),使用括号包括强制计算
less
@unit-count: 10;
@unit-width: 100% / 10

.col {
    width: @unit-width * 5  // 理想应该输出 50   实际会输出 100% / 10 * 5
    width: (@unit-width * 5)  // 强制计算
}
  1. less中没有slot功能,比如想在@media将内容整个嵌入,还没找到办法实现
  2. 嵌套选择器没法跳过,这个还没找到功能
less
.a {
    &-b {
        color: red;
    }
}
// 这里我只想最终的输出如下
.a-b {
    color: red;
}
// 实际上会输出如下
.a .a-b {
    color: red;
}
  1. 如果选择更上一级的父选择器, 这个目前已经解决,通过将&赋值实现