Bootstrap 的使用心得

萌新Bootstrap——真好用!

休闲玩家BootstrapHTML页面耦合在一起,如何维护?

高端玩家:用Compass引入Bootstrap

虽然Bootstrap已经“烂大街”了,但是它至少是个完整的CSS组件库。Bootstrap 文档非常详细,参照示例代码,就能快速上手。

复用Bootstrap所提供的组件样式,有利于原型的制作实现。但原型就是原型,由于HTML页面中充斥着大量无语义的类名,CSS样式就与HTML页面深度耦合了。耦合,使得页面代码既不易阅读,也不易修改。

有时,我们并不只是满足于原型的制作,而是希望得到一个曳光弹。在不舍弃Bootstrap的情况下,需要找到一个既能复用组件,又能减少耦合的办法。

从文档着手

Bootstrap 文档中,整个框架按层次被划分为四部分:LayoutContentComponentsUtilities

Layout提供了基于Flexbox的响应式“网格布局”,其中的“列”和“槽”是无语义的类名;Content提供了文字、图片、代码与表格的排版样式,但大部分都是无语义的展示性类名;Components提供了一系列通用性组件,如:面包屑、手风琴、轮播等; Utilities中大都是与元素的盒模型、外观有关的展示性类名。

单个元素的盒模型、排版与外观都可以在外部的CSS样式表中实现,而Bootstrap的核心则是响应式的“网格布局”与通用性组件。在Layout部分的Grid章节中,Sass mixins小节提供了可定制、语义化“网格布局”的解决方案——Sass

学习 Sass

既然官方已给出解决方案,那么我们顺着路走就好了。Sass没听说过,那就去查、去学!

Sass并不难学,它只是一种用于描述CSSDSL而已,可参考Sass 文档、《Sass和Compass设计师指南》、《Sass与Compass实战》。

阅读源码

GitHub上,可以找到Bootstrap源码仓库。在Ruby社区的Gem托管——RubyGems,可以获得Bootstrap 源码包

整个Bootstrap框架源码分为两部分:stylesheetsjavascripts,而javascripts与交互式组件有关,暂不考虑。stylesheets是由初始化文件、组件文件、mixins文件夹与 utilities文件夹构成。

网格布局

在自有的.scss文件中,覆盖_variables.scss中的变量可实现Bootstrap的定制。Bootstrap的“网格布局”是由_grid.scss调用mixins目录下_grid.scss_grid-framework.scss中的混合器实现的。

@import "bootstrap/variables";

@import "bootstrap/mixins/breakpoints";
@import "bootstrap/mixins/grid-framework";
@import "bootstrap/mixins/grid";

@import "bootstrap/grid";

mixins目录下的_grid.scss文件用于生成“容器”、“行”、“列” ,以及列偏移,“槽”是由参数$gutter控制。

@mixin make-container($gutter: $grid-gutter-width) {
  width: 100%;
  padding-right: $gutter / 2;
  padding-left: $gutter / 2;
  margin-right: auto;
  margin-left: auto;
}

参数$max-widths用于控制“容器”的最大宽度,参数$breakpoints用于设置断点,这些参数可以通过传参或使用默认值来调节。混合器media-breakpoint-up是由mixins目录下的_breakpoints.scss文件提供,用于设置媒体查询。

@mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) {
  @each $breakpoint, $container-max-width in $max-widths {
    @include media-breakpoint-up($breakpoint, $breakpoints) {
      max-width: $container-max-width;
    }
  }
}

“列”是通过调用混合器make-col-readymake-colmake-col-offset来实现的,flex属性控制列宽,margin-left属性控制列偏移。

@mixin make-col-ready($gutter: $grid-gutter-width) {
  position: relative;
  // Prevent columns from becoming too narrow when at smaller grid tiers by
  // always setting `width: 100%;`. This works because we use `flex` values
  // later on to override this initial width.
  width: 100%;
  padding-right: $gutter / 2;
  padding-left: $gutter / 2;
}

@mixin make-col($size, $columns: $grid-columns) {
  flex: 0 0 percentage($size / $columns);
  // Add a `max-width` to ensure content within each column does not blow out
  // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari
  // do not appear to require this.
  max-width: percentage($size / $columns);
}

@mixin make-col-offset($size, $columns: $grid-columns) {
  $num: $size / $columns;
  margin-left: if($num == 0, 0, percentage($num));
}

媒体查询

Bootstrap的媒体查询是由mixins目录下的_breakpoints.scss文件实现的,这个文件是整个框架的基石

media-breakpoint-upmedia-breakpoint-downmedia-breakpoint-betweenmedia-breakpoint-only四个混合器的$name参数,只接受$breakpoints中的存在的键名。而它们又是基于函数:breakpoint-nextbreakpoint-minbreakpoint-max,理解了这3个函数的返回值,也就弄懂了Bootstrap媒体查询的实现方式。

@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {
  $n: index($breakpoint-names, $name);
  @return if($n != null and $n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
}
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
  $min: map-get($breakpoints, $name);
  @return if($min != 0, $min, null);
}
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
  $next: breakpoint-next($name, $breakpoints);
  @return if($next, breakpoint-min($next, $breakpoints) - .02, null);
}

收工

Bootstrap自身不包含自动添加厂商前缀的功能,它依赖于AutoprefixerGem包:autoprefixer-rails),支持的浏览器见browserslist

使用Autoprefixer的话,就不再依赖于用Compass添加CSS 3特性啦!