Sass 父選取器 &:組合類別名、狀態與反向嵌套
在 巢狀 裡,& 代表 目前所在位置的完整父選取器。它與一般巢狀的差別只有一個字:空白。巢狀寫 .title 會產出 .card .title,寫 &.title 會產出 .card.title。
一、接偽類與偽元素
最常見的用法,:hover、:focus 這類 偽類 必須黏在選取器後面:
.btn {
color: #2965f1;
&:hover {
color: #1b4dc1;
}
&::after {
content: "→";
}
}.btn { color: #2965f1; }
.btn:hover { color: #1b4dc1; }
.btn::after { content: "→"; }少寫一個 & 意思就變了
:hover 直接巢狀會變成 .btn :hover,選到的是「.btn 裡面被滑鼠移過的任何元素」,完全不同的東西。
二、接修飾類別
同一個元件的不同變體:
.btn {
padding: 8px 16px;
&.is-active {
background: #2965f1;
}
&.is-disabled {
opacity: 0.5;
}
}.btn.is-active { background: #2965f1; }
.btn.is-disabled { opacity: 0.5; }三、串接成 BEM 類別名
& 後面接文字會直接接上去,這是 BEM 寫法的基礎:
.card {
padding: 16px;
&__title {
font-size: 20px;
}
&--featured {
border: 2px solid #2965f1;
}
}.card { padding: 16px; }
.card__title { font-size: 20px; }
.card--featured { border: 2px solid #2965f1; }產出的選取器都只有一層,優先權 維持在 0,1,0,同時原始碼裡 .card 相關的樣式全集中在一起,這是 & 最實用的地方。
這樣寫全域搜尋不到 .card__title
&__title 在原始碼裡不是字串 .card__title,用編輯器全域搜尋類別名會找不到。這是 BEM 串接寫法唯一的代價,取捨見 BEM 與 & 的搭配。
四、反向嵌套
& 不一定要在最前面。放到後面,父選取器就變成祖先:
.card {
background: #fff;
.theme-dark & {
background: #1a1a1a;
}
}.card { background: #fff; }
.theme-dark .card { background: #1a1a1a; }這個寫法讓「外層條件影響內層元件」的樣式,可以寫在元件自己的檔案裡,不必散到主題檔去。常見於深色模式、[dir="rtl"]、.no-js 這類全域旗標。
五、一行裡出現多次
& 可以重複使用:
.item {
& + & {
margin-top: 8px;
}
}.item + .item {
margin-top: 8px;
}「除了第一個以外都加上間距」的經典寫法。
六、搭配插值
#{&} 取得父選取器的字串形式:
.card {
@at-root #{&}__footer {
padding-top: 12px;
}
}也常拿來除錯,確認目前巢狀到哪:
.a .b {
@debug #{&}; // .a .b
}兩個限制
一、父選取器是串列時不能串接文字。
.a, .b {
&__title { color: red; } // ❌ 編譯錯誤
}& 這時代表 .a, .b 兩條,接上 __title 會產生無效的選取器。
二、元素選取器不能串接文字。
h1 {
&-sub { color: red; } // ❌ h1-sub 不是有效選取器
}遇到限制就改用插值
真的需要組出複雜選取器時,#{&} 搭配字串處理通常繞得過去,但先想想是不是命名該調整了。
常見問題
& 和直接巢狀寫選取器差在哪?
巢狀寫選取器會在父子之間補一個空白,變成 後代選取器;& 則是直接接在父選取器後面,中間沒有空白。所以 :hover、修飾類別、BEM 的元素名這類要黏在一起的寫法都必須用 &。
& 可以放在選取器中間嗎?
可以放在任何位置。寫成 .dark & 就變成反向嵌套,產出 .dark .card 這種祖先在前的選取器,適合處理外層主題類別控制內層元件的情境。
為什麼 &-title 這種寫法會出錯?
多數情況它是合法的,出錯是因為父選取器不是單純的類別名,例如父層是 .a, .b 這種選取器串列,或是 h1 這種元素選取器接上文字後變成無效選取器。這時 Sass 會直接報錯。
& 可以放進插值裡使用嗎?
可以,寫成 #{&} 就會取得目前父選取器的字串,常用來組合更複雜的選取器,或在 @debug 時確認目前的巢狀位置。它得到的是選取器串列,不是單純字串。