资讯专栏INFORMATION COLUMN

挑逗Bootstrap4源代码 - Grid篇(上)

wizChen / 1572人阅读

摘要:候补,分别代表两种宽度之间和仅在一种宽度下的情形。这里是一个很重要的变化,大家可以注意到,这里的变成了,这也是主要的改进之一,这个基础构建的变化意味着整个框架在很大程度上都会建立在的基础上滚蛋吧。

本文所引用的版本为Bootstrap 4 Beta版,阅读者请先下载好相关源文件。

时光荏苒,若后续版本代码发生变化,将看心情进行更新补充。如果你觉得本文不错,欢迎评论支持,如需转载请标明作者及出处,谢谢。

在日常使用Bootstrap的时候,我们最常见的做法是给HTML内的元素添加上预设的类名,这种方法直观且易于调试。但是对于一个前端洁癖患者来说,在HTML标签内添加一大堆类名简直和内联style一样让人深恶痛绝。那么在这种时候,学会使用Bootstrap的Scss,利用其内置的函数和@mixin来对你自己命名的类进行样式添加就成了一件很棒很酷的事。

涉及文件

变量:_variables.scss(起始行:171,结束行:205)

函数:_function.scss //其中函数主要用于变量文件中,在此不述

公共类:_flex.scss //在utilities文件夹下,用于flex布局的各种类,只是给属性加了包装,同样不述

@mixin:

_breakpoints.scss //断点函数区,包括断点区间查找、自动扩展媒体查询等功能

_grid.scss //辅助mixin,提供容器、行、列创建

_grid-framworks.scss //核心mixin,依据断点,循环创建以flex为基础的12网格

引用:_grid.scss //自动创建包括12列网格在内的布局,本质上是对_grid-frameworks和_grid的引用

要素分析 变量(_variales.scss):

$grid-breakpoints:

$grid-breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
) !default;
@include _assert-ascending($grid-breakpoints, "$grid-breakpoints");
@include _assert-starts-at-zero($grid-breakpoints);

分为xssmmdlgxl五个等级,分别表示极小中等超大。这个断点设置主要用于媒体查询,即当浏览器视窗横向尺寸发生变化时,一旦到了指定条件,比如width=768px,就将触发设置在md断点下的样式。这些等级的数据可以按需改动,全局凡是引用这个map的都将受到影响。

在文档注释中提到,这里设置的数值表示变化的最小值,即触发md的条件是≥768px。

在变量$grid-breakpoints后跟着两个@mixin,这两个@mixin定义在根目录下_function.scss文件中,都起一个判断作用,其中_assert-ascending()是确保整个$grid-breakpoints的内容是按升序排列,即从小到大;_asseert-starts-at-zero()是确保$grid-breakpoints的第一个元素值必须为0,即xs必须为0。

$container-max-widths:

$container-max-widths: (
  sm: 540px,
  md: 720px,
  lg: 960px,
  xl: 1140px
) !default;
@include _assert-ascending($container-max-widths, "$container-max-widths");

相比较于网格断点变量,这里的容器变量删去了xs等级,只余下了4个等级。这并不违背逻辑,因为在注释中,这里写的数值表示容器宽度的最大值。举个例子,在md条件下,视窗最小宽度为768px,而容器最大宽度为720px,留有一定的余地。所以这样的话,数值为0xs在容器宽度这里是没有意义的,标记为sm的容器宽度值就是在0-540px之间变动,正对应着视窗宽度xssm的区间。变量后紧跟着的函数之前已经提过,这里不再赘述。

grid-columns:

$grid-columns: 12 !default;
$grid-gutter-width: 30px !default;

这里的grid-columns指的是包括$grid-columns$grid-gutter-width在内的网格列定义。
这两者($grid-columns$grid-gutter-width)都是初始定义,分别表示总列数列间隔,在之前的alpha6版本中,还有一个不同视宽下的gutter组,在beta版本中已被删除。

至此,网格涉及的变量已经介绍完,后续的所有mixin和函数都是基于这些数值的,所以这里的数值很重要,牵一发而动全身。

@mixin(mixins文件夹)

_breakpoints.scss:

breakpoint-next:

@function breakpoint-next(
  $name, 
  $breakpoints: $grid-breakpoints, 
  $breakpoint-names: map-keys($breakpoints)) 
{
  $n: index($breakpoint-names, $name);
  @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
}

