在 SASS/SCSS 中,我們已經使用變數、Mixin 和 Function 等語法來幫我們管理 CSS Code 了,但是它還是可能會亂,例如散亂的單一變數,除了寫註解外,還有什麼辦法能夠讓 Code 更有結構呢?
答案是 SCSS 的資料結構——Lists 和 Maps,其實昨天在寫 Function 時有稍微帶過,今天,我們就更近一步先來仔細研究 Lists 吧!
本篇同步發表於我的 Hashnode 部落格:
Eva Chen | 網頁設計師下班後 (hashnode.dev)
List (列表) 就跟它聽起來一樣,就是個簡單有序的集合,一系列用逗號或空格分隔的值,有一點像其他程式語言中的陣列。非常適合用來存放一組有順序或有關聯性的簡單資料。
SCSS 的 List 中不同的值可以使用空格或逗號分隔,只要它在 List 中保持一致即可。內容可以包涵不同類型的值。
// SCSS
$font-stack: Helvetica, Arial, sans-serif; // 用逗號分隔
$gutters: 10px 20px 30px; // 用空格分隔
$animation-timing: ease-in, 1s, 2s; // 可以包含不同類型的值
[]
更清楚定義不過如果使用空格區分,就會不清楚這是不是多個數值在同一個 List 的值內,這時可以使用中括號 []
區隔開來,會更清楚。
// SCSS
// 定義一個包含「網格線名稱」和「軌道寬度」的 List
// 如果沒有中括號,Sass 會搞不清楚結構
$grid-definition: [main-start] 1fr [content-start] 1fr [main-end];
.container {
grid-template-columns: $grid-definition;
}
在這個 SCSS 例子中,我們用中括號 []
將網格線的名稱包起來。這樣讓 SCSS 能夠正確地將 [main-start]
、1fr
、[content-start]
等等,都視為 $grid-definition
這個 List 中的獨立項目。
如果沒有外層的中括號,SCSS 的解析就會變得困難且容易出錯。
使用中括號可以明確地告訴 Sass:「這整個中括號內的內容,是一個完整 List 的值」。
/
的結果時,使用 list 模組的函式 list.slash()
像我們之前在 SCSS 運算符號中提到的,現在 CSS 越來越常使用 /
作為分隔語法的一部分,再加上過去斜線在 SCSS 是除法的意思,直接使用斜線分隔非常容易產生錯誤。
所以,為了避免混淆,不能直接用斜線來定義一個 List。
當你需要用 Sass 的變數、迴圈或函式「動態產生」一個本身就包含 /
作為分隔符的 CSS 屬性值時,你就需要 list.slash()
函式。
要使用這個函式,你需要在檔案開頭引入 Sass 的 list 模組:
// SCSS
@use "sass:list";
// 一個動態設定 grid 位置的 mixin
@mixin grid-position($col-start, $col-end, $row-start, $row-end) {
// 這裡必須用 list.slash() 來組合 "1 / 3" 這樣的字串
grid-column: list.slash($col-start, $col-end);
grid-row: list.slash($row-start, $row-end);
}
.item-1 {
@include grid-position(1, 3, 1, 2);
}
.item-2 {
// 動態組合 "2 / span 3"
@include grid-position(1, 2, 2, "span 3");
}
編譯後的結果是:
/* CSS */
.item-1 {
grid-column: 1 / 3;
grid-row: 1 / 2;
}
.item-2 {
grid-column: 1 / 2;
grid-row: 2 / "span 3";
}
sass:list
僅僅是定義 List 還不夠,Sass 更厲害的是可以對這些資料進行操作。透過內建的 sass:list
模組,可以存取、修改、合併 List,讓樣式的管理更動態與自動化:
list.length()
: 取得 List 長度
list.nth()
: 取得特定位置的項目
list.append()
: 在列表最後新增項目
list.join()
: 連接兩個列表
list.index()
: 尋找項目在列表中的位置
要使用這些函式,記得在檔案開頭先引入模組: @use "sass:list";
// SCSS
@use "sass:list";
list.length()
: 取得 List 長度這個函式會回傳列表中包含多少個項目,非常適合用在迴圈中,根據列表的項目數量來動態生成樣式。
list.length($list)
用途:計算列表中的項目總數。
回傳值:一個數字。
// SCSS
@use "sass:list";
$colors: #ff0000, #00ff00, #0000ff, #ffff00;
// list.length($colors) 的結果會是 4
.info {
// 可以在 content 中顯示列表長度,方便除錯
content: "這個顏色列表總共有 " + list.length($colors) + " 個顏色。";
}
/* CSS */
.info {
content: "這個顏色列表總共有 4 個顏色。";
}
list.nth()
: 取得特定位置的項目這個函式可以幫助你抓取列表中特定位置的項目。
list.nth($list, $n)
用途:讀取列表中第 $n
個項目的值。
注意:Sass 列表的索引是從 1 開始,而不是像 JS 陣列一樣從 0 開始。
$n
也可以是負數,例如 -1
代表最後一個項目,-2
代表倒數第二個項目。
// SCSS
@use "sass:list";
$font-sizes: 12px, 16px, 24px, 32px;
.title {
// 取得第 3 個項目 (24px)
font-size: list.nth($font-sizes, 3);
}
.caption {
// 取得倒數第 1 個項目 (32px)
font-size: list.nth($font-sizes, -1);
}
/* CSS */
.title {
font-size: 24px;
}
.caption {
font-size: 32px;
}
list.append()
: 在列表最後新增項目這個函式會在既有的 List 尾端加上一個新項目,並回傳一個全新的 List (原始 List 不會被改變)。
list.append($list, $value, $separator: auto)
用途:擴充列表。
$separator
:
可以指定新 List 的分隔符(省略不寫,就會是 auto
),可以是:
comma
(逗號)、
space
(空格)
slash
(斜線) 或
auto
(預設值 → 沿用原始 List 的分隔符)。
// SCSS
@use "sass:list";
$default-spacers: 10px, 20px, 30px;
// 在尾端加上 40px
$extended-spacers: list.append($default-spacers, 40px, $separator: auto);
// $extended-spacers 現在是 (10px, 20px, 30px, 40px)
.container {
// 取得新 List 的最後一個值
padding: list.nth($extended-spacers, -1);
}
/* CSS */
.container {
padding: 40px;
}
list.join()
: 連接兩個列表這個函式可以將兩個列表合併成一個全新的大列表。
list.join($list1, $list2, $separator: auto, $bracketed: auto)
用途:組合多個列表。
$separator
:同樣可以指定新列表的分隔符。
$bracketed
:決定新列表是否要用中括號 []
包起來。
// SCSS
@use "sass:list";
$text-colors: #333, #555, #777;
$background-colors: #eee, #ddd;
// 將兩個列表合併,並用逗號分隔
$all-colors: list.join($text-colors, $background-colors, $separator: comma);
// $all-colors 現在是 (#333, #555, #777, #eee, #ddd)
.first-color {
color: list.nth($all-colors, 1); // #333
}
/* CSS */
.first-color {
color: #333;
}
list.index()
: 尋找項目在列表中的位置這個函式會回傳某個值在 List 中第一次出現的位置 (索引)。
如果該值不存在於列表中,則回傳 null
。
list.index($list, $value)
用途:檢查某個值是否存在,或取得其索引值。
回傳值:一個數字 (索引值) 或 null
。
// SCSS
@use "sass:list";
$z-layers: "modal", "dropdown", "tooltip";
// 尋找 'dropdown' 的位置,回傳 2
$dropdown-index: list.index($z-layers, "dropdown");
// 尋找 'header' 的位置,回傳 null
$header-index: list.index($z-layers, "header");
.dropdown-menu {
// 可以根據索引值來計算 z-index
z-index: $dropdown-index; // 結果為 2
}
@if not $header-index {
// 由於 $header-index 是 null,這個警告會被觸發
@warn "在 z-layers 列表中找不到 'header'。";
}
/* CSS */
.dropdown-menu {
z-index: 2;
}
在編譯過程中,你還會在 Console(終端機)中看到警告訊息:Warning: 在 z-layers 列表中找不到 'header'。
透過使用這些 List 函式,昨天學到的 Function,我們可以建立一個非常實用的 z-index
管理系統。
假設我們定義了一個關於 z-index
層級順序的 List:
// SCSS
@use "sass:list";
// 統一管理 z-index 層級
$z-layers: "behind", "default", "dropdown", "sticky", "modal", "overlay";
// 建立一個名叫 z 的函式來取得指定層級的 z-index 值
@function z($layer-name) {
$index: list.index($z-layers, $layer-name);
@if $index == null {
@error "在 $z-layers 中找不到 '#{$layer-name}' 這個層級。請檢查拼寫是否正確。";
}
// list.index 回傳的是索引值,剛好可以直接當作 z-index 使用
@return $index;
}
// 使用函式來設定 z-index
.modal {
// z("modal") 會回傳 5
z-index: z("modal");
}
.dropdown-menu {
// z("dropdown") 會回傳 3
z-index: z("dropdown");
}
.footer {
// z("behind") 會回傳 1,如果需要,我們可以夠過算數讓它變成負值
z-index: z("behind") * -1;
}
.some-element {
// 如果傳入一個不存在的名稱,編譯時就會報錯,可能無法完整編譯
z-index: z("non-existent-layer");
}
編譯後的結果:
/* CSS */
.modal {
z-index: 5;
}
.dropdown-menu {
z-index: 3;
}
.footer {
z-index: -1;
}
在這個範例中,我們利用 list.index()
來找每個區塊對應的順序,讓 z-index
的管理變得集中、更容易理解。
而且,當你需要調整層級順序,或在中間插入一個新層級時,只需要修改 $z-layers
這一個 List,所有有使用這個 z()
函式的地方都會自動更新,大大提升了效率。
好的!今天就先到這裡囉!
之前沒有好好研究過 SCSS 中的 List,今天真正了解後,覺得有點相見恨晚,早點認識的話,我的 Code 可能就會更整齊了。XD
明天,我們再來好好研究 SCSS 中的 Map。
感謝看到最後的你,若你覺得獲益良多,請不要吝嗇給我按個喜歡。❤️
如果你喜歡我的創作,還想看看其他有趣的分享與日常,
可以追蹤我的 IG @im1010ioio,或者是🧋送杯珍奶鼓勵我,謝謝你🥰。