[學習之路] CSS 預處理器 Sass
本篇介紹 Sass 這套預處理器,他能將大型專案上編寫 CSS 不易維護的問題進行改善。使用 Sass 的 Script 語言來進行 CSS 開發,再透過編譯 complier 後轉為瀏覽器可閱讀的 CSS。
Sass
Sass 於 2006 年誕生,屬於最成熟且廣為人知的 CSS Preprocessor 預處理器編輯語言(可稱為 SassScript),起初用於 ruby 程式語言所使用 的 CSS 框架,可相容原生 CSS 語法並以副檔名 *.sass
來保存。
新舊差異 *.scss & *.sass
早期的編譯副檔名為*.sass
編寫方式,隨同敵 LESS 的出現後才推出新版的副檔名*.scss
的編寫方式,主要是因為原*.sass
的寫法省略範圍符號{}
與結尾符號;
的方,導致 web 開發人員在學習上不易習慣與視察維護,推新出 Sassy CSS *.scss
之編寫習慣更貼近 css 原生格式。而這兩者都併存目前皆可使用解讀編譯,如果學習選擇直接以新的*.scss
編譯習慣即可。
/*Scss SYNTAX */ |
/*Sass SYNTAX */ |
/* CSS OUTPUT */ |
雖然如此官方名稱仍以 Sass 稱呼,只需理解 Sass 的 Script 語言提供了*.sass
與*.scss
兩種轉換編碼即可。一律聲稱所學的是 Sass 並採新編譯方式 Scss 使用。
安裝
早期需要安裝 ruby 才能使用編譯 Complier(元祖版本),隨著時代推進發展至 Node.js 為主流市場已停止維護(包含 LibSass 版)。改由 Dart Sass 版本來工作。以下方法皆不使用 ruby 方式下進行安裝。但方法其實不只一種,其主要的是需要找到工具能夠協助將 Sass 編譯成 CSS 即可。列出 2 種方式與各自工具:
現在大部分都採用 Dart Sass 版來編譯使用,如果不清楚最好判別的方式為 Dart Sass 版本目前是 1.42.1 而 LibSass 版本為 3.6.5。如果不是採用官方的管道來安裝 Sass,很可能是該作者根據 Sass 邏輯來自設計或嵌入 Dart Sass 某版,版本上的新功能嘗鮮或閹割就沒這麼正統便是。
Dart Sass
Sass 已經將主要更新維護落於 Dart Sass 這個版本,如果你還聽過 libSass 也被官方宣告不再維護了,Dart Sass 是採用 JavaScript 來開發的,編譯時間上稍微慢但也沒啥問題。先從下列方式獲得 Dart Sass 編輯能力。
獨立安裝
從 Github 安裝主程式,透過 Dart Sass 主程式來安裝到電腦,並自行設定 PATH 使得 CMD 支援 Sass 指令。
本篇不介紹自行前往了解。
自動化管理工具
大多數的資深開發人員都會選擇這方面的套件管理工具,選擇支援 Sass 的管理工具來使用,像是 Webpack (推薦)、Gulp 等。
本篇不介紹。未來有機會介紹 webpack
Node.js 安裝與測試
身為 Web 開發人員,從 NPM 方式來獲取是最便捷的,這裡教學兩種 npm 安裝,分別是全域模式與專案模式。
全域安裝
使用指令npm install -g sass
來全域安裝,注意由於是 JavaScript 來實現因此執行效率稍慢一些。
全域安裝方式 |
i
等價 install;-g
等價安裝至 Global 也就整台電腦上,使得 node.js 終端指令能使用 sass 模組。
接著測試一下終端指令。開啟終端機輸入 sass 獲得提示,你可以執行以下指令要求輸入來源與輸出位置
來源檔案 目標檔案 兩種寫法 |
單一檔案轉換
舉例透過前面的 scss 範例代碼存為 test.scss,輸入以下指令將能獲得 myOutput.css 與 myOutput.map 檔案
sass test.scss myOutput.css |
如果需要多個檔案轉換,可一次輸入例如
sass a.scss:myA.css b.scss:B.css
目錄下全數轉換
將多個 scss 檔案放置在自訂目錄下例如/scss/*
,而想要指定輸出至目錄/dist/css/*
,根據以下指令完成(你可以拿 Bootstrap Source 包來測試)。能發現原本 Bootstrap 的 scss 目錄內之多個檔案變成只有 8 隻檔案。
sass scss:dist/css |
如果整個根目錄底下的 scss 都要轉換且輸出位置同於輸入位置,可暴力使用指令
sass .
來全部完成。
watch 監看
如果每次轉換都要手動很麻煩,可以對指令多添加–watch。第一次轉換之後就會保持監看模式,一但來源檔案有所異動就會立即同步至輸出檔案,除非按下Ctrl+C停止監看。
sass --watch test.scss myOutput.css |
更多指令請參閱官方網站手冊 https://sass-lang.com/documentation/cli/dart-sass
專案安裝
如果只想綁定在專案上使用,我們需要規畫一個 npm 初始化並在這個專案上設定 script 指令來出動。
如果前面有試過全域安裝,可考慮先移除
npm remove sass -g
避免功能差異上之混淆。
- 在專案下終端輸入
npm init
使得專案獲得 npm 環境,過程可以先 pass 跑完。 - 檢查剛產生的 package.json 可能長這樣
package.json {
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
} - 接著終端指令輸入
npm i sass -save
,要求安裝 sass 至專案下。i
等價 install;-save
等價寫入,能自動寫入此 sass 模組相關資訊至 package.json - 再次檢查 package.json 長這樣
package.json {
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"sass": "^1.42.1"
}
} - 接著我們開始能自訂指令寫入到 package.json 的 script 項目內,舉例來只要輸入 sass 就能幫我們自動轉換(指定目錄)並監看模式中。
package.json {
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"autosass": "sass --watch scss:dist/css"
},
"author": "",
"license": "ISC"
} - 然後執行指令
npm run autosass
就能透過名稱 autosass 這個 script,開始將 scss 目錄轉換至 dist/css 目錄並保持 watch。可以多創造幾個喜歡的 script 指令
VSCode 插件
與前面 Dart SASS 的工具不同,由插件來使 VSCode 獲得 SASS 編譯能力。因此指令操作不是同前方式執行。假若只是做為新手練習快速獲得檢視(需搭配 Live Server) 使用下值得推薦。
啟用步驟
- 前往 vscode-live-sass-compiler 獲得 VSCode 安裝外掛
- 按下右下角狀態列之 Watch Sass / Watching.. 之按鈕,能切換 Sass 啟用並預設的自動將專案目錄下所有 sass 檔案轉為 css 並放置相同位置。
參數調整
透過 VSCode 的 setting.json(或從套件找到設定參數)進行客製調整
liveSassCompile.settings.formats
為導出的 css 設置格式(樣式)、擴展名和保存位置(支持多種格式)。
"liveSassCompile.settings.formats": [ //輸出格式 |
liveSassCompile.settings.excludeList
排除特定目錄。目錄內的所有 Sass/Scss 文件都將被忽略。
"liveSassCompile.settings.excludeList": [ //排除特定目錄 |
liveSassCompile.settings.includeItems
指定特定檔案才進行導出
"liveSassCompile.settings.includeItems": [ |
liveSassCompile.settings.generateMap
是否要導出 map 檔案
"liveSassCompile.settings.generateMap": false, |
liveSassCompile.settings.autoprefix
是否啟用自動對 css 自動前綴,能增加瀏覽器相容程度。預設值為 null 不使用。
"liveSassCompile.settings.autoprefix": [ |
liveSassCompile.settings.showOutputWindow
預設為 true,若不想顯示視窗工作訊息,可調整為 false
"liveSassCompile.settings.showOutputWindow": false, |
舉例以下參數使用,會生成*.min.css, .css ,.map,提供 autoprefix 並排除部分檔案。
{ |
區塊化檔案 Partials
在正式介紹 Sass 語法之前,先介紹將檔案設計成區塊的整理觀念。隨著專案的 CSS 龐大複雜而冗長不好維護(想想 Bootstrap.css 2 萬多行的恐怖之處),開發設計者為了方便維護,會將 CSS 寫成多筆區塊檔案來宣告並適時地將 CSS 分割整理在在不同的 Sass 檔案內,之後再使用一些語法並統整出一份樣式表。這樣維護性與時效性都能顧及到,而 Bootstrap Source 包就是這樣設計的。
非樣式表用的區塊檔案,需要特殊的命名方式讓 Sass 知道這些不是作為轉換用的單獨 css 檔案,命名方式以_
開頭,除非你在某 Sass 檔案內呼喚他們否則 Sass 會忽略這些檔案。
這些非樣式表的 sass 區塊檔案的應用方式可分為匯入(舊觀念)的
@import
語法,以及模組(新觀念)的@use
語法。在介紹@import
之前值得提早知道的是,未來版本的@import
逐漸會被汰換。取而代之改推薦 Modules@use
來運作。但目前市面上包含 Bootstrap 這些大廠仍延續使用 import 舊方式來合併區塊,因此還是有學習之必要。Modules 的@use 操作會另外特別仔細介紹。
匯入規則 @import
將區塊化檔案進行進行匯入,需要匯入的 sass 內透過@import
陳述式來宣告。舉例 bootstrap 設計方式為建立一個bootstrap-reboot.scss
檔案並匯入指定的區塊檔案完整內容,事後導出檔案時會自動載入這些區塊內的 css 內容。
... |
然而 Sass 的@import
與 css 的@import
不同且不影響判別運作,這裡是指進行區塊合併。
@import "variables"; // SCSS 區塊合併 |
在原生 CSS 規則上的觀念,原生 css 的@import 必需編寫於於任何選擇器之前之頁首處,且不可寫於 Media Query 之內。
Sass 開發人員會有條理地整理這些檔案,透過子目錄依據功能來分類,最後在最外層編寫主樣式表之 Sass,Bootstrap 的作法就是如此。如果區塊檔案在某目錄下之路徑也要寫在@import
上,舉例 Bootstrap 提供四種 css 版本,其中 bootstrap-grid.scss 這檔案寫法長這樣
//... |
Bootstrap 透過目錄來區分要載入哪些項目區塊,如果好奇可發現 Bootstrap 的@import "mixins"
其實是指向一個窗口用的區塊檔案,再從這個區塊檔案載入 mixins 目錄下所有項目區塊檔案。
//... |
嵌套 Nesting
若在某選擇器下進行@import 某選擇器內容,等同形成選擇器的 Nesting 嵌套效果。
pre, code { |
.theme-sample { |
變數
如果熟悉原生 SCC 的變數,這裡也是差不多的做法。差別於 Sass 使用$
符號代表變數宣告與套入,不像原生 CSS 需要透過 var() 函式才能使用。變數除了拿來作為屬性內容也能作為布林值其他用途。
$blue: #0d6efd; // 宣告變數 |
良好的整理習慣會單獨一個檔案(通常是取名_variables.scss
) 來存放整個專案 Sass 的變數。而其他區塊檔案要使用這些變數勢必要優先 import variables 才能被其他區塊檔案所使用否則無法認識。
//.. |
多重變數
變數的常見用法會導向多個步驟來定義,舉例根據網站的先定義常用顏色變數,隨著不同的特定元素綁定此顏色變數形成多重變數。最後將這個特定元素用在其他區塊檔案內導入各種場合內。多重變數這個觀念能確保來源指向同一個變數,使得事後修改更方便。
// scss-docs-start color-variables |
!default
為預設值,如果沒有出現同名之變數值(不含 null) 會以此為值。
適用字串
變數也會用在 font family 上,在需要的選擇器下帶入變數
$font-family-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" !default; |
變數運算利用
變數可以拿來做彈性的設計,透過加減乘除獲得指定一個數據的比例調整。但注意進行加減行為需要相同單位否則無法計算。
$margin-top:20px; |
全域變數與區間變數
變數本身如果宣告在最外層為全域性任何地方都能存取,若存在某選擇器{}內則為只有該區間能存取。
$global-var: "global"; |
若在區間變數與全域變數同名時,會以區間變數為主。
$let: "global"; |
同上,若想從區間內設置全域變數,需告知這個變數為!global
指的是全域變數不是新創的區間變數。
$let: "global"; |
!global 只在 Dart Sass 2.0.0 版本出現的功能,其他 Ruby 與 LibSass 版本沒有。
屬性
操作屬性上也提供一些規則寫法。
前綴同名整合
CSS 屬性常有相同前綴的name-*
屬性名名稱,可以透過選擇範圍搭配:
符號來簡化。
.enlarge { |
如果加上自身也有值,提供另一種變化寫法
.info-page { |
隱藏屬性
若屬性指定為 null,此屬性不會被編譯出來
$boolean: false; |
資料型態 Value Types
在 Sass 領域內,任何的資料 types 可以是 number,string,color,lists,maps,boolean,null,function,並可指定給變數或進行判斷使用。本篇不會提供執行範例,只需知道各種數值型態的觀念與可用規則
數字 Number
支援原生 CSS 原本的數字型之屬性值,且能進行簡單的數學計算,單位是否存在不影響 Sass 對數字處理的能力。
如果希望在終端機呈現數字,可添加
@debug
來檢測輸出
// 基礎數字 |
單位上的計算處理看起來很詭異,但有些場合下可以剛好抵銷使得規劃上容易處理。
@use "sass:math"; |
運算元
相關運算元細節總類請參考以下官方說明,不再解釋。
文字串 String
帶雙引號(例如 font-family) 或不帶雙引號(例如 bold) 的字串型態都能使用。如果需要拔除或添加雙引號可透過內建模組sass:string
的特殊函式來協助。
@use "sass:string"; |
//基本操作 |
運算元
字串連接的符號為+
,相關運算元細節總類請參考以下官方說明,不再解釋。
顏色 Colors
因為 CSS 的色系定義,Sass 特別規劃了 color 這個型態操作。包含所知道的幾種顏色表示法
//基本操作 |
列表 Lists
Sass 沒有陣列結構的觀念,因此當多個 value 的型態統稱為 lists,表示方式可以用,
,
,/
來區隔出不同值 (/
會誤判為除法只有在 list.slash 這個內建模組函式用到),只要在 lists 內能保持一致不要混用符號。lists 也可以用中誇號[]
來提示這是一個 lists。由於 lists 不是直接拿來做屬性值使用,通常需要搭配函式或場合才有作用。舉幾個例子
//內建模組 list |
list 不可以對舊索引處的舊值進行修改,但可以再後面新索引位置添加新值,透過內建函式append()
達到
//內建函式 `append()` 可以對 lists 讀取出來並在後面添加新值。 |
若在 list 內查找某值是否存在,可透過內建模組 sass:list 的index()
來判斷。index 的用法如下
// 內建模組 list |
搭配一些判斷就能進行檢查與報錯功能。
$valid-sides: top, bottom, left, right; |
list 本身可作為其餘參數的原型,舉例提供給 mixin 的參數為 list。
@use "sass:meta"; //內建模組,可以把 |
映射 Maps
意思是指只能透過某個關鍵字 key 去獲得對應的值 value,類似 JavaScript 內的物件資料。map 的資料通常會編寫在 list 內,使得這個資料形成了物件的映射關聯。使用方式可搭配批次來抽取,key 本身也可以加以利用。例如 each 能循序抽出 key 與 value。
$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f"); |
可對 map 進行新增修改與讀取,不過記得內建模組的 map 相關函式只是帶結果,因此需要時必須回存到變數內。
@use "sass:map"; //內建模組 |
合併 map 的作業透過map.marge()
來達成,如果有重複的 key 會以後出現的第二組而覆蓋。
@use "sass:map"; |
已宣告的 map 內容是不可修改的,因此前列的作法都是重新定義變數而不是修改調整 map。
布林值 Booleans
獲得布林值的方式除了直接指定 true 與 false,也能透過比較式或透過內建模組的結果取得布林值,以及複合邏輯、否定式
@use "sass:math"; |
使用時機用於邏輯判斷上等多種場合之下。
@use "sass:math"; |
判斷時機當下,有值也可以當作 true,若為 null 可當作 false 使用
運算元
相關運算元細節總類請參考以下官方說明,不再解釋。
- 基礎 - Sass: Operators
- 等價 - Sass: Equality Operators
- 比較 - Sass: Relational Operators
- 布林 - Sass: Boolean Operators
無 null
所有的型態都有 null 的可能,代表缺少這內容。
@use "sass:map"; |
若將 null 出現在 list 上則為省略。指定給 css 屬性作為值,會忽略此屬性的輸出。
$fonts1: ("serif": "Helvetica Neue", "monospace": "Consolas"); |
函式 Functions
函式也可以當作一個值,需透過meta.get-function()
轉換為一個值。若需要對這個函式之值提供參數則需要透過meta.call($fn, $arg)
才能執行函式與結果。這在函數的進階操作上很有用。
@use "sass:list"; |
選擇器規則
嵌套 Nesting
俄羅斯娃娃的設計觀念,對多層元素下達選擇器時,在原 CSS 需要分多個選擇器來指定。舉例一個父元素與兩個子元素的樣式如下:
.nav { |
在 Sass 可以當作集合的觀念寫在父子之間,Sass 會自動整合來自外部選擇器的關係。
.nav { |
Sass 的註解語法為
//
,若使用/**/
則為 CSS 註解並會保留轉譯出。
組合列表
嵌套下的內部選擇器若使用,
多選,會組合出所有選擇器結果。
.alert, .warning { |
複合子選擇
操作>
,+
,~
等等複合子選擇時,可以彈性放在選擇範圍之外部、內部、甚至獨立寫都可以。
SCSS 語法 |
父選擇器 &
&
符號代表的是本身自己相對應之外層選擇器為代表替換,使得舉例常用於偽類這方面需求設計。
a { |
也能對&
符號添加後綴,利用&
替代文字特性,呈現另一種 class 重複利用的簡寫。
.main { |
在嵌套內的複雜程度沒有限制但越少越好約 1~2 層,否則轉譯過程會耗費較多時間且不易掌控。盡可能把相關的放在適合的嵌套內。
.nav { |
Media Query 嵌套
編寫媒體查詢時,直接寫在選擇器內進行宣告即可,會自動產生對應該選器的媒體條件。但其缺點他不會整合相同的@media 條件,隨樣式表擴大會產生大量相同的@media 條件,這利弊關係(好管理,不精簡)的支持者分兩派爭議。
.container { |
繼承屬性 extend
繼承@extend
能將某一個選擇器內部的屬性整個繼承過來,類似組合選擇 (ex:h1,h2) 但又賦予個別彈性添加。
h1 { |
@extend
可放置在行數內任何位置不影響,大多人會放在第一行方便察覺。
不過要注意的繼承效果非常強烈過度。前列範例上指定一個存在的選擇,繼承的對象除了所指定的選擇器 A,其實也會參考其他包含此 A 的選擇器。然而以下會發生不想要 #main h1, #main h2, #main h3 的結果
#main h1 { //跟目標對象 A 有關的其他選擇器 |
佔位符號 %
Sass 提供了類似別名不存在任何網頁元素的佔位選擇器 Placeholder Selector。透過符號%
前綴一個選擇器,而這個不屬於任何 HTML 元素所圈選的非真實存在,只是一個假的選擇器。因此需要避免繼承過度發展到其他實際存在的選擇器,透過虛擬的佔位選擇器來做為繼承區分開來。
#main h1 { |
繼承的應用場合通常發生在一個具有相同數的外觀,再額外的個別差異使用。多看一個例子結束這話題。
%btn { |
混入 Mixins
一種多重繼承的實現並可重複使用,但不是函式。建立方式為@mixin name{}
而使用方式為@include name
。而良好的習慣上會將所有 mixin 的語法都另存為_mixins.scss
區塊檔案,並在一開始進行合併提供使用。通常會在 variables 之後因為 mixin 可能會用到變數。
@import "functions"; |
舉例如何建立與使用 mixin:
///////////////////////// mixins.scss |
extend 與 mixin 的用途看似類同,但 mixin 用途更廣泛的應用多元場合下。
傳遞參數
mixin 可像函式一樣夾帶引數作為參數使用。
// mixins.scss |
插值 interpolation
然而如果想傳遞數字做為引述並在 mixin 內組合成文字,需使用插值 interpolation 方式來做替換,否則語意上無法預期作業。字串內的插值寫法為#{name}
,插值幾乎可以在 Sass 樣式表的任何地方使用,只需在任何位置插入#{}
作為使用。
// mixins.scss |
插值可以抵替 mixin 內任何位置,包含屬性名、值、甚至也可以頂替 mixin 內的選擇器名
@mixin demo($name, $fontawesome) { |
或作為快速混入一個動畫名稱與內容之範例。
@mixin addAnimate($duration) { |
參數預設值
傳遞參數可以指定預設值,當未獲得參數時會以預設值來使用。原則上參數需全部必填存在,除非若預設值為 null 則忽略並不會回傳該此結果屬性(選填)。而參數順序上若需必填應排列前面,選填(具備預設值或 null) 排列後面才能正常運作。
@mixin myText($size, $height:null, $weight:normal, $color:null) { |
參數關鍵字
引數的排序位置因為匿名對應配合參數位置,除非特別在引數上寫關鍵字來指定名稱。但注意使用此指名引數之後,其餘後列引數不可再恢復匿名。
@include myText(10px, $color:red); //scuess |
最後,mixins 就像函式一樣只要特定的參數就能獲得外觀屬性值,因此你可以創造一個第自訂函式來快速得到 CSS 外觀屬性組合。也可從訪間尋找一些免費提供的 mixins library 來快速獲得網站外觀。
其餘參數
接受任意數量的參數可使用...
代表。再搭配一些邏輯規則就能做出批次作業。
@mixin order($height, $args...) { |
也可以用變數來作為其餘參數內容,透過,
分開。
$lokiArgs:".a1", ".a2", ".a3"; |
內容綁定 @content
若在@mixin
內出現@content
,則代表這部分的內容屬性來自於呼叫端@include{}
之外部內容,可藉由此方式更彈性運用
@mixin myText($size) { |
Mixin vs Extend
這兩者角色十分貼近能辦到類似的效果。選擇哪種根據以下判斷:
是否需要傳遞參數
如果需要透過外層的引數來傳遞參數進行處理獲得結果屬性,也只能 mixin 才能辦到,extend 沒有這樣的功能。
樣式表生成的大小
透過 mixin 所產生出來的選擇是獨立的會出現大量重複的選擇器之結構屬性,如果 mixin 呼喚 10 次會產生 10 組選擇器。而呼喚 10 次 extend 只會產生 1 組多選的選擇器。
組合應用
這裡提供一些上述介紹過的語法進行應用組合。
調度父容器
既使是 mixin 也能認出&
來自誰。透過這方式可在 mixin 內加以利用&
。
@mixin bgColor($color) { |
breakpoint
我們可以運用變數與 Mixin 來重新規劃 Media Query 的響應式範例。
- 將響應的 break point 做成變數放置在
_variables.scss
內,未來調整時也方便。_variables.scss $sm: 576px;
$md: 768px;
$lg: 992px;
$xl: 1200px; - 將 media query 定義成 mixin 函式,之後任何選擇器要加入 RWD 機制直接使用該 mixin 進行 include,獲得 break point 的機制。
_mixins.scss @mixin grid {
@media (max-width:$sm - 1px) {
@content;
}
}
@mixin grid-sm {
@media (min-width:$sm) and (max-width:$md - 1px) {
@content;
}
}
@mixin grid-md {
@media (min-width:$md) and (max-width:$lg - 1px) {
@content;
}
}
@mixin grid-lg {
@media (min-width:$lg) and (max-width:$xl - 1px) {
@content;
}
}
@mixin grid-xl {
@media (max-width:$xl) {
@content;
}
} - 接著呼喚 mixin 來獲得 media query 條件,條件內的屬性由外部來編寫設計。使得 media query 的規劃從該元素的選擇器來一併整合。
style.scss @import "variables";
@import "mixins";
.container {
width: 100%;
margin: 0 auto;
@include grid {
background: lightyellow;
}
@include grid-sm {
background: lightblue;
}
@include grid-md {
background: lightcoral;
}
@include grid-lg {
background: lightgoldenrodyellow;
}
@include grid-xl {
background: lightpink;
}
} - 最後輸出結果為:
.container {
width: 100%;
margin: 0 auto;
}
@media (max-width: 575px) {
.container {
background: lightyellow;
}
}
@media (min-width: 576px) and (max-width: 767px) {
.container {
background: lightblue;
}
}
@media (min-width: 768px) and (max-width: 991px) {
.container {
background: lightcoral;
}
}
@media (min-width: 992px) and (max-width: 1199px) {
.container {
background: lightgoldenrodyellow;
}
}
@media (max-width: 1200px) {
.container {
background: lightpink;
}
}
目前為止以足夠讓你開始使用 SCSS 來取代原生 CSS 之開發設計。後面開始會介紹更程式邏輯的功能技巧。
模組 Modules
目前只有 Dart Sass 這個版本有提供 Modules 觀念(包含內建模組)。因此像是 VSCode 插件的 vscode-live-sass-compiler 就不支援了。@use
的使用方式雷同並將取代@import
並提供更彈性的用法。欲將區塊檔案從模組進行參照變數、mixin、function 時,其規則與條件較為繁瑣些。
加載規則 @use
假設區塊檔案長這樣。
// _base.scss |
與@import 方式相同,當從區塊檔案獲得選擇器,直接@use
即可。
// styles.scss |
以上做法指限定選擇器可直接引用,然而如果是變數、mixin、function 這類就無法像@import
這樣直接使用。因為這是原詬病的全域重疊問題,這裡需要透過名字來找到藏於模組下的空間位置。名字預設為檔案名稱,或者可另外由命名空間方式來重新取名。
@use 'base'; |
命名空間
命名空間主要是保護當從區塊檔案獲得的模組為獨一性不與原樣式表下的名稱重疊(全域下之覆蓋問題),因此當進行@use
規則時給予命名才能獲得找模組內的名稱空間位置。命名空間的作法能套用在變數、mixin、function 且不受重名覆蓋影響。
$radius: 3px; |
@use "src/corners" as loki; //你必需命名才能以模組名稱來訪問內容 |
如果沒有特別取名,則模組的別名預設為同區塊檔案之檔案名稱。
@use "corners"; //假若不特別指定別名 |
也可以直接命名為*
就能像@import 那樣使用,但模組就變成全域下的訪問(需自己注意重名覆蓋問題)。同上修改:
@use "src/corners" as *; //不以物件方式保存,以全域空間來加載模組 |
早期
@import
舊方式來載入檔案的內容,跟@user
效果雷同差異在於舊方式會有全域性之覆蓋問題且效能不佳即將淘汰。詳情可參閱 Introducing Sass Modules | CSS-Tricks。
禁止訪問 -
假設有個項目僅作為該區塊檔案內的使用,並不想被外面的樣式表給模組讀取,可添加-
前綴使得模組提取過程中所忽略禁止。
$-radius: 3px; |
@use "corners" as loki; |
可配置 with
類似函式的傳遞引數效果,開發人員可從樣式表在進行 use 先提供變數並配置修改給區塊檔案之前置流程,再把模組結果回傳獲得取回。但區塊檔案內這些變數要先存在且需綁定!default
設定為默認值才能允許被開發人員重新配置。
$black: #000 !default; //默認值,如果變數已存在則捨棄此設定 |
@use 'library' with ( //配置已存在於區塊內之變數給模組 |
變數值後綴寫上
!default
之意,只有在該變數沒有被定義或值 null 時才會被分配給變數。
然而如果只是簡單的配置可以這樣使用with()
,反之如果高級複雜性的例如傳遞後判斷性則需要用 mixin 比較適合。
$-black: #000; |
// style.scss |
轉發規則 @forward
與@use 雷同但場合不同,如果 use 模組來源是另一個窗口型中繼站的區塊檔案,該中繼站可使用@forward
來進行轉往到其他區塊檔案獲取內容。跟舊方式@import
兩次有同用途之意思(如 bootstrap 的_mixis.scss)。
@mixin list-reset { |
@forward "mixins/list"; // mixins/_list.scss |
@use "mixins"; // _mixins.scss |
命名空間並前綴
透過@forward
獲得的區塊內容當下可選擇考慮命名至轉發內容,方式為as name-*
能保留原名稱添加前綴。使得本體樣式表呼喚時根據此新名稱來獲取。
@mixin reset { //原名稱 |
@forward "mixins/list" as loki-*; // 添加前綴名稱 |
@use "mixins"; // _mixins.scss |
禁止訪問 hide
部分內容不想被轉發出去,可以在@forward
當下指定那些內容不被轉發,多個用,
分開。
$horizontal-list-gap: 2em; //不想轉發這個 |
@forward "list" hide list-reset, $horizontal-list-gap; |
可配置 with
可設定配置內容作為取代,同樣需指定!default
參數使得上游樣式表可進行配置,且允許下游樣修改它。
$color: #000 !default; //覆蓋為 red |
@forward 'library' with ( |
@use 'opinionated' with ($color: red); //配置 red |
函式 @function
Sass 可透過自訂函式來達到一些複雜動作,與 Mixins 最大不同的是直接寫上 name() 就能得到,但要主動進行@return
將結果傳回。
@function pow($base, $exponent) { |
參數預設值
傳遞參數可以指定預設值,當未獲得參數時會以此預設值來使用。
@function invert($color, $amount: 100%) { |
參數關鍵字
參數的排序位置因為匿名對應配合參數位置,除非特別在引數上寫關鍵字來指定名稱。
$primary-color: #036; |
其餘參數
接受任意數量的參數可使用...
代表。再搭配一些邏輯規則就能做出批次作業。
@function sum($arg...) { |
也可以用變數來作為其餘參數內容,透過,
分開。
$widths: 50px, 30px, 100px; |
除錯測試
若是 Sass 標準安裝,遇到語法或使用錯誤會將錯誤訊息輸出在編譯後的 css 上。若開發者的編輯階段需要測試相關資訊回傳分以下規劃。
錯誤輸出 @error
使用@error
能將文字輸出在編譯 css 上。一旦@error
執行時會中斷整個 Sass 工作。舉例在 mixin 與 function 的內部判斷底下,需要檢查參數內容為何
@mixin demo($arrow, $value) { |
/* Error: "arrow top must be either left or right." |
警告輸出 @warn
同前面用法,差別於 Sass 會繼續執行不會中斷 Sass。
@mixin demo($arrow, $value) { |
.sidebar { |
除錯 @debug
拿來測試用的輸出,例如是拿來檢查變數內容。輸出情報的地方於終端機上呈現而不是在編譯後的 css 檔案內。
@mixin demo($arrow, $value) { |
style.scss:2 Debug: arrow is top, value is 12px |
邏輯判斷
Sass 提供了邏輯判斷的語法,能設計在 Mixin 與 function 提供良好的演算法則,使得 Sass 更聰明智慧。
@if
if 的判斷條件為布林值進行處理,進階用法為當變數內容存在等價 true,若 null 等價 false。使用方式為@if
與@else
。
@mixin avatar($size, $circle: false) { |
@else
不成立時若存在 else 則由這部分處理。
$light-background: #f2ece4; |
@else if
前一個@if
不成立時,因 else 因素進入此判斷式同時在給予 if 的判斷。此外 if 除了直接提供布林值也可以透過比較式來得到布林值。
@mixin triangle($size, $color, $direction) { |
三元運算子 if(,,)
由內建函式來提供,透過三個傳遞參數來回傳。
@mixin delo($light-theme: true) { |
@each
Sass 沒有陣列觀念但有列表(多筆以,
分隔)觀念,可透過@each
來對列表做循序同樣的內容工作。使用 each 需提供批次下替代變數與來源變數。語法為@each <variable> in <expression>
。
$sizes: 40px, 50px, 80px; |
映射 with maps
遇到列表變數的資料型態為("key": "value", ...)
進行抽取(類似 json 但沒有此觀念),多一個變數於 each 語法內。
$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f"); //資料型列表 的 變數 |
解構 destructuring
遇到列表變數的資料型態為("value" "value" "value", ...)
,使用對應的變數數量來抽取。
$icons: |
@for
for 的語法非常簡易,只需指定一個變數並告知兩個整數(最小值與最大值),每次變化為+1 次。
$base-color: #036; |
@while
迴圈 while 的結構只有布林值判斷,除非獲得 false 否則會再進行重複迴圈。
@function scale-below($value, $base, $ratio: 1.5) { |
內建模組
Sass 提供了一些已設計好的內建模組提供使用,提供更高階便利的進階技巧使用。各個內建模組具備多種 function 或 mixin 作為應用,每次使用這些內建模組與載入區塊檔案作為模組方式相同@use 'name'
。只差別於 name 都為sass:*
為前綴代表為 Sass 提供模組。另外還有一些 function 已存在於全域空間上不需透過呼喚內建模組來宣告,可直接使用。
全域函式
這些都是 Sass 基本提供的便利函式,直接就能使用
hsl() 與 rgb()
原已存在的 CSS 原生函式hsl()
,由 hue 色調(單位 deg:0~360)、saturation 飽和度、lightness 明亮度來組成顏色(可配 alpha 透明度)。以及 CSS 函生函式rgb()
由三原色來代表。
而 Sass 也特意撞名提供hsl()
與rgb()
之 Sass 內建函式,目的為協助轉為 16 進位(無透明色)或 rgba(有透明度)的色碼。
// 原生 CSS 規則 HSL 寫法組合 |
當由 Sass 編譯時會自動對 hsl 或 rgb 轉換動作,除非遇到var()
這種原生變數套用才會保留不做異動。
$color1: hsl(210deg 100% 20%); |
if()
作為三元運算子的函式使用。語法為if($condition, $if-true, $if-false)
。
@debug if(true, 10px, 15px); // 10px |
內建函式
variable-defined()
可檢查變數是否被定義
sass:color
內建模組 color 提供多元調整顏色的函式可供使用,注意部份的函式有提供全域函式的版本(免宣告@use 直接可使用)。
指定色之調整
color.adjust
函式結構如下,可將指定色$color
調整 RGB 三色 (-255~255)、色調 H、飽和 S、L 明亮、透明 A 之增減。
@use 'sass:color'; |
使用方式舉例如下,需先宣告內建模組之定義才可使用。
@use 'sass:color'; |
另有提供全域函式的版本adjust-color()
,用法跟color.adjust()
相同只差在不需宣告模組即可直接使用。
//免宣告模組也能使用,等價上面結果 |
其中由於常用性質部分,有單獨提供全域的內建函式:
調整色調 Hue
語法為adjust-hue($color, $degrees)
單位為 deg 但也可省略不寫。
// #6b717f(Hue 222deg) becomes #796b7f(282deg) |
等價對應內建模組函式
color.adjust($hue)
。
調深明度 darken
語法為darken($color, $amount)
單位為 0% ~ 100% 。只能調低亮度不能反向。
@debug darken(#f00, 30%); // #600 |
等價對應內建模組函式
color.adjust($color, $lightness: -$amount)
。
調高明度 lighten
語法為lighten($color, $amount)
單位為 0% ~ 100% 。只能調高亮度不能反向。
@debug lighten(#f00, 30%); // #f99 |
等價對應內建模組函式
color.adjust($color, $lightness: $amount)
。
調低飽和度 desaturate
語法為desaturate($color, $amount)
單位為 0% ~ 100% 。只能單向調低飽和度不能反向。
// Saturation 35% becomes 85%. |
等價對應內建模組函式
color.adjust($color, $saturation: -$amount).
。
調高不透明比例 opacify
語法為opacify($color, $amount)
或fade-in($color, $amount)
其單位為 0 ~ 1 浮點數 。只能調高不透明度不能反向。
@debug opacify(#ff000099, 0.1); // rgba(255, 0, 0, 0.7) |
等價對應內建模組函式
adjust($color, $alpha: $amount)
。
調低不透明比例 transparentize
語法為transparentize($color, $amount)
或fade-out($color, $amount
其單位為 0 ~ 1 浮點數 。只能調低不透明度不能反向。
@debug transparentize(#ff000099, 0.1); // rgba(255, 0, 0, 0.5) |
等價對應內建模組函式
adjust($color, $alpha: -$amount)
。
color.change
函式結構如下,與 adjust 不同的是直接指定單位覆蓋過去而不是加減多少。可將指定色$color
調整 RGB 三色 (-255~255)、色調 H、飽和 S、L 明亮、透明 A 之修改。
@use 'sass:color'; |
使用方式舉例如下,需先宣告內建模組之定義才可使用。
@use 'sass:color'; |
color.scale
函式結構如下,與 adjust 雷同而差別是調整單位參位為-100% ~ 100%調整,0%代表無變化。隨調整移動距離越遠變化值就越大。
@use 'sass:color'; |
舉例方式如下,雙向正負參數之幅度越大變化越多。
@use 'sass:color'; |
指定色之獲取
如需取得顏色中的組成 (RGB 三色、色調、飽和、明亮、透明)單位值,提供以下方法
透明度 alpha
獲得該顏色的透明度值,另有提供 2 種全域函式。
@use 'sass:color'; |
RGB
@use 'sass:color'; |
色調、飽和度、亮度、暗度、互補色、灰階色、反差色
@use 'sass:color'; |
其他應用
hwb 色碼
hwb 是特殊的色碼公式(色調、亮度、暗度)但不備大眾瀏覽器通用(僅 Safari 瀏覽器支援),詳情規則說明請查看 W3school - Colors HWB 說明。Sass 有提供了 hwb 的色碼函式輸入轉為標準色碼公式。透過內建模組color.hwb()
使用。
@use 'sass:color'; |
mix 混色
語法為color.mix($color1, $color2, $weight: 50%)
,能將兩個顏色混和,其中分配比例 100% 貼近$color1
,0%貼近$color2
。
@use 'sass:color'; |
sass:list
內建模組 list 能對 list type 的對象提供多種函式功能,同時如果是 map type 也能適用內建模組 list,畢竟 map 也算 list 的一種。不過還是提醒注意,已宣告的 list 是不可改的,函式的結果是將新的結果回傳給你,看是另外覆蓋原變數或其他打算。
append 插入至底
將資料合併至尾端做新增。語法為list.append($list, $val, $separator: auto)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
append($list, $val, $separator: auto)
。(不需使用內建模組)
index 查詢索引值
將查詢資料內目標 value 之索引值為多少,最小為 1,不存在為 null。語法為list.index($list, $value)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
index($list, $value)
is-bracketed 判斷 [] 存在
將查詢資料之結構是否[]
存在。語法為list.is-bracketed($list)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
is-bracketed($list)
jonn 合併
將多個資料進行合併,並可決定分隔符號 (comma、space、slash),預設為 auto 與來源相同。以及是否 [] 之存在。語法為list.join($list1, $list2, $separator: auto, $bracketed: auto)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法
為join($list1, $list2, $separator: auto, $bracketed: auto)
length 長度
計算資料長度。語法為list.length($list)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
length($list)
separator 查詢分隔符
檢查資料使用何種分隔符號(回傳 comma、space、slash)。語法為list.separator($list)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
list-separator($list)
nth 指定位置
查詢資料內指定位置之 value,指定位置初始為 1,負數從末端開始最小為-1。語法為list.nth($list, $n)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
nth($list, $n)
set-nth 指定修改
查詢資料內指定位置之 value 並修改,指定位置初始為 1,負數從末端開始最小為-1。語法為list.set-nth($list, $n, $value)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
set-nth($list, $n, $value)
list.slash 改為分隔線符號
將資料內分隔符號替換為 slash,但由於目前舊語法的/
仍被當作除法。因此尚未開放此功能。語法為list.slash($elements...)
。範例如下:
@use 'sass:list'; |
zip 壓縮合併
將多筆資料合併壓縮成類似二維 list 格式,數量匹配需一致才能合併。語法為list.zip($lists...)
。範例如下:
@use 'sass:list'; |
另提供全域函式寫法為
zip($lists...)
sass:map
映射格式的 list,每筆內容具備了 key 與 value。而 map 型態可以採用多維方式記錄更深層的資料結構。善用內建模組有效去操作 map 進行合併與讀取等複雜行為
get 獲取值
從 map 透過關鍵字 key 獲得 value,支援多維 map 的查找。語法為map.get($map, $key, $keys...)
。
@use 'sass:map'; |
另提供全域函式寫法為
map-get($map, $key, $keys...)
set 修改值
從 map 透過關鍵字 key 找到 value 並修改,可透過多組 key(不含最後一組參數 key) 對多維 map 的 value 修改。語法為map.set($map, $keys..., $key, $value)
。
@use 'sass:map'; |
keys 列出全關鍵字
可對一維 map 要求印出所有 key 內容以 list 方式回傳。語法為map.keys($map)
。
@use 'sass:map'; |
另提供全域函式寫法為
map-keys($map)
values 列出全值
可對一維 map 要求印出所有 value 內容以 list 方式回傳。語法為map.values($map)
。
@use 'sass:map'; |
另提供全域函式寫法為
map-values($map)
has-key 確認存在
確認指定關鍵字是否存在於 map 內回傳布林值,支援多維 map 的查找。語法為map.has-key($map, $key, $keys...)
。
@use 'sass:map'; |
另提供全域函式寫法為
map-has-key($map, $key, $keys...)
merge 合併
可對兩個 map 進行合併,若第一組參數 map 為多維 map 且提供關鍵 key,能指定該 map 哪層維度為出發處進行合併。語法為map.merge($map1, $keys..., $map2)
。
@use 'sass:map'; |
另提供全域函式寫法為
map-merge($map1, $keys..., $map2)
deep-merge 深度合併
與 merge 相同,差別是可以深度進行合併。每個維度 map 的都會進行合併。語法為 map.deep-merge($map1, $map2)
。
@use 'sass:map'; |
remove 移除
可指定一維 map 下的尋找 key 進行移除,一次可移除多組 key。語法為 map.remove($map, $keys...)
。
@use 'sass:map'; |
另提供全域函式寫法為
map-remove($map, $keys...)
deep-remove 深度移除
可指定多維 map 下的尋找 key 進行移除,需透過 keys(不含最後一組參數 key) 一步步映射到指定位置才行,一次只能移除一組 key。語法為 map.deep-remove($map, $key, $keys...)
。
@use 'sass:map'; |
sass:math
提供大量數學相關功能函式使用。
數學單位
以下為常用的數學函式使用。
@use 'sass:math'; |
數學公式
因低使用性,僅列表說明不範例說明(請自行查看 官方文件)。
語法 | 功能 |
---|---|
math.hypot($number...) |
三角斜邊值 (求 a² + b² + c² 的平方根) |
math.log($number, $base: null) |
對數 |
math.pow($base, $exponent) |
幂值 |
math.sqrt($number) |
平方根 |
math.cos($number) |
三角函數 cos 值 |
math.sin($number) |
三角函數 sin 值 |
math.tan($number) |
三角函數 tan 值 |
math.acos($number) |
三角函數 acos 值 |
math.asin($number) |
三角函數 asin 值 |
math.atan($number) |
三角函數 atan 值 |
math.atan2($number) |
三角函數 atan2 值 |
sass:meta
做為 meta 元件的高深函式提供使用。
load-css
跟@use/@mixin
機制差不多且提供 with 可配置,不需要@use 就能獲得區塊檔案。語法為meta.load-css($url, $with: null)
$border-contrast: false !default; |
@use "sass:meta"; |
與@use 載入模組的差別在於:@use 載入同對象之區塊檔案只能出現一次;meta.load-css() 沒有限制因此可以重複出現在代碼中。
calc-args 與 calc-name
回傳計算型的函式之參數或名稱。
@use 'sass:meta'; |
call
由於 function 一旦轉為變數就無法執行它,故可透過 call 將此變數呼喚回 function 模式並執行它,也可以提供該 functionn 所需之參數。語法為 meta.call($function, $args...)
。
@use "sass:list"; |
另提供全域函式,語法為
call($function, $args...)
get-function
將函式結構轉為一個 function type 之變數。若存在 module 參數則會自動命名為該@use
規則的命名方式。
@use "sass:list"; |
另提供全域函式,語法為
get-function($name, $css: false, $module: null)
inspect
轉換為 string
@use "sass:meta"; |
另提供全域函式,語法為
ginspect($value)
keywords
能將持有變數的參數 list,轉化為字串的 keyword。
@use "sass:meta"; |
另提供全域函式,語法為
keywords($args)
type-of($value)
檢查變數類型。
@debug meta.type-of(10px); // number |
另提供全域函式,語法為
type-of($value)
檢查性
檢查指定對象獲得結果之布林值。有以下歸類:
variable-exists
檢查目前領域下是否存在該變數
@debug meta.variable-exists("var1"); // false |
另提供全域函式,語法為
variable-exists($name)
global-variable-exists
檢查指定名稱是否存在於全域變數。
@use "sass:meta"; |
另提供全域函式,語法為
global-variable-exists($name, $module: null)
content-exists
寫在 mixin 內部使用,檢查該 mixin 是否存在之獲得來自外部的@content
。
@use "sass:meta"; |
另提供全域函式,語法為
content-exists()
feature-exists
檢查 Sass 目前環境開放那些功能。檢查項目為以下內容為字串檢查:
- global-variable-shadowing:
同名之區間變數存在時是否會隱匿全域變數。 - extend-selector-pseudoclass:
@extent
規則將影響嵌套內的偽類選擇器 (ex:not())。 - units-level3:
支援 CSS3 原生變數。 - at-error:
支援@error
功能。 - custom-property:
- 自訂屬性不支持任何表達式,除了使用在插值上。
@use "sass:meta"; |
mixin-exists
檢查指定 mixin 是否存在。
@use "sass:meta"; |
另提供全域函式,語法為
mixin-exists($name, $module: null)
function-exists
檢查函式是否存在或在指定模組內存在。語法為 meta.function-exists($name, $module: null)
。
@use "sass:math"; |
另提供全域函式,語法為
function-exists($name)
模組抽取
對模組(區塊檔案)進行萃取回傳map。有以下歸類:
module-variables
返回指定模組內的變數名稱與變數值,並以 map 方式回傳。語法為meta.module-variables($module)
。
$hopbush: #c69; |
@use "sass:meta"; |
module-functions
返回指定模組內的函式名稱與變數值 (function type),並以 map 方式回傳。語法為meta.module-functions($module)
。
@function pow($base, $exponent) { |
@use "sass:map"; |
sass:selector
選擇器之相關名稱字串的函式庫。
is-superselector
檢查兩者字串名稱(順訊為祖先與子孫)在選擇器規則上是否為超集合(子孫層級)。語法為selector.is-superselector($super, $sub)
。
@use "sass:selector"; |
另提供全域函式,語法為
is-superselector($super, $sub)
append
將選擇器名稱插入後綴,可允許輸入list格式將形成獨立組合排列。語法為selector.append($selectors...)
。
@use "sass:selector"; |
另提供全域函式,語法為
selector-append($selectors...)
extend
等同@extend
邏輯,將指定選擇器名稱的名稱A替換成名稱B。但會提供list包含原選擇器值與新選擇值。語法為selector.extend($selector, $extendee, $extender)
。
@use "sass:selector"; |
另提供全域函式,語法為
selector-extend($selector, $extendee, $extender)
nest
多個選擇器進行合併嵌套,若遇到list會組合出各自list。語法為selector.nest($selectors...)
。
@use "sass:selector"; |
另提供全域函式,語法為
selector-nest($selectors...)
parse
解析選擇器的值為何。語法為selector.parse($selector)
。
@use "sass:selector"; |
另提供全域函式,語法為
selector-parse($selector)
replace
將指定選擇器名稱的名稱A替換成名稱B。語法為selector.replace($selector, $original, $replacement)
。
@use "sass:selector"; |
另提供全域函式,語法為
selector-replace($selector, $original, $replacement)
unify
回傳這兩個選擇器都能匹配的選擇器描述方式,無理則為null。語法為selector.unify($selector1, $selector2)
。
@use "sass:selector"; |
另提供全域函式,語法為
selector-unify($selector1, $selector2)
simple-selectors
簡化選擇器描述將定義範圍放大,也就是重組改成空白符號。語法為selector.simple-selectors($selector)
。
@use "sass:selector"; |
另提供全域函式,語法為
simple-selectors($selector)
sass:string
文字串的內建模組函式庫。容易解讀不分章節解釋。
@use "sass:string"; |