Bootstrap——快速开发Web应用的前端工具包

Bootstrap是一个快速开发Web应用的前端工具包,它为开发者提供了下面三种工具。

  • 基础:样式重置,栅格系统,响应式设计支持等
  • 零件:按钮,导航,面包屑,分页,进度条,各种常用icon等
  • 组件:对话框,下列菜单,tabs,浮出提示,轮播等

有了这样一套风格统一的基础工具、小零件、成品组件,快速搭建美观易用的Web应用会让你轻松不少。

Bootstrap开源不久,很快就成为GitHub上最热门的项目之一。许多开发者们也把它应用在了自己维护的站点上。事实上,在Bootstrap推出前,前端工具包已经有很多了,也不乏非常流行的如 jQuery + jQuery UI, YUI 等。为什么Bootstrap依然能脱颖而出呢?我们先大致看下它是怎么设计的吧。

Bootstrap现在已经发布了2.0版本,架构更加清晰。其核心部分是在less.css的基础上构建的,入口文件有2个,bootstrap.less 和 responsive.less 。后者是Bootstrap实现响应式设计的配置文件;前者是它的主入口文件,依序包含了下面几部分:

  1. CSS Reset
  2. Core variables and mixins
  3. Grid system and page structure
  4. Base CSS
  5. Components
  6. Utilities

这里第1,第3部分是许多其他前端工具包都有的部分,Bootstrap也提供了自己的版本。

第2部分是less.css扩展的变量、混入功能的应用。它为Bootstrap提供了最大的灵活性,给二次开发带来了许多便利。这是许多其他前端工具包所没有的优势。

第4,第5部分是Twitter贡献的各种零部件风格。其中4是各种基础元素——字型、表单、表格等。而第5部分是各种自定义零部件,其中有十分全面的图标,有各种按钮,以及各种复杂的组件风格等。

Bootstrap发布的是less编译后的文件,bootstrap.css 与 bootstrap-responsive.css。另外,Bootstrap还提供了一些自己风格的jQuery插件。

用户使用时,只要依葫芦画瓢,按Bootstrap提供的demo,写上同样的class,美观、统一的页面就生成了。得益于Bootstrap零部件的全面,只关心html,无需在htlml/css/js间切换,给页面开发带来一气呵成的快感。如果你要自定义风格,修改几个less变量即可实现,极大地解放了生产力。

当然,Bootstrap还有许多其他优点,比如文档丰富、跨平台、社区发展势头好等,这些都可以让开发者放心大胆地选择Bootstrap。

less在Bootstrap中的应用

个人觉得比较赞的:

  1. colors 变量。一般是主体色+辅色,Bootstrap的定义主要像navbarLinkColor,navbarBackground这种,许多辅色是主色的50%,也应用了less。个人认为这与设计师习惯相符,便于在不同频道间复用。但第一次书写成本可能会增加10%,复用时可以同时减少设计师与前端的工作量。
  2. .broder-radius,.bos-shadow等函数在Bootstrap中都有定义。个人觉得这对提高开发效率有不少帮助。
  3. Bootstrap是利用 less 的 import 来组织代码的,既便于调试,也便于打包。书写优雅,学习成本较低。

其他细节:

  1. zindex,Bootsrtap里有十分细致的 zindexDropdown,zindexTooltip等。个人认为与全站z-index约定不同,这个涉及范围小一些,在多人维护的项目中可以减少调试工作。
  2. Bootstrap中许多小模块的组织使用了嵌套的方式,个人觉得这种方式用来组织小模块还是很方便的。但是不宜滥用,太深的嵌套会导致性能下降。
  3. less其实还有命名空间可以使用,Bootsrtap在定义 gradient(horizontal、vertical、radial等),popoverArrow(top、left、bottom、right) 等mixin时采用了这种组织方式。

CommonJS Modules/1.1.1笔记

先简单说明下CommonJS模块。每个模块都有对应的标示符,而标示符有两种:相对标示符与绝对标示符。模块的上下文中,有requireexports以及module三个变量。

模块的引入是通过模块中的require函数完成的,参数是要引入的模块标示符,返回值是被引入模块暴露的API。require可以有一个main属性,这个属性是只读的,一般指向主模块的”module”对象(没有主模块时为undefined)。比如,在nodejs环境中,你可以使用require.main === module来判断当前模块是否为主模块。如果不是沙箱环境,require还可以有一个paths属性,这个属性是一个字符串数组,内容是顶级标示符对应的模块查找目录。paths属性是全局唯一的,对它的修改会影响模块的搜索行为。需要注意的是,paths内容的格式是由模块的loader程序决定的,规范没有统一规定。

模块引入部分最让我费解的是模块出现循环依赖时的处理方式。不过,在承玉同学的帮助下,终于搞明白了。比如下面的例子:

a.js

exports.done = false;
var b = require(‘./b.js’);
exports.done = true;

b.js

var a = require(‘./a.js’);
console.log(‘in b, a.done = %j’, a.done);

如果直接运行a.js,在b.js中引入模块a时,a实际上并没有完全执行。这个时候,按规范的要求,require至少会返回被require时已经执行的部分,这里是exports.done = false。因此,这段代码会输出“in b, a.done = false”。(如果你有兴趣,可以用nodejs测试一下循环依赖的问题。不过需要注意,在nodejs中,模块在第一次执行后,会被缓存下来)

与引入相反,模块向外界暴露API是通过exports对象实现的。

模块最后一个属性:”module”有一个必选属性”id”和一个可选属性”uri”。模块的id的值是改模块的顶级标示符,这个值是只读的。而”uri”属性指向该模块所在的资源文件的URI。在沙箱环境里是没有”uri”属性的。

模块的标示符是一个字符串,内容是由’/'分割的”terms”,每个”term”都是驼峰式的标示符、”.”或”..”。如果标示符以”.”或”..”开始,该标示符就是相对标示符。相对标示符是相对调用”require”的模块,顶级标示符是相对于模块的根命名空间。最后一点,标示符可以没有”.js”这样的文件后缀。

个人感觉顶级标示符这里,规范的解释并不是很清晰,使用时还是应该以模块的loader为准。

整体看下来,Modules/1.1.1规范还有不少不清楚或有争议的地方,这个在CommonJS的wiki里也承认。不过模块的组织思想应该不会变了。人们的实践也走在了规范的前面,比如seajs :)