栅栏布局
栅栏布局是网页中最常见的使用组件之一了。
最常见的就是在 Bootstrap 3 中的栅栏使用。
bootstrap系统会自动分为 12列,在12列的基础上根据不同类名再区分,例如col-md-1 代表12列中的一列宽度。
一个最简单的栅栏使用在bs中是这样的
<div class="row">
<div class="col-md-12">.col-md-12</div>
</div>
我们留意到bs整体也只是 对列分 而已。例如12栅栏,每一列即为 1/12 * 100% = 8.33333%
加上内部的整体栅栏块的浮动,这样一来整体浮动块在同行编排一块搭一块。
偏移量
bs 的栅栏还提供偏移量。
从css代码上来看,偏移量其实是将原先列大小设置margin值。 bs 使用 float left 生成栅栏布局。 使用margin-left 设立 偏移量。
响应式
我们知道做响应式适配一般是使用媒体查询,响应式覆盖的终端希望越多,则我们设置的断点即越多。
bs 给我们设立了几个默认断点
超小屏幕 手机 (<768px) 小屏幕 平板 (≥768px) 中等屏幕 桌面显示器 (≥992px) 大屏幕 大桌面显示器 (≥1200px)
(min-width表示大于xxx 则执行)(max-width 表示小于xxx 则执行)
对应的使用是
xs, sm, md, lg
用一些预处理工具做这样的 media query 写个mixin,在原普通栅栏情况下传入变量即可
Gutter
把 gutter 放在最后面是因为有一些地方有意思。
gutter 简单,它定义了,一个栅栏列与另一个栅栏列之间的间隔。
假如我们设置了类似如下的 DOM 结构
div.row
div.col-6
dov.col-6
我们假设 col-6 与 col-6 之间定义一个 30px 的间隔。
原先的 column 定义,我们是将 column 栅栏铺满 100% 计算。如果此时我们增加外边距。
gutter实现方式
简单地有四种实现:
- (元素之间加 margin-left 舍弃头元素的 margin-left )(元素之间加 margin-right 舍弃尾部元素的 margin-right )
这种方式情况下,我们必须舍弃一边的 margin , 以换取相对合理的间距。
但是问题增加到多层栅栏的时候。单个 margin 的多余肯定是仍然会存在的。换行后的元素与换行后前元素必然存在margin的多余。 这样就导致不一致了。
- 元素之间使用单边的 padding 值
这种方式情况下,元素在单行视觉下,确实会做到有一定的间距。但是这种情况下依旧在多行不可行。
因为总有被舍弃的一方,在视觉上不平衡
- 拆分 margin 给两端消化。
这种实现是较为可行的一种,利用calc计算每段的实际 width ,给出位置给 margin 填充。
但这种方案可以注意到边界左右两侧的元素始终与容器保持这 gutter/2 的差距。gutter 只是为了栅栏之间的距离。
以上计算方法应该变成 假定 gutter 30px 分发给左右两侧margin 消化。 则此时一个 column col-1 = calc(8.3% - 30px);
- 拆分 padding 给两端消化。
这种实现也是可行的。也是bs采用的方案。使用 padding 来填充 gutter,左右两侧的 差距 通过 margin 负值来进行去除。
(这种技巧还可以用在有一定距离的元素,在单行转多行的情况下,利用 margin 负值来清理多余值。eg: 小短片)
而 padding 的计算方式,则col-1 仍为8.3% width, 使用左右两侧的 padding: 0 15px; 容器组件 再使用 margin: 0 -15去除掉这个边距15即可。
(注意容器组件的设定,不能在设置width: 100%; 的前提下设置 margin: 0 -15px; 因为 margin 的计算方式,假定设置了元素的宽度: width 这个水平方向的计算会变成(怪异盒模型时): 左margin + width + 右margin = width; 当左 margin 为负数时, 右 margin 需要设置正数来将其总和等于元素的内容宽度。(计算方式还依赖于文档编排顺序。右往左读则相反))(css权威指南 175)
这样一来,一个简单的栅栏布局需要要素,我们都已经厘清了。
实际上 bs3 的栅栏实现还是较为经典的。利用float 加 栅栏百分比实现。 gutter 采用 padding,容器采用负 margin 去除多余间距。
按钮组
主要是遇到几个问题想记录一下。
按钮的边框多余堆叠
假定我们的按钮组是由多个 button 块组合的。
这样以来通常每个 button 块就会有 1px 的 border 值。在按钮组的情况下,按钮一般是堆叠实现的。
横排或者竖排。这样以来免不了有一部分重叠的元件,会造成 border 2px的情况。
参考 bulma,bs,antd。惊人的发现,它们之间的实现,居然可以说,差别只有在具体一些hover的处理,还有颜色主题的差别。
核心都是一样的。利用 margin 负边距,使得每个按钮将多余的1px“吃掉”。
但是 margin 负值会有一个问题,当我们要做例如hover 边框线条高亮的话,这个时候由于margin负值,边框border堆叠,可能我们不能很好的实现border的堆叠问题。所以看到,几乎 bs, bulma, ant-design,都给 active focus 这种状态下的按钮元素给添加上了一个较小的z-index值,使得其能更好地展示。
但是 antd 会有一个问题(我们知道庞大的 antd,更像是在 rc 基础库上的一个巨大设计系统。)antd的按钮边框,悬停会触发动画,移开也会触发动画。当一个按钮 focus了以后,动画触发,且给元素设置一个较小 z-index 值。所以 focus 的时候动画触发很稳定没问题。但是在移出时候,z-index的移除是马上的,所以显示上,虽然边框的颜色动画还是在进行,可是一边边框的早就因为没有了z-index 而消除。
我想了一下,z-index可以设置一个较少值,使得其在动画转移时候仍然生效,而不是马上移除。 亦或者 像 bs,bulma 等,取消其 border-color 的动画,改为直出。
这个问题源自于看的一个 antd 的bug。
按钮组的outline显示
再记录一个关于访问性的。
我们经常可能会忽略 outline。很多人会经常习惯性地将 outline 设置为0,或者 none,认为它们将高亮赋予给元素时显得很丑陋。
(维持可访问性是前端应该做的,同时同理心也是必须的,当然可访问性也很难TAT)
由于 outline 不占据空间,所以我们设计按钮组的时候,也可能会有问题。

不妨来猜测解决方案是如何?
实际上我们给按钮设置 position: relative; 即可。
(问题的成因确切来说不是很清楚。有知情者欢迎交流。)
我看到 antd 下其实也有这个代码。但是看代码处链接好像是为了解决ie下的文字偏移问题。链接
我的问题解决链接是这个outline问题链接
好啦,本文就到这了。
总结
- 探讨了 旧版 栅栏布局的实现
- 按钮组的几个考虑问题。
本文参考
- How to build a responsive grid system
- Making Future Interfaces: Algorithmic Layouts
- outline-getting-hidden-by-the-next-element
- bulma
- bootstrap
- antd
联系我
欢迎理性交流探讨