该函数看似有三个,实际只有两个参数,一个是$name,即断点名,需手动输入,第二个是在变量中定义的断点的名称列表。该函数的作用就是返回输入的断点名的下一个断点,如果没有下一个了,那就返回空值。即breakpoint-next(“sm”)将返回mdbreakpoint-next(“xl”)将返回null。

breakpoint-min、breakpoint-max:

@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
  $min: map-get($breakpoints, $name);
  @return if($min != 0, $min, null);
}
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
  $next: breakpoint-next($name, $breakpoints);
  @return if($next, breakpoint-min($next, $breakpoints) - 1px, null);
}

这两个函数光看函数名很容易引起误会,它们的作用绝非获取断点列表中的最大值和最小值,因为我们在事先定义断点列表时就已经确认过断点列表是按照升序排列的了。这里的min,max指的是当前选中等级的区间左右值。所以这两个函数都包含$name参数,当对“md”分别应用这两个函数时,得到的值将是768px(min)和991px(max)。

这里有一个问题,当使用breakpoint-max()函数获取区间右值时,为了不与下一个断点数值上重合,所以进行了一个减一操作(官方的膜法)。

另外就是通过这个函数,能够知道新的Bootstrap4的一个小坑,在Bootstrap3中,是有等级xs的,代表极小,而在新版本中,由于xs设定值的特殊性(断点值为0),所以从宽度定义上,xs这个等级就被取消了,这里的min函数,在$name=“xs”的情况下将返回空值,这样就从数值上去掉了xs。在后面提到的breakpoint-infix函数中,将从类名定义层次上取消”xs”等级。

breakpoint-infix:

@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
  @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
}

核心函数,直接关系到类名的自动化生成。它的功能是利用前面breakpoint-min()函数,将断点名以“-name”的形式返回,即breakpoint-infix(“md”)将返回“-md”,换句话说,这个函数的作用就是给断点名前头加个短横线,等到时候需要循环创建列的时候,就可以利用这个函数动态生成诸如”.col-md-4”之类的类名了。

在这个函数中有一个判断,即如果breakpoint-min()函数返回的值是null,那么整个函数将返回一个空字符串,而在min函数中,只有等级为“xs”时,才会返回null,所以,在创建列的类名时,你将再也看不见“.col-xs-4”,取而代之的是”.col-4”。在从b3迁移至b4的时候,这一点要尤其注意。

media-breakpoint-up

media-breakpoint-down:

@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($name, $breakpoints);
  @if $min {
    @media (min-width: $min) {
      @content;
    }
  } @else {
    @content;
  }
}
@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
  $max: breakpoint-max($name, $breakpoints);
  @if $max {
    @media (max-width: $max) {
      @content;
    }
  } @else {
    @content;
  }
}

关于media的都用@mixin定义,而不是前面的@function了。这里的两个mixin,功能也简单,就是利用前面提到的breakpoint-minbreakpoint-max函数,定义变化节点的media query,这样在创建网格时,就能根据预先设定的几个等级来进行响应式变化了。这里的updown,可以理解成“大于(up)”、”小于(down)”,亲测,在后续的应用中,基本都是用的media-breakpoint-up。如果你打算重写Bootstrap,那么用用down好像也不错。

media-breakpoint-between

media-breakpoint-only:

@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($lower, $breakpoints);
  $max: breakpoint-max($upper, $breakpoints);

  @media (min-width: $min) and (max-width: $max) {
    @content;
  }
}
@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($name, $breakpoints);
  $max: breakpoint-max($name, $breakpoints);

  @if $min != null and $max != null {
    @media (min-width: $min) and (max-width: $max) {
      @content;
    }
  } @else if $max == null {
    @include media-breakpoint-up($name)
  } @else if $min == null {
    @include media-breakpoint-down($name)
  }
}

候补@mixin,分别代表两种宽度之间和仅在一种宽度下的情形。between好说,利用前面的updown两个@mixin表示在某个区间范围内的情形,可以用来跨等级,比如说给“sm”一种排版,然后给“md”到“xl”一种排版(真的有人会这么干吗?)。而only这个@mixin有些奇怪,在Alpha6中它将between包在了其中,在Beta中它也做了大致相同的事,只是多进行了一些判断。而且正如其函数名所示,它表示“仅”,直接把表达式写出来可能更直观,(前缀省略)

only(“md”)=between(“md”,”md”)

就是这样一种奇怪的函数,不排除在后续对Bootstrap进行拆解时会再见到它,不过目前,它对我们没什么用处。

