Skip to content

Sass @at-root:把規則移出巢狀

Sass @at-root 跳出巢狀

巢狀 的規則會繼承父選取器。@at-root 打破這件事:寫在裡面,輸出在最外層。

基本用法

scss
.card {
  padding: 16px;

  @at-root .standalone {
    color: red;
  }
}
css
.card { padding: 16px; }
.standalone { color: red; }   /* 沒有 .card 前綴 */

也可以包住一整段:

scss
.card {
  padding: 16px;

  @at-root {
    .a { color: red; }
    .b { color: blue; }
  }
}

主要用途:組織與產出分開

它的價值在於「程式碼位置」與「輸出位置」可以不一樣。元件相關的東西全寫在同一個區塊裡,方便維護;產出卻是乾淨的頂層規則:

scss
.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

& 取得父選取器名稱,再組出獨立的類別:

scss
.card {
  padding: 16px;

  @at-root #{&}__footer {
    border-top: 1px solid #eee;
  }
}
css
.card { padding: 16px; }
.card__footer { border-top: 1px solid #eee; }

不過這跟直接寫 &__footer 產出完全一樣,而且後者短得多:

scss
.card {
  padding: 16px;

  &__footer { border-top: 1px solid #eee; }
}

BEM 用 & 就好

@at-root #{&}__footer 只有在 父選取器本身有巢狀 時才有差別。一般情況用 & 就對了,見 BEM 與 & 的搭配

without:跳出媒體查詢

預設 @at-root 只跳出 選取器@media 仍然保留:

scss
@media (min-width: 768px) {
  .card {
    @at-root .a { color: red; }
  }
}
css
@media (min-width: 768px) {
  .a { color: red; }   /* 還在 media 裡 */
}

要連 @media 一起跳出來,加 without: media

scss
@media (min-width: 768px) {
  .card {
    @at-root (without: media) {
      .a { color: red; }
    }
  }
}
css
.a { color: red; }   /* 完全在外層 */
參數效果
(without: media)跳出媒體查詢
(without: rule)跳出選取器(預設行為)
(without: all)全部跳出
(with: rule)反過來,只保留 選取器

跳出媒體查詢是危險操作

讀的人會以為那段樣式只在該斷點生效,實際上是全域的。真的要全域樣式,就寫在 @media 外面。

別過度使用

@at-root 讓「程式碼寫在哪」與「樣式輸出在哪」不一致,每一次使用都是讓讀的人多想一層。

常常需要它,通常代表巢狀太深或命名該調整了。 用 BEM 讓選取器維持一層,多數情況根本不會需要跳出來,見 巢狀規則

常見問題

@at-root 什麼時候會用到?

當你希望某段樣式在原始碼裡跟著父元件放,但產出時不要帶父選取器的前綴。常見於元件內部要定義動畫、或要輸出一個不受巢狀影響的全域類別。

without 參數可以做什麼?

指定要跳出哪一類包覆,可以只跳出媒體查詢而保留選取器,或反過來。不加參數時預設只跳出選取器,媒體查詢仍然會保留。

keyframes 一定要用 @at-root 嗎?

不用。Sass 已經會自動把 @keyframes 提到最外層,寫在巢狀裡也不會被加上父選取器。真正需要處理的是動畫名稱的唯一性,那要靠命名或插值。

常常需要用它是不是代表結構有問題?

多半是。它會讓原始碼的位置與產出的位置不一致,讀的人得多想一層。偶爾用它換來組織上的方便沒問題,整份檔案到處都是就該重新檢視巢狀的深度與命名。

延伸閱讀