Bootstrap3源码分析


前言

Bootstrap3依赖于jQuery,须先引入jQuery后方可使用。 Bootstrap3源码涉及Less,建议先了解Less再阅读源码。
官网:https://www.bootcss.com/
Git:https://github.com/twbs/bootstrap/

一、Bootstrap和它的栅格系统

1.Bootstrap介绍

Bootstrap是快速开发Web应用程序的前端工具包。它是一个HTML、CSS和JS的集合。为Web开发者提供了各种版式,如表单、组件、页面内容、布局等。

预处理工具
Bootstrap 的源码是采用最流行的 CSS 预处理工具 Less 和 Sass 开发的。可以直接采用预编译的 CSS 文件快速开发,也可以从 Bootstrap 源码自定义自己需要的样式。

	Bootstrap3:Less 	
	Bootstrap4、5:Sass

一个框架、多种设备。
在 Bootstrap 的帮助下通过同一份源码快速、有效地适配手机、平板和 PC 设备,这一切都是 CSS 媒体查询(Media Query)的功劳。

2.容器

  • 流体容器:width:auto
    流体布局:网页缩放时页面布局会随着浏览器大小而改变。
  • 固定容器
阈值 width
>=1200(lg 大屏pc) 1170(1140 + 槽宽)
>=992(md 中屏pc) 970(940 + 槽宽)
>=768(sm 平板) 750(720 + 槽宽)
<768(xs 移动手机) auto

3.栅格系统

Bootstrap 提供了一套响应式、移动设备优先的流式栅格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多12列。它包含了易于使用的预定义类,还有强大的mixin 用于生成更具语义的布局。

二、栅格系统源码分析

涉及源码文件如下:

  • variables.less
  • grid.less
  • mixin/clearfix.less
  • /mixin/grid.less
  • /mixin/grid-framework.less

1.固定容器&流体容器 公共样式

源码(Less)如下:

/* 
	入口文件代码(grid.less)
*/
.container {
    
    
  /* 调用固定和流体容器的公共样式 */
  .container-fixed();
  ......
}
// 流体容器
.container-fluid {
    
    
  .container-fixed();
}

/* 
	混合文件代码(grid.less)
	固定和流体容器的公共样式
	@grid-gutter-width: 30px;(槽宽)(变量声明文件variables.less)
 */
.container-fixed(@gutter: @grid-gutter-width) {
    
    
  padding-right: ceil((@gutter / 2));
  padding-left: floor((@gutter / 2));
  margin-right: auto;
  margin-left: auto;
  &:extend(.clearfix all); //继承clearfix清除浮动
}

/* 
	清除浮动(clearfix.less)
 */
.clearfix() {
    
    
  &:before,
  &:after {
    
    
    display: table; // 2
    content: " "; // 1
  }
  &:after {
    
    
    clear: both;
  }
}

其目的是设置容器的默认样式为:

padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;

2.固定容器 特定样式

源码如下:

/* 
	入口文件代码(grid.less)
	顺序不可变
	媒体查询(默认是移动设备)
*/
.container {
    
    
  .container-fixed();
  /* 媒体查询 */
  @media (min-width: @screen-sm-min) {
    
    
    width: @container-sm;
  }
  @media (min-width: @screen-md-min) {
    
    
    width: @container-md;
  }
  @media (min-width: @screen-lg-min) {
    
    
    width: @container-lg;
  }
}

/*
	在variables.less文件中值设置如下:
*/
@screen-sm:                  768px;
@screen-sm-min:              @screen-sm;
@container-tablet:             (720px + @grid-gutter-width);
@container-sm:                 @container-tablet;

@screen-md:                  992px;
@screen-md-min:              @screen-md;
@container-desktop:            (940px + @grid-gutter-width);
@container-md:                 @container-desktop;

@screen-lg:                  1200px;
@screen-lg-min:              @screen-lg;
@container-large-desktop:      (1140px + @grid-gutter-width);
@container-lg:                 @container-large-desktop;

3.行

源码如下:

/* 
	入口文件代码(grid.less)
*/
.row {
    
    
  .make-row();
}

/* 
	混合代码(grid.less)
*/
.make-row(@gutter: @grid-gutter-width) {
    
    
	margin-right: floor((@gutter / -2));
	margin-left: ceil((@gutter / -2));
	&:extend(.clearfix all);
}

其目的是设置行的默认样式为:

margin-right: -15px;
margin-left: -15px;

4.列

2.4.1 全部加默认样式

源码如下:

.make-grid-columns(); 

/* @grid-columns: 12;*/

