Sass @at-root:把規則移出巢狀
巢狀 的規則會繼承父選取器。@at-root 打破這件事:寫在裡面,輸出在最外層。
基本用法
.card {
padding: 16px;
@at-root .standalone {
color: red;
}
}.card { padding: 16px; }
.standalone { color: red; } /* 沒有 .card 前綴 */也可以包住一整段:
.card {
padding: 16px;
@at-root {
.a { color: red; }
.b { color: blue; }
}
}主要用途:組織與產出分開
它的價值在於「程式碼位置」與「輸出位置」可以不一樣。元件相關的東西全寫在同一個區塊裡,方便維護;產出卻是乾淨的頂層規則:
.modal {
animation: modal-in 0.3s;
// 這個動畫只有 .modal 用得到,寫在旁邊比較好找
@at-root {
@keyframes modal-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: none; }
}
}
}@keyframes 其實不需要 @at-root
Sass 本來就會把 @keyframes 提到最外層,不會加上父選取器。上面那樣寫只是讓意圖更明確。真正要注意的是 動畫名稱是全域的,元件庫裡要自己加前綴避免撞名。
搭配 BEM
用 & 取得父選取器名稱,再組出獨立的類別:
.card {
padding: 16px;
@at-root #{&}__footer {
border-top: 1px solid #eee;
}
}.card { padding: 16px; }
.card__footer { border-top: 1px solid #eee; }不過這跟直接寫 &__footer 產出完全一樣,而且後者短得多:
.card {
padding: 16px;
&__footer { border-top: 1px solid #eee; }
}BEM 用 & 就好
@at-root #{&}__footer 只有在 父選取器本身有巢狀 時才有差別。一般情況用 & 就對了,見 BEM 與 & 的搭配。
without:跳出媒體查詢
預設 @at-root 只跳出 選取器,@media 仍然保留:
@media (min-width: 768px) {
.card {
@at-root .a { color: red; }
}
}@media (min-width: 768px) {
.a { color: red; } /* 還在 media 裡 */
}要連 @media 一起跳出來,加 without: media:
@media (min-width: 768px) {
.card {
@at-root (without: media) {
.a { color: red; }
}
}
}.a { color: red; } /* 完全在外層 */| 參數 | 效果 |
|---|---|
(without: media) | 跳出媒體查詢 |
(without: rule) | 跳出選取器(預設行為) |
(without: all) | 全部跳出 |
(with: rule) | 反過來,只保留 選取器 |
跳出媒體查詢是危險操作
讀的人會以為那段樣式只在該斷點生效,實際上是全域的。真的要全域樣式,就寫在 @media 外面。
別過度使用
@at-root 讓「程式碼寫在哪」與「樣式輸出在哪」不一致,每一次使用都是讓讀的人多想一層。
常常需要它,通常代表巢狀太深或命名該調整了。 用 BEM 讓選取器維持一層,多數情況根本不會需要跳出來,見 巢狀規則。
常見問題
@at-root 什麼時候會用到?
當你希望某段樣式在原始碼裡跟著父元件放,但產出時不要帶父選取器的前綴。常見於元件內部要定義動畫、或要輸出一個不受巢狀影響的全域類別。
without 參數可以做什麼?
指定要跳出哪一類包覆,可以只跳出媒體查詢而保留選取器,或反過來。不加參數時預設只跳出選取器,媒體查詢仍然會保留。
keyframes 一定要用 @at-root 嗎?
不用。Sass 已經會自動把 @keyframes 提到最外層,寫在巢狀裡也不會被加上父選取器。真正需要處理的是動畫名稱的唯一性,那要靠命名或插值。
常常需要用它是不是代表結構有問題?
多半是。它會讓原始碼的位置與產出的位置不一致,讀的人得多想一層。偶爾用它換來組織上的方便沒問題,整份檔案到處都是就該重新檢視巢狀的深度與命名。