製作成品:
- GitHub Pages (展示頁面、樣式文件)
- GitHub Link
前言
近期應六角學院針對疫情所推的公益活動,主要針對要入門或對 Bootstrap 5 有興趣的人所規劃活動,我自已本人是屬於後者,對於 Bootstrap 4 與 5 版想了解新功能與主要差異,因而設入此活動一窺究竟。
此外,近期也花了些時間了解了 webpack 與相關 npm 管理與應用,將站台內所需的資源與設定透過這個 side project 實現與實作出來。
Bootstrap 5
CSS 底層
CSS 變數定義與運用全域或區域 (色彩與字體廷伸運用於模組)
將主要使用重覆性高的設定,除了 SCSS 定義變數外,也將設定值以 CSS 的 :root 變數做為編譯後的同用設定值,如果在沒有透過 SCSS 撰寫的情形下,直接針對 CSS 變數修改也可以達到全域或區塊修改的目地。
- 宣告 CSS 變數: --<名稱>: <值>;
- 使用 CSS 變數: <CSS 屬性>:var(--<名稱>, <預設值>); (預設值不一定要填)
對於原生 CSS 的變數分為 :root 全域與區域寫法,使用方式可參考 oxxostudio-深入理解 CSS 變數 ( CSS Variables ) 一文。
基本上單純的字體設定就直接取用 CSS :root 變數設定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | :root { --bs-blue: #0d6efd; --bs-indigo: #6610f2; --bs-purple: #6f42c1; --bs-pink: #d63384; --bs-red: #dc3545; --bs-orange: #fd7e14; --bs-yellow: #ffc107; --bs-green: #198754; --bs-teal: #20c997; --bs-cyan: #0dcaf0; --bs-white: #fff; --bs-gray: #6c757d; --bs-gray-dark: #343a40; --bs-primary: #0d6efd; --bs-secondary: #6c757d; --bs-success: #198754; --bs-info: #0dcaf0; --bs-warning: #ffc107; --bs-danger: #dc3545; --bs-light: #f8f9fa; --bs-dark: #212529; --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); } |
以 CSS 變數在 Bootstrap 5 中使用,可見到
<table class="table table-dark table-borderless"> 的組合樣式中查看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | .table { --bs-table-bg: transparent; --bs-table-striped-color: #212529; --bs-table-striped-bg: rgba(0, 0, 0, 0.05); --bs-table-active-color: #212529; --bs-table-active-bg: rgba(0, 0, 0, 0.1); --bs-table-hover-color: #212529; --bs-table-hover-bg: rgba(0, 0, 0, 0.075); width: 100%; margin-bottom: 1rem; color: #212529; vertical-align: top; border-color: #dee2e6; } |
在 .table 的基本樣式中,直接使用 CSS 宣告變數的方式在模組的最外層宣告。
在同層元素上使用 .table-dark 樣式。
1 2 3 4 5 6 7 8 9 10 11 | .table-dark { --bs-table-bg: #212529; --bs-table-striped-bg: #2c3034; --bs-table-striped-color: #fff; --bs-table-active-bg: #373b3e; --bs-table-active-color: #fff; --bs-table-hover-bg: #323539; --bs-table-hover-color: #fff; color: #fff; border-color: #373b3e; } |
透過權重方式把 .table 的 --bs-table-bg: transparent; 改成 --bs-table-bg: #212529;,讓模組的最外層宣告出 CSS 區域變數。
在 HTML 結構中的 table > thead > tr > th 元素上,可見到樣式如下。
1 2 3 4 5 6 | .table>:not(caption)>*>* { padding: .5rem .5rem; background-color: var(--bs-table-bg); border-bottom-width: 1px; box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg); } |
巧妙的將 .table 下的後代,以 var(--bs-table-bg) 最例使用 var() 取 CSS 變數值的方式,運用於 table 裡的所有的元素上。
單位以 rem 為主
在 Bootstrap 4 可使用單位值 xp 直接於 variables.scss 設定於變數,但到了 bootstrap 5 時 _variables.scss 檔的使用定義不太相同,因為後面有許多的 SCSS 變數要承接前面的 SCSS 變數設定,如果要擴充通用類別樣式進行客製化的話,最好是直接在 Bootstrap 5 的 API 設定 _utilities.scss 檔,對於級數和單位都可做不同的自定義與設定。
Bootstrap 文件:間隔 (Spacing)
RFS 依裝置大小變化的字級段落變化
bootstrap 文件:RFS 裡面提到。
什麼是 RFS?
Bootstrap 的附帶項目 RFS 是一個單元的縮放調整引擎,最初是為了調整字體大小而開發的 (因此縮寫為 Responsive Font Sizes)。如今 RFS 能夠使用單位數值來縮放大多數的 CSS 屬性,諸如 margin、 padding、 border-radius、甚至 box-shadow 等。該機制會根據瀏覽器視窗的尺寸自動計算適當的值。它將使用 rem 和視窗單位組合編譯為 calc() 的函數,啟用響應式的縮放行為。
這裡簡單說就是,可對應不同裝置動自變數大小或空間,而在 Bootstrap 5 的 API 設定 _utilities.scss 檔中,可透過 rfs: true / false, 決定是否使用 RFS,而使用後會將 px 換算 rem。
格線系統
父層容器下樣式,設定內層容器間距
Gutters 欄間距:.g-*
、.gx-*
、.gy-*
bootstrap 文件:Gutters
控制 gutter 的寬度,主要用於格線系統的三劍客 .row 同層為主,可操作 .col 見的 margin 的正負值,以水平、垂直、行列的方式設定。
增加 .container
與斷點 xxl
與 bootstrap 4 比較,多了 xxl 於 1400px 的斷點設定可使用。
齊頭、齊尾排版與佈局 (flex & text-align & spacing):left
=> start
、right
=> end
通用類別 (utilities) 中的文字與 flex 的相關命名上,統一以 -start 與 -end 來對應齊頭、齊尾的設定。
為何說是對應齊頭、齊尾的設定呢?對於我來說用來幫助記憶,在 flex 的設定上有軸線與方向的問題,這樣的名稱上不直觀但表達上可以比較貼合語意。
原先在 bootstrap 4 以 .text-left 的屬性設定 text-align: left,也統一命名為 .text-start。
相關的像是 .ml-x 等也以 start 的簡寫 s 取代,寫在 .ms-x 的方式應用。
Utilities API:自訂通用類別 (工具型樣式)
API 的自訂設定,大大增加了 css 客製的方便,以這次實作的 _utilities.scss 自訂設定 .font 說明 (GitHub 連結)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $utilities: () !default; $utilities: map-merge( ( "font-family": ( property: font-family, class: font, values: ( monospace: var(--#{$variable-prefix}font-monospace), NotoSansTC: ('Noto Sans TC', sans-serif), BalooTamma2: ('Baloo Tamma 2', cursive), ) ) // scss-docs-end utils-visibility ), $utilities ); |
- "font-family":SCSS map-merge() 叢集方法下的名稱。
- property: font-family,:CSS 設定的屬性名稱。
- class: font,:編譯 CSS 後的樣式名稱 .font。
- values: ():裡面帶有屬性名稱與值。
- monospace: var(--#{$variable-prefix}font-monospace):是將 SCSS 定義的變數名稱 $variable-prefix 做為 CSS :root 設定裡的 CSS 全城變數名稱與設定,所編譯後 CSS 的樣式名稱為 .font-monospace。
- NotoSansTC: ('Noto Sans TC', sans-serif):SCSS 與 JavaScript 表達示一樣以 () 執行後回傳結果,回傳出來的是字串用於 CSS 樣式設定的屬性值,所編譯後 CSS 的樣式名稱為 .font-NotoSansTC。
其他的設定可參考文件 API,有用到的部份如下。
- responsive:響應式類別的布林值,預設值為 false。
- rfs:用於啟用流體縮放的布林值,預設值為 false。如果不使用可設定 false,而啟用的計算單位為 rem,不啟用的情型下才可單純設定成固定值或特定單位,如 px、 em 等等…來使用。
JavaScript
移除 jQuery 相依
jQuery 函式庫在現今主流框架下不一定會用的到,而以 JavaScript 原生 Vanilla.js 寫法為主,這部份就自然被捨去。
HTML 標籤的 JavaScript 動態屬性 data-attribute
,data-xx
改成 data-bs-xx
data-toggle=”dropdown” 更換成 data-bs-toggle=”dropdown”,可更方便快速視別為 bootstrap 的賴件所使用,也可避免名稱衝突造成開發上除錯的不便。
前端套件
前端套件這部份與 npm 設定比較有關,這裡主要是將 icon font 字體檔做為模組引入 webpack 中使用,透過 webpack 的插件 CopyWebpackPlugin() 搬移一份到專案資料夾下的 /src/assets/fonts/ 編輯源資料夾中,在透過 loader: 'file-loader', 將相關字體檔的副檔名,搬移到相對的輸出資料夾下。
基本上只要用一套就好,這裡主要是要將整包的字體整合進專案中,以方便日後查看文件使用不同的圖示。
fortawesome
所使用的版號為 "@fortawesome/fontawesome-free": "^5.15.3",
material-design-icons
所使用的版號為 "material-design-icons": "^3.0.1"。
webpack 4
webpack 4 設定上比較多,這裡主要針對有處理的問題記錄。
webpack-dev-server 設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | module.exports = { devServer: { port: 3000, stats: { assets: true, // 加入資源訊息 cached: false, // 加入暫存(但未建構)模塊的信息 chunkModules: false, // 將建構模塊信息加入到 chunk 信息 chunkOrigins: false, chunks: false, // 加入 chunk 訊息(設置為 `false` 能允許較少的冗长輸出) colors: true, // 等同 `webpack --colors` hash: false, // 加入 compilation 的hash modules: false, // 加入建構模塊訊息 reasons: false, // 加入模塊被引入的原因 source: false, version: false, // 加入 webpack 版本信息 warnings: false, // 加入警告 }, /** * Reloading [WDS] Disconnected! Fix * 官方文件:https://webpack.docschina.org/configuration/dev-server/ * https://github.com/webpack/webpack-dev-server/issues/2199#issuecomment-522800528 * https://www.jianshu.com/p/85c0eb8f3b0f * https://andyyou.github.io/2015/07/23/webpack/ */ open: // false, { app: [ // 指定開啟瀏覽器 only one // 'Google Chrome', 'Firefox', // '--incognito', // 無痕模式 '--other-flag', ], }, overlay: { warnings: true, errors: true, }, // 編譯器錯誤或警告時全屏覆蓋 hot: false, // webpack 模块熱替換 inline: true, // false 瀏覽器路徑多 /webpack-dev-server/ 與狀態列 App ready. noInfo: true, // --no-info option // liveReload: false, writeToDisk: true, // 檔案形式輸出 dev-server 程式碼,設定 false 內容只會在記憶體中不會有實體檔案 compress: true, // 啟用 gzip 壓縮,預設 false }, } |
- writeToDisk: true,:在使用 webpack-dev-server 時,透過 loader 取得的相關檔案會以在記憶體中處理,而不會產生實體的檔案,這裡要使用 .sourcemap 的實體檔來查看 SCSS 編譯過程,沒啟用瀏覽器無法精確取得 .sourcemap 檔來除錯。
- inline: true,:會多 App ready 狀態列出來,而 HTML 不會在包一層 frame 將結構置於其中。
CSS 預處理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | module.exports = { devtool: (process.env.NODE_ENV === 'development') ? 'cheap-module-source-map' : 'false', module: { rules: [ { test: /\.(sass|scss)$/, use: extractCSS.extract([ { loader: 'css-loader', options: { sourceMap: true, // 開啟 sourcemap 支持 }, }, { loader: 'postcss-loader', options: { sourceMap: true, // 開啟 sourcemap 支持 }, }, { loader: 'sass-loader', options: { sourceMap: true, // 開啟 sourcemap 支持 }, }, ]), include: path.resolve('src/scss'), exclude: path.resolve('./node_modules'), }, ] } } |
處理 SCSS 的 .scss 檔的過程中,使用了 sass-loader、 postcss-loader、 css-loader 的 loader,裡面的參數設定都帶上 options: { sourceMap: true },,在轉化成 CSS 的 .css 檔的過程中,都可帶上轉化的程式行數,以方便除錯使用。
配合上 devtool: (process.env.NODE_ENV === 'development') ? 'cheap-module-source-map' : 'false', ,最後會產生 'cheap-module-source-map' 模式的 .sourcemap 檔,透過三元運算子確任執行環境是否為 'development'。
HTML 樣版
一開始也是 file-loader 將 .html 檔做搬移與監視的動作,裡面的結構是可以完成手動撰寫。
但透過 HtmlWebpackPlugin() 可以結合 webpack 的 entry 注入點,帶上 ?[hash:8] 的設定,將 .css 與 .js 路徑帶上亂數方便開發,不會有快取的問題產生。
但也因為由 file-loader 改成 HtmlWebpackPlugin() 的方式產生檔案,原生就有的 <link href="main.css" rel="stylesheet"> 與 <script src="./assets/js/vendor.js"></script> 和 <script src="./assets/js/main.js"></script> 沒改成樣版動態產生結構,所以等同於各執行二次,對於 css 的開發者工具上會動覆出現二次樣式結構,而 JS 的部份像是 彈出提示框 (Popovers) 觸發時,也會點按一下執行二次,收閤選單點按後直接收起來,這也是因為各重覆載入的問題所產生。
webpack 輸出設定
1 2 3 4 5 6 | module.exports = { output: { path: path.resolve(__dirname, (process.env.NODE_ENV === 'development') ? 'dist' : 'docs'), filename: './assets/js/[name].js?[hash:8]', }, } |
原先 webpack 預設產生實體檔案或是輸入資料夾都會是在 dist 資料夾內,透過判斷式指定在開發模式下的實體檔案到 dist,另外這裡配合 GitHub pages 的自動部署路徑,指定與打包後到 docs 資料夾內,在使用 git 推送後設定好排除就可配合 npm 指令將打包的後的檔案直接處理到 GitHub Repos 上, dist 設定為排除。