---
# System prepended metadata

title: Bootstrap 5 如何客製化自己的樣式

---

# Bootstrap 5 如何客製化自己的樣式

### 原始碼

先來看看 Bootstrap 5 的 scss 原始碼怎麼組成的，才能方便的進行客製化，所謂知己知彼，百戰不殆。

#### [Bootstrap 5 Repository](https://github.com/twbs/bootstrap/tree/main/scss)
![](https://i.imgur.com/gljKneC.png)

#### [Bootstrap 4 Repository](https://github.com/twbs/bootstrap/tree/v4-dev/scss)
![](https://i.imgur.com/E9D1zf6.png)

跟 Bootstrap 4 一樣可以依照自己想要用的功能引入相對的 scss，如同匡起來的部分。但眼尖的朋友應該發現 Bootstrap 5 多出了 bootstrap-utilities.scss 吧，這就是這次的重點，等等會講到。

#### 1. bootstrap-grid.scss
如果只想要用到 Bootstrap 5 格線系統，在自己的專案裡引入這個就可以了。

#### 2. bootstrap-reboot.scss
這支是 Bootstrap 裏面只有載入 reboot.scss 用來初始化 css 樣式，以便統一且一致性的建立樣式。是基於 Normalize.css 上進行規劃的，有需要的話，也可以單獨引入專案中。

#### 3. bootstrap.scss
所有的元件載入，包含格線系統、按鈕、手風琴、表單等等。什麼都要的話，直接引入到專案中是最方便的了，缺點就是很大一包。

#### 4. bootstrap-utilities.scss
這將會是重點中的重點，Bootstrap 5 利用了 scss 的 map-merge 定義了很多通用類別，而且強化了他的功能，讓我們可以單獨只引入這包來進行使用，與 Tailwind 不同的地方在於，他幾乎不用到 Javasript 就可以工具化許多 css 樣式。並且我們可以透過修改或覆蓋 utilities 來針對工具的客製化跟調整，是很讚讚的改變！！

### 建立客製化 scss 檔案

透過觀察 bootstrap.scss，我們知道說其實只要載入必須載入的 SCSS 檔案，其餘的只要用到再載入就好，這樣做的好處是可以減少打包後的大小，客製化自己的需求。([官網](https://getbootstrap.com/docs/5.0/customize/sass/#importing)也是這樣建議)

專案大概會長這樣(請依據需求調整)

```
project/
┣ node_modules/
┣ public/
┣ scss/
┃ ┗ customize.scss
┣ index.html
┣ package-lock.json
┗ package.json
```

建立 customize.scss 管理所有 scss 元件的入口，包含 Bootstrap 5 元件、變數覆蓋、utilities 甚至我們額外寫的 scss 檔。

:::warning
此處的作法用 npm 安裝 Bootstrap 5 後引入專案中。SCSS 編譯這邊就不多說了，自行用 gulp 或是 webpack 來實現。
:::

### 必須引入的 scss 檔案
 
```css=
// customize.scss
// 引入 bootstrap 預設的 variables、functions、 mixins
// 我們同時可以運用裡面的 function、mixins 來精簡我們的 scss 內容，color, svg, media-breakpoint-up 等
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";
```

在客製化 bootstrap 前，這三支檔案是必須引入的，需要載入他本身設定好的 functions、mixins、variables，以便元件的運用跟計算。

引入順序很重要，**function 一定要在 variables 前面**，因為 variables 裡面有用到 function 的方法。

#### 剩餘的元件或格線系統依照需求引入:

```css=
// Require
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";

// Optional
// Layout & components
@import "../node_modules/bootstrap/scss/root";
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
@import "../node_modules/bootstrap/scss/images";
@import "../node_modules/bootstrap/scss/containers";
@import "../node_modules/bootstrap/scss/grid";
@import "../node_modules/bootstrap/scss/forms";
@import "../node_modules/bootstrap/scss/badge";
@import "../node_modules/bootstrap/scss/buttons";
@import "../node_modules/bootstrap/scss/transitions";
@import "../node_modules/bootstrap/scss/nav";
@import "../node_modules/bootstrap/scss/navbar";
// ...etc

```

> root 這支建議載入，他會定義原生的 css 變數在瀏覽器的全域環境。

### SCSS 變數新增修改

基本上，我們可以透過覆蓋或是直接修改它 `_variables.scss` 中的變數來實現客製化的需求。

#### default 是什麼？

在修改變數前，先來談談 default 這個在 scss 關鍵字是起到什麼作用，簡單來說，他就是預設值。

範例：

```css=
$var : null;
$var : #777 !default;

p {
  color : $var; /* color: #777; */
}
```

當 $var 是 null 或是沒有定義時，他會是預設值。

```css=
$var : #888;
$var : #777 !default;

p {
  color : $var; /* color: #888; */
}
```

但是若 $var 是已經有值了，那預設值就不會指定。

----

#### 看一下 bootstrap 5 的 variables.scss

![](https://i.imgur.com/533RrBf.png)

發現他裡面的變數幾乎都是預設值，所以我們可以輕易的從外面進行修改。

#### 建立 variable.scss 來覆蓋裡面的變數

##### 專案結構
```
project/
┣ node_modules/
┃ ┣ @popperjs/
┃ ┣ bootstrap/
┃ ┗ .package-lock.json
┣ public/
┣ scss/
┃ ┣ variable.scss // 自定義的 variable.scss
┃ ┗ customize.scss
┣ index.html
┣ package-lock.json
┗ package.json
```
```css=
// customize.scss

@import "./variables";   // 自定義的變數 scss 檔
$primary: red;           // 若是修改的變數很少，也可以直接宣告

// Require
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";

// Optional...
```

官方文件有說，只能在載入 bootstrap 的 variables.scss 前作修改，不然部分樣式會變更無效。為什麼？

查看 bootstrap 的 variables.scss 可以發現，

![](https://i.imgur.com/YRVr25A.png)

他把變數一路指定下來，到 theme-colors-map 中，所以程式碼一行行執行時，還沒跑到我們自定義的變數時，他的主題顏色就被先指定了。

因此官方才建議自定義變數放到 bootstrap 的 variables.scss 前，當然如果後面也自定義 theme-colors-map 來修改內容，就可以把變數修改放後面了。

* 若你是整包載下來，也可以直接修改 bootstrap 的 variables.scss 變數內容。

### utilites 介紹

關鍵來了，Bootstrap 5 新增了這個通用類別工具，運用方式[官網有詳細說明](https://getbootstrap.com/docs/5.0/utilities/api/)，我們這邊就來看看他是怎麼實現的，以及我們該如何修改或新增自己的工具。([六角](https://bootstrap5.hexschool.com/docs/5.0/utilities/api/))
#### scss map 變數管理

Bootstrap 5 巧妙的運用 scss 的 map、each 以及 if 把所有的 utilites 工具宣告出來。
#### utilities

```css=
$utilities: map-merge(
  "display": (
    responsive: true,
    print: true,
    property: display,
    class: d,
    values: inline inline-block block grid table table-row table-cell flex inline-flex none
  ),
  "rounded": (
    property: border-radius,
    class: rounded,
    values: (
      null: $border-radius,
      0: 0,
      1: $border-radius-sm,
      2: $border-radius,
      3: $border-radius-lg,
      circle: 50%,
      pill: $border-radius-pill
    )
  )
)
```

利用了 map-merge 統一了所有 map，並在 map 中也可以再定義 map，形成一個類似於 JSON 格式的變數，差別在於大括號換成小括號而已。

utility map 包含了通用類群組的鍵值清單，這些清單接受以下選項：


| 選項 | 類型 | 介紹 |
| -------- | -------- | -------- |
| property     | 必要     | 屬性的名稱，可以是字串或是字串陣列 ( 例如，水平的 padding 或 margin )。     |
| values     | 必要     | 清單中的值或 map，在您不希望 class 名稱與值相同時使用。如果將 null 作為 map 鍵值，則不會編譯它。     |
| class     | 可選     | 當您不希望 class 名稱與屬性相同時所使用的變數。如果您不提供 class 鍵值，且 property 鍵值是字串陣列，則 class 名稱將是 property 陣列的第一個元素。     |
| state     | 可選     | 為通用類別生成的虛擬類別類清單，像是 :hover 或 :focus。沒有預設值。     |
| responsive     | 可選     | 用於指示是否要生成響應式類別的布林值。預設值為 false。     |
| rfs     | 可選     | 用於啟用流體縮放的布林值。可以查看 RFS 頁面以了解如何運作。預設值為 false。     |
| print     | 可選     | 用於指示是否要生成 print 類別的布林值。預設值為 false。     |
| rtl     | 可選     | 用於指示是否要將通用類別保留於 RTL 中的布林值。預設值為 true。     |

* 參考：[六角 Bootstrap 5 API 文件](https://bootstrap5.hexschool.com/docs/5.0/utilities/api/)

#### utilities/api.scss

$utilities 定義完成後，必須引入 utilities/api.scss，這支 scss 會幫我們把所有的 $utilities 裡定義的 map，轉換成 scss。 主要是運用 @each 跑過所有的 map，
再運用 @if 判斷 print 或 responsive 設定 $infix，最後呼叫定義好的 generate-utility 這支 mixin 來產生對應的 css。(詳細內容請參閱[原始碼](https://github.com/twbs/bootstrap/blob/main/scss/utilities/_api.scss)。)

```css=
// customize.scss

@import "./variables";   // 自定義的變數 scss 檔

// Require
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";

// Optional...
// ...載入自己需求的 scss 組件

// utilites
@import "../node_modules/bootstrap/scss/utilities";
// utilites/api
@import "../node_modules/bootstrap/scss/utilities/api";

```

### utilities api 說明

以下都可以在[官網](https://getbootstrap.com/docs/5.0/utilities/api/)或[六角](https://bootstrap5.hexschool.com/docs/5.0/utilities/api/)找到，就列出比較常用的來做範例。

#### 1. 簡單運用
```css
$utilities: (
  "height": (
    property: height,
    values: (
      25: 25%,
      50: 50%,
      75: 75%,
      100: 100%,
      auto: auto
    )
  ),
 );
```
輸出：
```css
.height-25 { height: 25%; }
.height-50 { height: 50%; }
.height-75 { height: 75%; }
.height-100 { height: 100%; }
.height-auto { height: auto; }
```

#### 2. 加入 class 生成對應的前綴

```css
$utilities: (
  "height": (
    property: height,
    class: h, // class 對應前綴
    values: (
      25: 25%,
      50: 50%,
      75: 75%,
      100: 100%,
      auto: auto
    )
  ),
 );
```
輸出：
```css
.h-25 { height: 25%; }
.h-50 { height: 50%; }
.h-75 { height: 75%; }
.h-100 { height: 100%; }
.h-auto { height: auto; }
```

#### 3. 加入 responsive 生成對應斷點的 css 樣式

```css
$utilities: (
  "height": (
    property: height,
    class: h, // class 對應前綴
    responsive: true,
    values: (
      25: 25%,
      50: 50%,
      75: 75%,
      100: 100%,
      auto: auto
    )
  ),
 );
```
輸出：
```css
.h-25 { height: 25%; }
.h-50 { height: 50%; }
.h-75 { height: 75%; }
.h-100 { height: 100%; }
.h-auto { height: auto; }

@media (min-width: 576px) {
  .h-sm-25 { height: 25%; }
  .h-sm-50 { height: 50%; }
  .h-sm-75 { height: 75%; }
  .h-sm-100 { height: 100%; }
  .h-sm-auto { height: auto; }
}

@media (min-width: 768px) {
  .h-md-25 { height: 25%; }
  .h-md-50 { height: 50%; }
  .h-md-75 { height: 75%; }
  .h-md-100 { height: 100%; }
  .h-md-auto { height: auto; }
}

@media (min-width: 992px) {
  .h-lg-25 { height: 25%; }
  .h-lg-50 { height: 50%; }
  .h-lg-75 { height: 75%; }
  .h-lg-100 { height: 100%; }
  .h-lg-auto { height: auto; }
}

@media (min-width: 1200px) {
  .h-xl-25 { height: 25%; }
  .h-xl-50 { height: 50%; }
  .h-xl-75 { height: 75%; }
  .h-xl-100 { height: 100%; }
  .h-xl-auto { height: auto; }
}

@media (min-width: 1400px) {
  .h-xxl-25 { height: 25%; }
  .h-xxl-50 { height: 50%; }
  .h-xxl-75 { height: 75%; }
  .h-xxl-100 { height: 100%; }
  .h-xxl-auto { height: auto; }
}
```

#### 4. 加入 state 生成對應狀態的 css 樣式

```css=
$utilities: (
  "height": (
    property: height,
    class: h,
    state: hover,
    values: (
      25: 25%,
      50: 50%,
      75: 75%,
      100: 100%,
      auto: auto
    )
  ),
 );
```
輸出：
```css=
.h-25-hover:hover { height: 25%; }
.h-50-hover:hover { height: 50%; }
.h-75-hover:hover { height: 75%; }
.h-100-hover:hover { height: 100%; }
.h-auto-hover:hover { height: auto; }
```

### utilites 新增修改

先來看看 Bootstrap 5 做了件很貼心的動作：

![](https://i.imgur.com/uAEkoVY.png)

他把 utilites 變數，定義為預設值，這就代表說，我可以在外面直接用 utilites 變數宣告客製化的通用類別了，但是如果我在外面自己定義後，他這邊的通用類別不就會失效了嗎？

來看看他怎麼解決的：

![](https://i.imgur.com/EUssvGj.png)

> 1. 有想過為什麼他要設定兩個 utilites 變數嗎？
> 2. 為什麼第二個 utilites 最底下會有一個 utilites？
> 
> 第一個 utilites 他其實是預設值，可以給我們外面覆蓋使用的。第二個就不是預設值了，他是用來 merge 第一個 utilites 和 Bootstrap 本身定義好的通用類別。

1. 在 Bootstrap 本身的 utilities 後面

自定義的 utilities 最好是放在 Bootstrap 本身的 utilities 後面，這樣才能覆蓋住修改過的通用類別。

```css=
// customize.scss

@import "./variables";   // 自定義的變數 scss 檔

// Require
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";

// Optional...
// ...載入自己需求的 scss 組件

// bootstrap 的 utilites
@import "../node_modules/bootstrap/scss/utilities";

// 自定義的 utilites
$utilities: map-merge(
  $utilities, // bootstrap utilites 一定要引入，不然會沒辦法使用原本的通用類別
  (
    "object-fit": (
      property: object-fit,
      class: o-f,
      responsive: true,
      values: contain cover grab,
    ),
    "BalooTamma2": (
      property: font-family,
      class: ff,
      values: (
        bt2: "Baloo Tamma 2"
      ),
    ),
    "margin2": ( // 因為有 margin 所以用 margin2 
      responsive: true,
      property: margin,
      class: m,
      values: (
        100: 100px, // 新增 margin: 100px
        auto: auto  // 覆蓋或修改  margin: auto
      )
    ),
  )
);

// utilites/api 一定要在最後引入，會用到 mixins 跟 variables 定義的內容
@import "../node_modules/bootstrap/scss/utilities/api";

```

* map 變數宣告跟 bootstrap 的必須不一樣，但是產出的類別可以一樣，他會在 @each 都跑過一遍，依照 css 權重，相同層級設計，後面會覆蓋前面的。

* 自定義的 $utilities map 一定要在第一個引入 bootstrap 預設的 $utilities，這樣後面定義相同的通用類別時才可以覆蓋。


2. 在 Bootstrap 本身的 utilities 前面

  那如果要放在前面也可以，自定義的 $utilities map 就可以不用在第一個放入 bootstrap 的 $utilities，因為你放在前面後，再前面根本沒有宣告過，會報錯。
  在 bootstrap utilities.scss 中，他會把你前面定義的 $utilities 放在最後，來覆蓋他本來的樣式。

```css=
// customize.scss

@import "./variables";   // 自定義的變數 scss 檔

// Require
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";

// Optional...
// ...載入自己需求的 scss 組件


// 自定義的 utilites
$utilities: map-merge(
  (
    "object-fit": (
      property: object-fit,
      class: o-f,
      responsive: true,
      values: contain cover grab,
    ),
    "BalooTamma2": (
      property: font-family,
      class: ff,
      values: (
        bt2: "Baloo Tamma 2"
      ),
    ),
    "margin2": ( // 因為有 margin 所以用 margin2 
      responsive: true,
      property: margin,
      class: m,
      values: (
        100: 100px, // 新增 margin: 100px
        auto: auto  // 覆蓋或修改  margin: auto
      )
    ),
  )
);
// bootstrap 的 utilites
@import "../node_modules/bootstrap/scss/utilities";


// utilites/api 一定要在最後引入，會用到 mixins 跟 variables 定義的內容
@import "../node_modules/bootstrap/scss/utilities/api";

```

* 在那邊修改，所呈現的形式會不太一樣。
* **map 的名稱不要跟 bootstrap 的重複，會蓋掉本來的設定。** 至於為什麼會蓋掉，自行去看 scss 的官方文件囉。

### 結論

這些都是依照官網的建議做修正的，當然如果不怕改壞掉也可以直接載下來針對 utilities 和 variables 進行修改。variables 的客製化最好寫在 bootstrap 的 variables 前面。utilities 修改要注意是在 bootstrap 的 utilities 前還是後，會稍微不一樣。最簡單的方式就是在引入 bootstrap 前，把要客製化的 scss 先定義好囉。