bootstrap把response单独分开作为一个独立模块
这样整个栅格系统实际上分为了栅格grid和响应式布局response。非响应式的栅格是940固定宽度的,并且分为固定和流式两种,响应式布局就是通过media query增加了对不同屏幕宽度的适应。
布局上,通过容器的负padding-left和每一个列的margin-left来实现的,如下图所示:
一,定宽栅格的实现
在variables.less文件中定义了不同容器宽度下栅格系统的几个变量:列数(总是12列),列宽度columnWidth, 列间隙宽度gutterWidth和行宽度rowWidth。
代码如下:
// Default 940px grid
// -------------------------
@gridColumns: 12;
@gridColumnWidth: 60px;
@gridGutterWidth: 20px;
@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));
// 1200px min
@gridColumnWidth1200: 70px;
@gridGutterWidth1200: 30px;
@gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1));
// 768px-979px
@gridColumnWidth768: 42px;
@gridGutterWidth768: 20px;
@gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1));
这段代码定义了三种宽度下的显示方式,默认的940px宽度下,每一列宽度是60,列间隙是20,那么行宽度就是60x12+20x(12-1)=940px
在grid代码中直接调用了mixin中的grid方法:
// Fixed (940px)
#grid > .core(@gridColumnWidth, @gridGutterWidth);
// Fluid (940px)
#grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth);
// Reset utility classes due to specificity
[class*="span"].hide,
.row-fluid [class*="span"].hide {
display: none;
}
[class*="span"].pull-right,
.row-fluid [class*="span"].pull-right {
float: right;
}
注意其中还用了属性选择其来选择spanX,因此是不支持ie8一下的浏览器的。
#grid > .core和#grid - .fluid都是在mixin中定义的方法。
我们先看看core是如何实现的:
.core (@gridColumnWidth, @gridGutterWidth) {
//这个函数用递归实现了循环,因为less是没有循环的,因此index=12的时候会输出 .span1 ~ 12,而内部是调用.span函数
.spanX (@index) when (@index > 0) {
.span@{index} { .span(@index); }
.spanX(@index - 1);
}
.spanX (0) {} //用来结束递归
//这个函数和.spanX函数很像,都是用递归实现循环操作,内部也是调用了.offset函数实现的
.offsetX (@index) when (@index > 0) {
.offset@{index} { .offset(@index); }
.offsetX(@index - 1);
}
.offsetX (0) {}
//定义了12列offset的margin
.offset (@columns) {
margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1));
}
//定义了12列的宽度,注意宽度是如何计算出来的
.span (@columns) {
width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1));
}
//注意负margin,注意这里自带了clearfix,因此宽度会被里面的列撑开,而不需要指定宽度
.row {
margin-left: @gridGutterWidth * -1;
.clearfix();
}
//通过属性选择器统一定义了每一列的通用样式,好处是只需要定义一次,坏处是不支持ie8以下的浏览器(不支持属性选择器)
[class*="span"] {
float: left;
min-height: 1px; // prevent collapsing columns
margin-left: @gridGutterWidth;
}
// Set the container width, and override it for fixed navbars in media queries
//重载了container的宽度
.container,
.navbar-static-top .container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container { .span(@gridColumns); }
// generate .spanX and .offsetX
//调用函数递归生成.span1~12和.offset1~12
.spanX (@gridColumns);
.offsetX (@gridColumns);
}
其中最大的亮点就是用递归模拟了循环,通过循环避免了重复写12次代码。
二,流式栅格的实现
流式栅格相比对定宽栅格,最大的区别就是:
1,定宽栅格直接使用了传入的参数,而流式栅格用传入的参数计算出百分比,最终使用百分比来做布局。
2,定宽栅格可以使用负margin row来布局,而流式栅格则不行,因为row的负margin应该和span的margin-left保持一致,而这两个使用百分比的话是无法保持一致宽度的,因为百分比计算的对象不一样。
比如在同样是如下参数:
@gridColumns: 12;
@gridColumnWidth: 60px;
@gridGutterWidth: 20px;
@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));
定宽栅格中,每一列就是60px宽度,列间距就是20px
而在流式栅格中根据上述参数会计算出一个百分比来,实际使用的是这些百分比:
// Fluid grid
// -------------------------
@fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth);
@fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth);
流式栅格的代码如下:
.fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) {
//和定宽栅格没什么区别
.spanX (@index) when (@index > 0) {
.span@{index} { .span(@index); }
.spanX(@index - 1);
}
.spanX (0) {}
.offsetX (@index) when (@index > 0) {
.offset@{index} { .offset(@index); }
.offset@{index}:first-child { .offsetFirstChild(@index); }
.offsetX(@index - 1);
}
.offsetX (0) {}
.offset (@columns) {
margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth*2);
*margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + (@fluidGridGutterWidth*2) - (.5 / @gridRowWidth * 100 * 1%);
}
.offsetFirstChild (@columns) {
margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth);
*margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);
}
.span (@columns) {
width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1));
*width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%);
}
.row-fluid {
width: 100%;
.clearfix();
[class*="span"] {
.input-block-level();
float: left;
margin-left: @fluidGridGutterWidth;
*margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);
}
[class*="span"]:first-child {
margin-left: 0;
}
// Space grid-sized controls properly if multiple per line
.controls-row [class*="span"] + [class*="span"] {
margin-left: @fluidGridGutterWidth;
}
// generate .spanX and .offsetX
.spanX (@gridColumns);
.offsetX (@gridColumns);
}
}
三,响应式布局
有了上面的#grid > .core和 #grid > .fluid函数,实现响应式就非常简单了。
首先variables中已经定义好了不同宽度的样式,前面已经讲过了。
然后在加上media query并调用 #grid就ok了:
比如 1200px宽屏就是这么定义的:
@media (min-width: 1200px) {
// Fixed grid
#grid > .core(@gridColumnWidth1200, @gridGutterWidth1200);
// Fluid grid
#grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200);
// Input grid
#grid > .input(@gridColumnWidth1200, @gridGutterWidth1200);
// Thumbnails
.thumbnails {
margin-left: -@gridGutterWidth1200;
}
.thumbnails > li {
margin-left: @gridGutterWidth1200;
}
.row-fluid .thumbnails {
margin-left: 0;
}
}