bootstrap源码分析系列:二,栅格和响应式布局

bootstrap把response单独分开作为一个独立模块
这样整个栅格系统实际上分为了栅格grid和响应式布局response。非响应式的栅格是940固定宽度的,并且分为固定和流式两种,响应式布局就是通过media query增加了对不同屏幕宽度的适应。

布局上,通过容器的负padding-left和每一个列的margin-left来实现的,如下图所示:

一,定宽栅格的实现

在variables.less文件中定义了不同容器宽度下栅格系统的几个变量:列数(总是12列),列宽度columnWidth, 列间隙宽度gutterWidth和行宽度rowWidth。
代码如下:

  1. // Default 940px grid  
  2. // -------------------------  
  3. @gridColumns:             12;  
  4. @gridColumnWidth:         60px;  
  5. @gridGutterWidth:         20px;  
  6. @gridRowWidth:            (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));  
  7.   
  8. // 1200px min  
  9. @gridColumnWidth1200:     70px;  
  10. @gridGutterWidth1200:     30px;  
  11. @gridRowWidth1200:        (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1));  
  12.   
  13. // 768px-979px  
  14. @gridColumnWidth768:      42px;  
  15. @gridGutterWidth768:      20px;  
  16. @gridRowWidth768:         (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1));  




这段代码定义了三种宽度下的显示方式,默认的940px宽度下,每一列宽度是60,列间隙是20,那么行宽度就是60x12+20x(12-1)=940px

在grid代码中直接调用了mixin中的grid方法:

  1. // Fixed (940px)  
  2. #grid > .core(@gridColumnWidth, @gridGutterWidth);  
  3.   
  4. // Fluid (940px)  
  5. #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth);  
  6.   
  7. // Reset utility classes due to specificity  
  8. [class*="span"].hide,  
  9. .row-fluid [class*="span"].hide {  
  10.   display: none;  
  11. }  
  12.   
  13. [class*="span"].pull-right,  
  14. .row-fluid [class*="span"].pull-right {  
  15.   float: right;  
  16. }   




注意其中还用了属性选择其来选择spanX,因此是不支持ie8一下的浏览器的。
#grid > .core和#grid - .fluid都是在mixin中定义的方法。

我们先看看core是如何实现的:

 

  1. .core (@gridColumnWidth, @gridGutterWidth) {  
  2.    //这个函数用递归实现了循环,因为less是没有循环的,因此index=12的时候会输出 .span1 ~ 12,而内部是调用.span函数  
  3.    .spanX (@index) when (@index > 0) {  
  4.      .span@{index} { .span(@index); }  
  5.      .spanX(@index - 1);  
  6.    }  
  7.    .spanX (0) {} //这个没有任何输出的,不知道写这里干嘛  
  8.       
  9.     //这个函数和.spanX函数很像,都是用递归实现循环操作,内部也是调用了.offset函数实现的  
  10.    .offsetX (@index) when (@index > 0) {  
  11.      .offset@{index} { .offset(@index); }  
  12.      .offsetX(@index - 1);  
  13.    }  
  14.    .offsetX (0) {}  
  15.   
  16.     //定义了12列offset的margin  
  17.    .offset (@columns) {  
  18.      margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1));  
  19.    }  
  20.       
  21.     //定义了12列的宽度,注意宽度是如何计算出来的  
  22.    .span (@columns) {  
  23.      width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1));  
  24.    }  
  25.   
  26.     //注意负margin,注意这里自带了clearfix,因此宽度会被里面的列撑开,而不需要指定宽度  
  27.    .row {  
  28.      margin-left: @gridGutterWidth * -1;  
  29.      .clearfix();  
  30.    }  
  31.   
  32.     //通过属性选择器统一定义了每一列的通用样式,好处是只需要定义一次,坏处是不支持ie8以下的浏览器(不支持属性选择器)  
  33.    [class*="span"] {  
  34.      float: left;  
  35.      min-height: 1px; // prevent collapsing columns  
  36.      margin-left: @gridGutterWidth;  
  37.    }  
  38.   
  39.    // Set the container width, and override it for fixed navbars in media queries  
  40.    //重载了container的宽度  
  41.    .container,  
  42.    .navbar-static-top .container,  
  43.    .navbar-fixed-top .container,  
  44.    .navbar-fixed-bottom .container { .span(@gridColumns); }  
  45.   
  46.    // generate .spanX and .offsetX  
  47.     //调用函数递归生成.span1~12和.offset1~12  
  48.    .spanX (@gridColumns);  
  49.    .offsetX (@gridColumns);  
  50.  }   




其中最大的亮点就是用递归模拟了循环,通过循环避免了重复写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);


流式栅格的代码如下:

  1. .fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) {  
  2.      //和定宽栅格没什么区别  
  3.     .spanX (@index) when (@index > 0) {  
  4.       .span@{index} { .span(@index); }  
  5.       .spanX(@index - 1);  
  6.     }  
  7.     .spanX (0) {}  
  8.   
  9.     .offsetX (@index) when (@index > 0) {  
  10.       .offset@{index} { .offset(@index); }  
  11.       .offset@{index}:first-child { .offsetFirstChild(@index); }  
  12.       .offsetX(@index - 1);  
  13.     }  
  14.     .offsetX (0) {}  
  15.   
  16.     .offset (@columns) {  
  17.       margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth*2);  
  18.          *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + (@fluidGridGutterWidth*2) - (.5 / @gridRowWidth * 100 * 1%);  
  19.     }  
  20.   
  21.     .offsetFirstChild (@columns) {  
  22.       margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth);  
  23.       *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);  
  24.     }  
  25.   
  26.     .span (@columns) {  
  27.       width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1));  
  28.       *width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%);  
  29.     }  
  30.   
  31.     .row-fluid {  
  32.       width: 100%;  
  33.       .clearfix();  
  34.       [class*="span"] {  
  35.         .input-block-level();  
  36.         float: left;  
  37.         margin-left: @fluidGridGutterWidth;  
  38.         *margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);  
  39.       }  
  40.       [class*="span"]:first-child {  
  41.         margin-left: 0;  
  42.       }  
  43.   
  44.       // Space grid-sized controls properly if multiple per line  
  45.       .controls-row [class*="span"] + [class*="span"] {  
  46.         margin-left: @fluidGridGutterWidth;  
  47.       }  
  48.   
  49.       // generate .spanX and .offsetX  
  50.       .spanX (@gridColumns);  
  51.       .offsetX (@gridColumns);  
  52.     }  
  53.   
  54.   }   

三,响应式布局


有了上面的#grid > .core和 #grid > .fluid函数,实现响应式就非常简单了。
首先variables中已经定义好了不同宽度的样式,前面已经讲过了。
然后在加上media query并调用 #grid就ok了:
比如 1200px宽屏就是这么定义的:

  1. @media (min-width: 1200px) {  
  2.   
  3.   // Fixed grid  
  4.   #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200);  
  5.   
  6.   // Fluid grid  
  7.   #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200);  
  8.   
  9.   // Input grid  
  10.   #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200);  
  11.   
  12.   // Thumbnails  
  13.   .thumbnails {  
  14.     margin-left: -@gridGutterWidth1200;  
  15.   }  
  16.   .thumbnails > li {  
  17.     margin-left: @gridGutterWidth1200;  
  18.   }  
  19.   .row-fluid .thumbnails {  
  20.     margin-left: 0;  
  21.   }  
  22.   
  23. }   

相关推荐