Bootstrap栅格布局Less源码分析(i)

前言

Bootstrap是一个非常牛逼的前端框架,几乎所有人都在使用这个东西,因为Bootstrap移动优先的历练,有着非常出色的响应式布局。(所谓的响应式布局就是针对不同的设备(不同的屏幕的大小),显示的样式是不一样的)其中Bootstrap的源码都是使用Less这个非常牛逼的动态CSS语言,(上面我们刚刚介绍过)尤其是Bootstrap中栅格布局的Less源码的实现,更是值得我们每个人学习的。所以本次,我们就好好的分析一下栅格布局的Less源码。

开始Bootstrap

使用的第一部就是下载Bootstrap,不过在有网络的情况下直接使用CDN也是可以的。Bootstrap的官网中有使用Bootstrap的基本使用模版。

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
    <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
    <!--[if lt IE 9]>
      <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <h1>你好,世界!</h1>

    <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
    <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
  </body>
</html>

观察一下模版(不看关于IE的那些hack),可以看到第六行是有关于移动设备的,是必须要加上的。不过很多情况下,我们还会使用如下的形式。

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

让网页不可以被放大或者是缩小,看起来更像是移动终端的原生应用。

然后就是第24行,引用了jQueryBootstrap是依赖jQuery的,不过如果我们都不使用Bootstrapjavascript的插件或者是功能其实后面的两个引用也没啥意义。

Bootstrap中,所有的元素都被进行了优化,有了一些初始的样式。就算是不加任何的CSS,也不会想原生的那么丑。

栅格布局

什么是栅格布局,简单的来说就是Flex伸缩布局,其实应该是反掉了,是先有了栅格布局才有了伸缩布局才对。

Talk is cheap, show me the code!

<div class="container">
    <div class="row">
        <div class="col-md-4">col-md-4</div>
        <div class="col-md-6">col-md-6</div>
        <div class="col-md-2">col-md-2</div>
    </div>
    <div class="row">
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
      <div class="col-md-1">.col-md-1</div>
    </div>
    <div class="row">
        <div class="col-md-3">col-md-3</div>
        <div class="col-md-3">col-md-3</div>
        <div class="col-md-3">col-md-3</div>
        <div class="col-md-3">col-md-3</div>
    </div>
</div>

上面就是一个简单的栅格布局,为了是栅格看起来更加的明显一点,我们可以给栅格一点儿样式。

[class*="col-"] {
  padding-top: 15px;
  padding-bottom: 15px;
  background-color: #eee;
  background-color: rgba(86,61,124,.15);
  border: 1px solid #ddd;
  border: 1px solid rgba(86,61,124,.2);
}

1575812255770

显示的样式如上图所示(图片是本地的,网上应该是看不到的。)

首先这个container容器是居中的,两边都有一定的间隙。那是因为Bootstrap中已经给container这个类设定了一些样式,还有一个容器叫做container-fluid(流体容器)。下面先来看看这两个容器的区别。

两个容器containercontainer-fluid的样式

下面是.container的样式。

.container {
  padding-right: 15px;
  padding-left: 15px;
  margin-right: auto;
  margin-left: auto;
}
@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}
@media (min-width: 992px) {
  .container {
    width: 970px;
  }
}
@media (min-width: 1200px) {
  .container {
    width: 1170px;
  }
}

两边设置了padding,而两边的margin都是auto表示其在水平方向上应该是居中的。(.container肯定是一个块元素的,比如最常见的div)。

后面的@media是媒体查询,根据设备的不同的大小,.container容器将有不同的表现。

  • 大于等于1200px (lg)

    此时.container的大小为1170px(两边还padding 15px)。这种设备一般是个人的pc,比如我的笔记本电脑。

  • 大于等于992px, 小于1200px (md)

    此时.container的大小为992px。这种设备一般是平板电脑之内的。

  • 大于等于768px, 小于992px (sm)

    此时.container的大小为750px。这种设备一般是大屏幕的手机。

  • 小于768px (xs)

    此时.container的大小没有限制,所以应该是auto。(注意auto并不是100%,两者不一样)这种设备一般是小屏幕的手机。

上面就是Bootstrap中的四个媒体查询的级别,不仅仅是在.container容器中,在整个Bootstrap中都是如此。每个级别都对应了两个字母,我标在了后面的括号中,含义分别如下。

lg -> large
md -> medium
sm -> small
xs -> extra small

下面是.container-fluid的样式

.container-fluid {
  padding-right: 15px;
  padding-left: 15px;
  margin-right: auto;
  margin-left: auto;
}

经过我仔细的在源码中的查询,发现.container-fluid似乎咩有有关媒体查询的设置,那就意味这无论什么时候流体容器的大小都是auto

当我们将上面的栅格布局的.container修改成.container-fluid之后我们会发现变成了这样子。

1575813499885

占据了100%的宽度,因为宽度是auto(将父元素撑满)。再次强调一下,auto100%是不一样的,下面是对二者的说明。

width auto和100%的区别

width: auto

  • 子元素(包括content+padding+border+margin)撑满整个父元素的content区域。
  • 子元素有margin、border、padding时,会减去子元素content区域相对应的width值
  • 父元素的content = 子元素(content + padding + border + margin )