.make-grid-columns() {
    
    
  /*
  	1. 首先执行(@index为1)
  	@item:.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1
  	调用.col((@index + 1), @item)。将@index+1和@item传过去
  */
  .col(@index) {
    
    
    @item: ~".col-xs-@{
    
    index}, .col-sm-@{
    
    index}, .col-md-@{
    
    index}, .col-lg-@{
    
    index}";
    .col((@index + 1), @item);
  }
  /*
  	2. (@index为2)
  	@item:.col-xs-2, .col-sm-2, .col-md-2, .col-lg-2
  	递归(自己调用自己),直到@index == 12。
  	最终@{list}为:
  		.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1,
	    .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2,
	    ......
	    .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12
  */
  .col(@index, @list) when (@index =< @grid-columns) {
    
     
    @item: ~".col-xs-@{
    
    index}, .col-sm-@{
    
    index}, .col-md-@{
    
    index}, .col-lg-@{
    
    index}";
    .col((@index + 1), ~"@{
    
    list}, @{
    
    item}");
  }
   /*
  	3. (@index为13)
  	@list:
  		..col-xs-1, .col-sm-1, .col-md-1, .col-lg-1,
	    .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2,
	    ......
	    .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12
  	添加属性
  */
  .col(@index, @list) when (@index > @grid-columns) {
    
    
    @{
    
    list} {
    
    
      position: relative;
      min-height: 1px;
      padding-right: floor((@grid-gutter-width / 2));
      padding-left: ceil((@grid-gutter-width / 2));
    }
  }
  .col(1); // kickstart it
}

其目的是给列加默认样式:

.make-grid-columns();
    .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1,
    .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2,
    ......
    .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{
    
    
        position: relative;
        min-height: 1px;
        padding-right: 15px;
        padding-left: 15px;
    }

2.4.2 设置列的浮动、宽度和位置

源码如下:

// 移动优先(以此为例进行源码分析)
.make-grid(xs);

// Small grid
@media (min-width: @screen-sm-min) {
    
    
  .make-grid(sm);
}
// Medium grid
@media (min-width: @screen-md-min) {
    
    
  .make-grid(md);
}
// Large grid
@media (min-width: @screen-lg-min) {
    
    
  .make-grid(lg);
}

/* 以移动界面为例,此时class=xs*/
.make-grid(@class) {
    
    
  // 2.1 左浮动
  .float-grid-columns(@class);
  // 2.2 列宽
  .loop-grid-columns(@grid-columns, @class, width);
  // 2.3 左右排序
  .loop-grid-columns(@grid-columns, @class, pull);
  .loop-grid-columns(@grid-columns, @class, push);
  // 2.4列偏移
  .loop-grid-columns(@grid-columns, @class, offset);
}

2.4.2.1 左浮动

.float-grid-columns(@class) {
    
    
	/*
		@index初始为1
		@item:.col-xs-1	
	*/
	.col(@index) {
    
    
	  @item: ~".col-@{
    
    class}-@{
    
    index}";
	  .col((@index + 1), @item);
	}
	/*
		递归至@index == 12。(@index为2)
		最终@list:.col-xs-1,.col-xs-2, ...... .col-xs-12	
	*/
	.col(@index, @list) when (@index =< @grid-columns) {
    
    
		@item: ~".col-@{
    
    class}-@{
    
    index}";
		.col((@index + 1), ~"@{
    
    list}, @{
    
    item}");
	}
	/*
		(@index为13)
		@list:.col-xs-1,.col-xs-2, ...... .col-xs-12	
		添加属性float
	*/
	.col(@index, @list) when (@index > @grid-columns) {
    
    
		@{
    
    list} {
    
    
			float: left;
		}
	}
	.col(1); // kickstart it 初始化
}

2.4.2.2 列宽

/*
	@index=12
	递归添加所有的width属性。当@index==0时,不符合calc-grid-column的条件。结束
	.col-xs-11{ width: 12/12 }
	......
	.col-xs-1{ width: 1/12 }
*/
.loop-grid-columns(@index, @class, @type) when (@index >= 0) {
    
    
  .calc-grid-column(@index, @class, @type);
  .loop-grid-columns((@index - 1), @class, @type);
}

/*
	添加width属性
	.col-xs-12{ width: 12/12 }
*/
.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {
    
    
  .col-@{
    
    class}-@{
    
    index} {
    
    
    width: percentage((@index / @grid-columns));
  }
}

2.4.2.3 列排序

/*
	@index=12
	递归添加所有的left属性
	.col-xs-push-12{ left: 12/12 }
    .col-xs-push-11{ left: 11/12 }
    ......
    .col-xs-push-1{ left: 1/12 }
    .col-xs-push-0{ left: auto }
*/
.loop-grid-columns(@index, @class, @type) when (@index >= 0) {
    
    
  .calc-grid-column(@index, @class, @type);
  .loop-grid-columns((@index - 1), @class, @type);
}

/*
	@index > 0 添加属性left并设置值
*/
.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {
    
    
  .col-@{
    
    class}-push-@{
    
    index} {
    
    
    left: percentage((@index / @grid-columns));
  }
}