综上,除了一些辅助函数,我们在后续的网格搭建中会用到的函数或者@mixin只有俩,一个是breakpoint-infix($name),一个是media-breakpoint-up($name)

_grid.scss

这里指的_grid.scss是指的mixins文件夹下的_grid.scss,而非根目录下的_grid.scss

关于这个@mixin集合,一言以蔽之,即,想建网格就靠它。
这是一个网格搭建的基础集合,但单靠它,我们还是创建不出Bootstrap引以为傲的12列网格系统的,想提前知道原因的话可以打开_grid-frameworks.scss文件先看看。

顺带一提,和Alpha6版本不同的是,_grid.scss删除了@mixin make-gutter(),大概是官方觉得写这么一个@mixin有点多此一举吧。

make-container:

@mixin make-container() {
  margin-right: auto;
  margin-left: auto;
  padding-right: ($grid-gutter-width / 2);
  padding-left:  ($grid-gutter-width / 2);
  width: 100%;
}

创建一个相对定位的容器,也就是大家熟悉的.container的本体……的一部分。嗯,是的,一部分。如果你新建了一个

在scss中写一个

.main{@include make-container();}

你创建的实际上是一个在Bootstrap中以“container-fluid”为类名的流体容器,仔细观察这个@mixin,你就会发现,它指定了容器宽度为100%,在实际的浏览器中的表现为横向全屏,任凭你调整浏览器的窗口大小,这一点都不会变(当然,它自带一个左右padding)。

make-container-max-width:

@mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) {
  @each $breakpoint, $container-max-width in $max-widths {
    @include media-breakpoint-up($breakpoint, $breakpoints) {
      max-width: $container-max-width;
    }
  }
}

一般不多带带使用,搭配上一个make-container,就能创建出大家熟悉的.container了(其实这一点在根目录下的_grid.scss就可以找到)。在这个@mixin里,它确定了width=$container-max-width(在变量中有定义),这就代表着根据这个@mixin创建出的容器,不会再像流体容器那样宽度随心所欲,而是呈阶梯性变化,某种程度上,这更符合我们的预期和使用习惯。

make-row:

@mixin make-row() {
  display: flex;
  flex-wrap: wrap;
  margin-right: ($grid-gutter-width / -2);
  margin-left:  ($grid-gutter-width / -2);
}

这里是一个很重要的变化,大家可以注意到,row这里的display变成了flex,这也是b4主要的改进之一,row这个基础构建的变化意味着整个b4框架在很大程度上都会建立在flexbox的基础上(IE8滚蛋吧)。

顺带吐个槽,大家可以注意到,make-row里的循环给每个row加上了一个负margin,大小也正是gutter/2,(即15px,如果你没改的话),目测是为了抵消创建容器(container)时padding的影响,所以说……嗯……当初为啥加个padding呢?

make-column-ready:

@mixin make-col-ready() {
  position: relative;
  width: 100%;
  min-height: 1px; 
  padding-right: ($grid-gutter-width / 2);
  padding-left:  ($grid-gutter-width / 2);
}

我很奇怪Bootstrap创建了这个@mixin却没有使用它,在后面的_grid-frameworks.scss中找到了原因,这个@mixin被替换成了一个占位符。这应该是目前内测版的一个小疏漏,后续版本要么删除这个@mixin,要么把占位符那一块进行更新。总之,这个@mixin我们先略过不谈。

make-col:

@mixin make-col($size, $columns: $grid-columns) {
  flex: 0 0 percentage($size / $columns);
  max-width: percentage($size / $columns);
}

嗯,列终于也变成flex布局了,以后等高列,元素垂直居中就很简单了。这里简单解释下这个@mixin,参数$size为整数,从1到12,它的列宽计算也正是基于此,通过$size/$columns得到占比,以这个百分数结果为列宽,这使得其具备一定的响应性。

顺带说明一下这个flexflex:0 0 这是个简写属性,它的具体意思为不放大也不缩小(对应情况为有剩余空间或剩余空间不足)的宽度(或主轴空间,一般为横向)为的flex元素。

这里也有一个小坑,我在刚开始测试时,以为make-col()就是12列布局的奥秘所在,于是创建了两个div,分别给它们加上make-col(4)make-col(8)

...
...
.side{
  @include make-col(4);
}
.main{
  @include make-col(8);
}