width: 100%

  • 强制将子元素的content区域 撑满 父元素的content区域
  • 子元素有margin、border、padding时,不改变子元素content区域的width,而是溢出父盒子,保持原有值
  • 父元素的content = 子元素的content

回归正题

为什么要说到两个容器.container.container-fluid呢,那是因为栅格的.row行必须要放置在这两个容器当中,以便为其赋予合适的排列(aligment)和内补(padding)。下面是官方文档中对栅格系统的一些说明。

  • “行(row)”必须包含在 .container (固定宽度)或 .container-fluid (100% 宽度)中,以便为其赋予合适的排列(aligment)和内补(padding)。
  • 通过“行(row)”在水平方向创建一组“列(column)”。
  • 你的内容应当放置于“列(column)”内,并且,只有“列(column)”可以作为行(row)”的直接子元素。
  • 类似 .row.col-xs-4 这种预定义的类,可以用来快速创建栅格布局。Bootstrap 源码中定义的 mixin 也可以用来创建语义化的布局。
  • 通过为“列(column)”设置 padding 属性,从而创建列与列之间的间隔(gutter)。通过为 .row 元素设置负值 margin 从而抵消掉为 .container 元素设置的 padding,也就间接为“行(row)”所包含的“列(column)”抵消掉了padding
  • 负值的 margin就是下面的示例为什么是向外突出的原因。在栅格列中的内容排成一行。
  • 栅格系统中的列是通过指定1到12的值来表示其跨越的范围。例如,三个等宽的列可以使用三个 .col-xs-4 来创建。
  • 如果一“行(row)”中包含了的“列(column)”大于 12,多余的“列(column)”所在的元素将被作为一个整体另起一行排列。
  • 栅格类适用于与屏幕宽度大于或等于分界点大小的设备 , 并且针对小屏幕设备覆盖栅格类。 因此,在元素上应用任何 .col-md-* 栅格类适用于与屏幕宽度大于或等于分界点大小的设备 , 并且针对小屏幕设备覆盖栅格类。 因此,在元素上应用任何 .col-lg-* 不存在, 也影响大屏幕设备。

上面说的都非常的明白易懂,主要就来看看第五点和最后一点。

第五点的说明

如果我们想创建列与列之间的间隙,我们需要通过padding而不是margin。为啥呢?我们使用的容器是.container,大小是确定的,而且是在父元素中居中的。当我们使用.col-md-4这种列的时候,因为.container默认就是12份,这个列的大小是确定的,就是.container三分之一Bootstrap在进行resetcss的时候给所有的元素都添加了一个我非常喜欢而且一直用的属性box-sizing = border-box

box-sizing = border-box改变了CSS中盒子大小的计算方式。先来说说box-sizing的另一个取值——content-box。这也是我最初开始学习的盒子模型。当我们给一个元素设置大小的时候,其实只是设置了content了的大小。此时如果给元素设置padding,元素的可视区域的大小会变大,设置border的话也是如此。这种规定说实话我是很看不惯的。在CSS3中,我们使用box-sizing = border-box就代表,如果我们为元素设置大小,这个大小指的是border + padding + content,因此设置padding或者border并不会影响元素的可视区域的大小。(content会变小)

简单的总结一下就是。

border-box: width/height = content + padding + border

content-box: width/height = content

因此我们设置padding的时候并不会改变元素的大小,元素的布局就没有改变,不过content之间确实是有了间距了。

如果我们设置的margin的话,元素的大小也没变,但是具有外边距了,原本完美的布局会因为多出来的外边距而变得一塌糊涂!下面是Bootstrap中列的源码。

.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-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
  position: relative;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}

这一点中还有一个需要说明,默认.container是有15px的padding的,作为内容的.row是没办法占用padding这部分的空间的,但是如果我们设置了负值的margin就可以占据这部分的空间。在Bootstrap中,.row有如下的样式。

.row {
  margin-right: -15px;
  margin-left: -15px;
}

最后一个点的说明

上面的xs sm md lg就是之前我们说过的对于不同的设备的媒体查询。如果我们设置的是.col-md-4这个类在其他的设备中没有办法识别的,这就为我们为不同的设备提供了非常方便的方式。

比如说如下的代码

<div class="container">
    <div class="row">
        <div class="col-md-4 col-xs-6">col-md-4 col-xs-6</div>
        <div class="col-md-6 col-xs-6">col-md-6 col-xs-6</div>
        <div class="col-md-2 col-xs-6">col-md-2 col-xs-6</div>
    </div>
</div>

md的模式下显示如下。

1575880287613

xs的模式显示如下。

1575880379272

从上图中,我们还可以看到xs下,.containerwidthauto的。

不过上面我说md模式显示如下,不过我的电脑是lg模式啊,lg模式好像我们并没有为他设置显示的样式。

这就要讲到上面我说媒体查询的顺序必须是xs sm md lg这种从大到小的顺序了。lg模式是,会先应用xs的样式,然后看有没有sm的样式,然后一次往后,后面的覆盖前面的。所以这里lg应用的是md的样式,而sm应用的是xs的样式。

总结

上面其实还是在简单的一步一步了解Bootstrap中的栅格布局,还没到看源码的时候呢。。。


一枚小菜鸡