本文所引用的版本為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的引用
- _grid-frameworks.scss
@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {
// Common properties for all breakpoints
%grid-column {
position: relative;
width: 100%;
min-height: 1px; // Prevent columns from collapsing when empty
padding-right: ($gutter / 2);
padding-left: ($gutter / 2);
}
@each $breakpoint in map-keys($breakpoints) {
$infix: breakpoint-infix($breakpoint, $breakpoints);
@for $i from 1 through $columns {
.col#{$infix}-#{$i} {
@extend %grid-column;
}
}
.col#{$infix},
.col#{$infix}-auto {
@extend %grid-column;
}
@include media-breakpoint-up($breakpoint, $breakpoints) {
.col#{$infix} {
flex-basis: 0;
flex-grow: 1;
max-width: 100%;
}
.col#{$infix}-auto {
flex: 0 0 auto;
width: auto;
max-width: none; // Reset earlier grid tiers
}
@for $i from 1 through $columns {
.col#{$infix}-#{$i} {
@include make-col($i, $columns);
}
}
@for $i from 1 through $columns {
.order#{$infix}-#{$i} {
order: $i;
}
}
}
}
}
整個檔案只有一個@mixin make-grid-columns()
,這個@mixin
才是真正的搭建12列Grid網格系統的核心,讓我們細細來拆解。
首先是引數,引入了列數($columns
)、列間距($gutter
)、斷點列表($breakpoints
)。這三者都已經預設好了,不需要操心。
%grid-column {
position: relative;
width: 100%;
min-height: 1px;
padding-right: ($gutter / 2);
padding-left: ($gutter / 2);
}
下面是佔位符%grid-column
,這個在之前講make-col-ready()
時已經講過了,出於減小css體積的考慮,佔位符在這裡顯然優於@mixin
。那麼這裡定義的就是一個列的基本屬性,而min-height
的設定也是考慮到當列為空時不至於坍縮。
@each $breakpoint in map-keys($breakpoints) {}
接下來是一個大迴圈,這個迴圈的根本目的在於為不同的斷點加上相匹配的類,它的迴圈依據就是斷點名。
$infix: breakpoint-infix($breakpoint, $breakpoints);
讓我們以“md
”為例進入這個迴圈,首先是$infix
變數,結合先前的知識,我們瞭解到,這個$infix
的值將是”-md
”,讓我們記住它,接下來,又是一個小迴圈。
@for $i from 1 through $columns {
.col#{$infix}-#{$i} {
@extend %grid-column;
}
}
這個@for
迴圈的目的,就是為了建立12列的基本屬性,因為所有的列都具備%grid-column
定義的基本屬性,所以我們將這份共性總結出來,單獨設定一個迴圈進行類名構建,當這個迴圈結束,你就可以看到css裡出現了用逗號相連的col-md-1
一直到col-md-12
.col-md-1, .col-md-2, .col-md-3,
.col-md-4, .col-md-5, .col-md-6,
.col-md-7, .col-md-8, .col-md-9,
.col-md-10, .col-md-11, .col-md-12,
{ position: relative; width: 100%; min-height: 1px; padding-right: 15px; padding-left: 15px; }
它們都有著同樣的屬性,這也是@extend
的好處。但是請注意,我們並沒有設定這些列的寬度,所以它們現在還是不可用的狀態。
.col#{$infix},
.col#{$infix}-auto {
@extend %grid-column;
}
接下來有一個單獨的小傢伙,通過它,你可以發現.col-md
這個類也出現了,也是同樣的屬性,這個我們就先不去管它了。
@include media-breakpoint-up($breakpoint, $breakpoints) {}
接下拉就是大頭了,我們引入了media-brakpoint-up()
函式,拿到了media查詢的外包裝
@media (min-width:768px){}
花括號裡就是我們要往這個外包裝裡塞的內容了。
.col#{$infix} {
flex-basis: 0;
flex-grow: 1;
max-width: 100%;
}
首先是一個小傢伙,又是這貨,它單獨給col-md
定義了一些flex
屬性,它的意思表明,當“.col-md
”出現的時候,它將撐滿整行剩餘的空間。
.col#{$infix}-auto {
flex: 0 0 auto;
width: auto;
max-width: none;
}
接下來定義了“.col-md-auto
”類,這個類挺奇葩,寬度隨著內容走,跟列寬毛關係都沒有。
@for $i from 1 through $columns {
.col#{$infix}-#{$i} {
@include make-col($i, $columns);
}
}
接下來的@for
迴圈就開始定義我們的列寬了,利用make-col()
,我們得到了從col-md-1
到col-md-12
各種不同的列寬。
@for $i from 1 through $columns {
.order#{$infix}-#{$i} {
order: $i;
}
}
最後的這個@for
迴圈也是從1到12遍歷一次,熟悉flex
的同學會知道,新增的這個order
屬性就相當於名次,數值越小越靠前,而在flex
佈局下的12列Grid也正是依靠這一點來對不同的列進行排序的。
至此,“
md
”下的12列Grid框架構建完成。依次類推,其它的斷點列也都是如此生成的。比較特殊的還是斷點”xs
”,由於先前提到的原因,最小的那一部分是沒有字首的,所以你在css裡看到的.col-[1-12]
就可以視作.col-xs-[1-12]
,這需要適應一下。
_grid.scss (根目錄)
自動化構建其它諸如”.container
”之類的元素,那個$enable-grid-classes
布林值,在變數裡的第126行,預設為ture
。
$enable-grid-classes: true !default;
換句話說,如果你哪天心情不好,不想用bootstrap的網格系統了,直接把這裡改成false
就行。
@if $enable-grid-classes {
.row {
@include make-row();
}
.no-gutters {
margin-right: 0;
margin-left: 0;
> .col,
> [class*="col-"] {
padding-right: 0;
padding-left: 0;
}
}
}
在這裡面有一個新定義的類“.no-gutter
”,它這個嵌入式展開後是“.no-gutter>col
,.no-gutter>[class*=”col-”]
”,從結構可以看出來,它就是加在row
元素上的,可以取消列的預設間距。
使用建議
說回我們的Grid,我們知道,如果不加以控制,那麼Bootstrap在編譯Scss的時候會自動生成所有斷點下的列,如果你不打算給每個等級都用上一種佈局,那麼自動編譯的Scss將會產生大量冗餘的css程式碼。
.col-1, .col-2, .col-3,
.col-4, .col-5, .col-6,
.col-7, .col-8, .col-9,
.col-10, .col-11, .col-12,
.col, .col-auto,
.col-sm-1, .col-sm-2, .col-sm-3,
.col-sm-4, .col-sm-5, .col-sm-6,
.col-sm-7, .col-sm-8, .col-sm-9,
.col-sm-10, .col-sm-11, .col-sm-12, .col-sm, .col-sm-auto,
.col-md-1, .col-md-2, .col-md-3,
.col-md-4, .col-md-5, .col-md-6,
.col-md-7, .col-md-8, .col-md-9,
.col-md-10, .col-md-11, .col-md-12,
.col-md, .col-md-auto,
.col-lg-1, .col-lg-2, .col-lg-3,
.col-lg-4, .col-lg-5, .col-lg-6,
.col-lg-7, .col-lg-8, .col-lg-9,
.col-lg-10, .col-lg-11, .col-lg-12,
.col-lg, .col-lg-auto,
.col-xl-1, .col-xl-2, .col-xl-3,
.col-xl-4, .col-xl-5, .col-xl-6,
.col-xl-7, .col-xl-8, .col-xl-9,
.col-xl-10, .col-xl-11, .col-xl-12,
.col-xl, .col-xl-auto
比如我只想做桌面端和手機端兩種適配,那麼我可能只需要lg
和sm
的列,css中其它的列程式碼對我是沒用的。所以面對這種情況,我們就需要對Bootstrap進行修改。這裡提供兩種化用方式,如果你有其它的主意,也歡迎在評論區留言。
- 在變數檔案中註釋掉不需要的列,與之對應的容器等級也不要忘記
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
//lg: 992px,
//xl: 1200px
) !default;
$container-max-widths: (
sm: 540px,
md: 720px,
//lg: 960px,
//xl: 1140px
) !default;
這是一種很簡單的方式,也很直觀,我需要什麼列就用什麼列,不需要的我就給扔掉,但是注意,別扔掉預設值為0的xs
。如果你不是前端潔癖患者,只是想縮減css體積,那麼推薦用這種方式。
- 自己新建一個
@mixin
,替換掉預設的迴圈建立行為
第一種方式有一個問題,即雖然你註釋掉了不需要的列,但仍需要在HTML中寫入預設的類名。如果你不希望在HTML中寫入一堆以”col-
”開頭的類名,那麼就嘗試自己定義一個@mixin
,來建立自己的列吧。
建立之前注意,在bootstrap-grid.scss
中將@import “grid”
註釋掉,我們們不需要自動建立。
其次,新建一個scss檔案,引入bootstrap-grid
。
@import "bootstrap-grid"
%grid-column{
position: relative;
width: 100%;
min-height: 1px;
padding-left: ($grid-gutter-width/2);
padding-right: ($grid-gutter-width/2);
}
@mixin make-my-col($breakpoint:null,$size:null,$breakpoints: $grid-breakpoints){
@extend %grid-column;
@include media-breakpoint-up($breakpoint,$breakpoints){
@include make-col($size,$grid-columns);
}
}
在這裡我提供一個自定義的@mixin
,名字也很簡單make-my-col
。包含兩個引數,一個是$breakpoint
(斷點名),一個是$size
(列寬)。這個@mixin
其實是make-grid-columns()
的簡化版。
具體原理不用多說了,因為是自用,所以我就沒去考慮引數驗證的問題。如果你有這方面的需求,要應用到專案中,可以考慮加上引數驗證。
呼叫也很簡單,在你需要的類中直接呼叫即可,傳入斷點名和列寬,就能建立在對應視寬下的列了。
@import "bootstrap-grid";
.side{
@include make-my-col(sm,2);
@include make-my-col(md,6);
}
.content{
@include make-my-col(sm,10);
@include make-my-col(md,6);
}
P.S.寫的時候注意順序,要按照升序排列,小的放在上面,即sm在md上面,寫反了md將失效。
這種方式同樣有一個問題,在小型專案中,這樣編譯出的css能顯著縮減css的體積。但在大型專案中,各種類名交錯混雜,利用這種建立單個列的方式,最後生成的css程式碼不見得比bootstrap預定義的類名更好,所以請規範命名,一些容器元素最好保持固定寬度和固定變化。
Scss顯然是利用Bootstrap更高效的方式,根據需求,以上兩種方式可任選其一。當然,如果你有其它的利用方式,也可以隨心所欲地蹂♂躪Bootstrap~
總結
“好的程式碼像一首詩”
以前對這句話只覺得莫名高大上,卻沒有多少感觸。而在閱讀了Bootstrap用Scss寫的原始碼之後,卻是真切地感受到了這一點。開啟變數(_variables.scss
)檔案的時候,帶給我的震驚是不可言表的。嚴謹而有序,體量龐大而層次井然。這些模組如果一個個看下來,相信會獲益良多。所以如果你和我一樣,是Scss的初學者,那麼瀏覽一下Bootstrap的原始碼,絕對會爽翻。
Grid應該是Bootstrap的核心區塊了,從這裡入手雖然比較難,但是方便從根本上了解Bootstrap的執行方式。
總的來說,Beta版本的Bootstrap4相比於Alpha版本已經往前邁了一大步,告別了傳統盒模型的佈局方式,轉身擁抱flexbox
,同時刪去了很多以前的殘餘程式碼,在初期,習慣使用b3的同學可能會覺得不大適應,具體表現是
“哎?我寫了這個類咋沒反應啊?”
眼下這個時候,官方說明文件都不見得會同步更新,看原始碼才是最直接的閱讀學習方式。
Grid篇到此結束,謝謝閱讀,歡迎指出本文的錯漏之處,前端新手上路,請多指教。