刚开始,它们也的确如我所想的呈1:2宽度分布,但是当我缩小窗口到一定程度的时候,惊恐地发现它们并没有折行,而是发生了重叠。

究其原因,就是出在这个make-col()上,首先,我们惯常是习惯在列上包一层rowrow中我们定义了flex-wrapwrap,理论上row中的元素在宽度不够时会折行,但是靠make-rol()定义的“.col-”的类(为什么没有前缀之前在infix中提过了)的宽度却是百分比数,换句话说,它的宽度永远是够的(row内的col宽度和永远小于等于100%),这样,当你的内容缩小到一定程度的时候,势必会出现溢出现象(容器宽度小于内容宽度)。当你手动调整,使其和大于12时,比如make-col(4)make-col(9),但这就相当于手动折行了,效果不算特别理想。

所以经过分析,实际使用中依然需要搭配前缀,比如大窗口下用md,而这个不带前缀的类则可以视作xs的替代品,在极小窗口下使用它,但不要多带带使用,不然在小窗口情况下,将会出现溢出情况,如果在页面元素多的情况下,影响会很大。

活在天堂的offset、push、pull,Alph6中存在而在Beta版中被删除,这里就不多做介绍了,愿它们一路走好

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/112563.html

相关文章

  • 挑逗Bootstrap4代码 - Grid(下)

    摘要:在这里面有一个新定义的类,它这个嵌入式展开后是,从结构可以看出来,它就是加在元素上的,可以取消列的默认间距。在这里我提供一个自定义的,名字也很简单。写的时候注意顺序,要按照升序排列,小的放在上面,即在上面,写反了将失效。 本文所引用的版本为Bootstrap 4 Beta版,阅读者请先下载好相关源文件。 时光荏苒,若后续版本代码发生变化,将看心情进行更新补充。如果你觉得本文不错,欢迎...

    fobnn 评论0 收藏0
  • bootstrap4源码阅读体会

    摘要:通过阅读发现了不少知识的盲点和误解,对有了更深入的理解。总结几点印象较深的体会,分享给大家。但是通过阅读源码改变了这种认识模块化很简单灵活,这是其优点,同时也是一个缺点。 欢迎到个人博客参观: 点击这里 bootstrap已经使用了很长时间,但是从来没有好好研究过其设计结构,春节期间闲来无事就阅读了源码。通过阅读发现了不少知识的盲点和误解,对css有了更深入的理解。总结几点印象较深的体...

    incredible 评论0 收藏0
  • bootstrap4.0 css架构

    摘要:原子性的默认变量一般是用来设置默认值,然后根据需求来覆盖的。语义化的变量名,值为直接的属性值。组件文件互不引用。组合有几个入口文件对组件进行按顺序的引入,形成不同的专用,形成完整可用的样式,注意引用顺序。 原子性 sass的默认变量一般是用来设置默认值,然后根据需求来覆盖的。覆盖的方式也很简单,只需要在默认变量之前重新声明下变量即可 存放变量的文件。语义化的变量名,值为直接的属性值。 ...

    solocoder 评论0 收藏0
  • 基于angular4+ng-bootstrap+bootstrap+scss的后台管理系统界面

    摘要:描述在刚才发布的不久,很多人不懂得怎么应用,直到现在也很多人不懂怎么用,于是我在余业时间做了这么一个后台管理系统页面,希望对大家有帮助从我个人的感觉来说,语法很舒服,上手起来也比较快可能是因为我有方面的经验吧,但同这些的思想有所不同,初学者 描述 在angular2刚才发布的不久,很多人不懂得怎么应用,直到现在也很多人不懂怎么用, 于是我在余业时间做了这么一个后台管理系统页面,希望对大...

    spacewander 评论0 收藏0
  • 基于angular4+ng-bootstrap+bootstrap+scss的后台管理系统界面

    摘要:描述在刚才发布的不久,很多人不懂得怎么应用,直到现在也很多人不懂怎么用,于是我在余业时间做了这么一个后台管理系统页面,希望对大家有帮助从我个人的感觉来说,语法很舒服,上手起来也比较快可能是因为我有方面的经验吧,但同这些的思想有所不同,初学者 描述 在angular2刚才发布的不久,很多人不懂得怎么应用,直到现在也很多人不懂怎么用, 于是我在余业时间做了这么一个后台管理系统页面,希望对大...

    Muninn 评论0 收藏0

发表评论

0条评论

wizChen

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<