/*
	@index == 0 添加属性left并设置值为auto
*/
.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {
    
    
  .col-@{
    
    class}-push-0 {
    
    
    left: auto;
  }
}
/*
	@index=12
	递归添加所有的left属性
	.col-xs-pull-12{ right: 12/12 }
    .col-xs-pull-11{ right: 11/12 }
    ......
    .col-xs-pull-1{ right: 1/12 }
    .col-xs-pull-0{ right: auto }
*/
.loop-grid-columns(@index, @class, @type) when (@index >= 0) {
    
    
  .calc-grid-column(@index, @class, @type);
  .loop-grid-columns((@index - 1), @class, @type);
}

/*
	@index > 0 添加属性right并设置值
*/
.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {
    
    
  .col-@{
    
    class}-pull-@{
    
    index} {
    
    
    right: percentage((@index / @grid-columns));
  }
}

/*
	@index == 0 添加属性right并设置值为auto
*/
.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {
    
    
  .col-@{
    
    class}-pull-0 {
    
    
    right: auto;
  }
}


2.4.2.4 列偏移

/*
	@index=12
	递归添加所有的 margin-left 属性
	.col-xs-offset-12{ margin-left: 12/12 }
    .col-xs-offset-11{ margin-left: 11/12 }
    ......
    .col-xs-offset-1{ margin-left: 1/12 }
    .col-xs-offset-0{ margin-left: auto }
*/
.loop-grid-columns(@index, @class, @type) when (@index >= 0) {
    
    
  .calc-grid-column(@index, @class, @type);
  .loop-grid-columns((@index - 1), @class, @type);
}

/*
	@index >= 0 添加属性margin-left并设置值
*/
.calc-grid-column(@index, @class, @type) when (@type = offset) {
    
    
  .col-@{
    
    class}-offset-@{
    
    index} {
    
    
    margin-left: percentage((@index / @grid-columns));
  }
}

最终列样式:

.make-grid(xs)  
    //2.1  左浮动
  .float-grid-columns(@class);
        .col-xs-1,.col-xs-2, ...... .col-xs-12{
    
    
            float: left;
        }
    // 2.2 列宽
  .loop-grid-columns(@grid-columns, @class, width);
      .col-xs-12{
    
     width: 12/12 }
      .col-xs-11{
    
     width: 11/12 }
      ......
      .col-xs-1{
    
     width: 1/12 }
 // 2.3 左右排序
  .loop-grid-columns(@grid-columns, @class, pull);
      .col-xs-pull-12{
    
     right: 12/12 }
      .col-xs-pull-11{
    
     right: 11/12 }
      ......
      .col-xs-pull-1{
    
     right: 1/12 }
      .col-xs-pull-0{
    
     right: auto }
      
  .loop-grid-columns(@grid-columns, @class, push);
      .col-xs-push-12{
    
     left: 12/12 }
      .col-xs-push-11{
    
     left: 11/12 }
      ......
      .col-xs-push-1{
    
     left: 1/12 }
      .col-xs-push-0{
    
     left: auto }
  // 2.4 列偏移
  .loop-grid-columns(@grid-columns, @class, offset);
      .col-xs-offset-12{
    
     margin-left: 12/12 }
      .col-xs-offset-11{
    
     margin-left: 11/12 }
      ......
      .col-xs-offset-1{
    
     margin-left: 1/12 }
      .col-xs-offset-0{
    
     margin-left: auto }


三、响应式工具

涉及源码文件如下:

  • mixin/responsive-visibility.less
  • responsive-utilities.less

源码如下:

/* 首先统一设置为不显示 */
.visible-xs,
.visible-sm,
.visible-md,
.visible-lg {
    
    
  .responsive-invisibility();
}

.visible-xs-block,
.visible-xs-inline,
.visible-xs-inline-block,
.visible-sm-block,
.visible-sm-inline,
.visible-sm-inline-block,
.visible-md-block,
.visible-md-inline,
.visible-md-inline-block,
.visible-lg-block,
.visible-lg-inline,
.visible-lg-inline-block {
    
    
  display: none !important;
}

/* 设置在什么宽度下显示 */
.visible-xs {
    
    
  @media (max-width: @screen-xs-max) {
    
    
    .responsive-visibility();
  }
}
.visible-xs-block {
    
    
  @media (max-width: @screen-xs-max) {
    
    
    display: block !important;
  }
}
......

/* 设置在什么宽度下不显示 */
.hidden-xs {
    
    
  @media (max-width: @screen-xs-max) {
    
    
    .responsive-invisibility();
  }
}
......

.responsive-visibility() {
    
    
  display: block !important;
  table&  {
    
     display: table !important; }
  tr&     {
    
     display: table-row !important; }
  th&,
  td&     {
    
     display: table-cell !important; }
}

.responsive-invisibility() {
    
    
  display: none !important;
}

四、栅格和模型设置的精妙之处

  • 容器 两边具有15px的padding

  • 行 两边具有-15px的margin

  • 列 两边具有15px的padding

     1. 为了维护槽宽的规定:
     	列两边必须有15px的padding
     2. 为了能使列嵌套行
     	行两边必须要有-15px的margin
     3. 为了让容器可以包裹住行
     	容器两边必须要有15px的padding
    

猜你喜欢

转载自blog.csdn.net/yan_danfeng/article/details/118395732