測試瀏覽器原生 CSS Nesting 能不能完全做到 SCSS Nesting 的功能

巢狀CSS (CSS nesting)終於從 Chrome 版本號 120 開始支援,去年(2023/8左右) Firefox 就支援 CSS nesting 了,以前寫 SCSS 的老人們可以放心直接寫,不用再編譯嗎? 並沒有,本文就來做一些實測。

巢狀結構寫法,有時候可以提升 CSS 樣式碼的易讀性和可維護性,如下圖所示,

左邊是 SCSS,右邊是編譯出來給瀏覽器看的 CSS。
人類也可以直接寫出右邊的 code,但是要多打了一大堆重複的部份,
反觀左邊的看起來輕便不少。
如果是用程式碼字數來算錢的,那左邊就是讓國家 GDP 和稅收大幅下降的罪人,
如果是依照檔案數量來算錢,那一個專案中多出一倍的檔案(原始檔和編譯後的檔案),還有一堆 npm 工具產生的檔案和資料夾,大家都將成為新的富翁!

巢狀 CSS 寫法很舒服,但是以前的網頁瀏覽器都看不懂,
開發者必須要用 SCSS/SASS 這種預處理器(preprocessors) 把 CSS 先編譯過,樣式寫得好不好先不論,整個編譯 CSS/JS 相關 toolchain 的演進又是一串辛酸史。
現在瀏覽器直接內建支援了!
距離工具自由可能又更近了一步。

雖然蘋果大魔王 iOS16.4 以下都不支援 瀏覽器原生的 CSS nesting,開發者可能要兩三年後 iOS 20 公開發布,iPhone 出到 19 了,大家把 iOS 作業系統都升級上來了,才敢放心在專案中使用。
不過還是值得先試試,
至少看看瀏覽器原生的,能不能做出跟 SCSS Nesting 一模一樣的功能?
直接上範例樣式,這樣每次回來看,就知道支援度到哪邊…

把 media query 放進去

(可以拉動邊框右下角來模擬不同的視窗大小)

 .test1{
        padding:5px 10px;
        background:#ccc;
        margin:0 auto 10px;
        max-width:1000px;
        width:100%;
        @media (orientation:landscape){
            background:#000;
        }
        .landscape{color:#ccc}
        &:after{
            content:'';
            display: block;
            width: 100%;
            background: yellow;
            margin-top: 10px;
            @media (max-width:300px){
                background:brown;color:#fff;
            }
        }
 
    }

會發現沒有預期變成咖啡色,因為包在**偽元素裡面的 media query **沒有生效,但是如果用 SCSS 編譯出來是正常的。
網路上查到說是 W3C 的規格 The nesting selector cannot represent pseudo-elements
所以會用偽元素的可能要小心…

多層多組 selector 與各種 combinators

刻意模擬多包幾層的方式,看看是否有不能被包在巢狀裡面的?

.test2{
  .alert, .warning {
    ul, p {
      background:red;color:#fff;margin:0;
    }
    ul{
      list-style:none;padding:0;margin:0;
      ~ p{background:#229241;color:#fff}
      + p{background:#0066cc;color:#fff}
      >li:nth-child(1){
        background:#000;
        &:before{content:'要顯示偽元素';display:inline;color:#ccc}
        &:after{content:'游標移入會變黃色背景';display:inline;color:#ccc}
        &:hover{background:yellow}
      }
    }
  }
}

在巢狀中用上了 nth-child, :hover, ~, +,至少包了兩三層,一切看起來都還正常。

has 選擇器、屬性選擇器和其他

 .test3{
  *{background:#0066cc;color:#fff;list-style:none;padding:0;margin:0}
  li:has(span) {background:#229241}
  li:has(input[type=checkbox]) {background:red}
  #test3{background:yellow;color:#000}
}

在巢狀中選到了 ID,另外還用了 has 選擇器來選 tag 或特定屬性的 input,也都能正常吃到樣式。

CSS 變數與 calc

.test4 {
     width: 200px;
     aspect-ratio: 1;
     --corner1:30%;
     --corner2:70%;
     clip-path: polygon(
      var(--corner1) 0%,
      var(--corner2) 0%,
      100% var(--corner1),
      100% var(--corner2),
      var(--corner2) 100%,
      var(--corner1) 100%,
      0% var(--corner2),
      0% var(--corner1)
     );
 
     background: linear-gradient(to right,#5ec7c1,#20e3b2,#0cebeb);
     display:flex;align-items:center;justify-content:center;
     span{background:#fff;aspect-ratio: 1;display:block;width:calc(var(--corner2) - var(--corner1))}
}

把 CSS 變數寫在巢狀中,還用 calc 來作減法運算,看起來也都正常。
ps.如果要畫八角型還可以用 css 的三角函數,用了 tan 之後就只需要一個變數,可參考 Temani Afif 的範例

巢狀簡寫

碰到 CSS 屬性或是 class name 開頭一樣的,在 SCSS/SASS 還有 Nested Properties 之類的特殊寫法可以用。
例如 background-color, background-repeat…系列的,或 font-weight, font-size… 系列的 CSS 屬性,
或是 UI 元件的內部零件,命名規則像是 .card-body, .card-footer 這種,
一養的東西只要打一次,用巢狀結構包好,編譯後會把省略的地方通通補好。

來測試瀏覽器原生的巢狀 CSS 是否支援這種寫法。

        .test5{
            font: {
                family: 'Noto Sans TC', sans-serif;
                size: 18px;
                weight: 600;
            }
            [class^="card-"] {padding: 5px 10px;color:#fff}
            .card {
                background: #f4f4f4;
                &-head {background: green;}
                &-body {background: #000;}
                &-footer {background: #0066cc;}
            }
        }

結果看起來目前是不支援,可惜。

其他

蒐集一些網路上看到的 CSS nesting 有趣用法。

& 在 CSS 與 SCSS 的差異

看不到貼文此點此 T. Afif @ CSS Challenges
比較使用了 .main &{} 在 CSS 與 SCSS 的差異。


看不到貼文此點此 Lea Verou – Realization: CSS Nesting also allows you to basically do “else” clauses in selectors.

用 not 來達成類似 if-else 的效果

a, abbr, acronym, b, bdo, big, br, cite, code, dfn, em, i, kbd, label, mark,
output, samp, small, span, strong,  sub, sup, time, tt, var {
    outline: 1px dashed hsl(220 10% 50% / 50%) !important;
    :not(&) {
        outline: 1px dashed red !important;
    }
}

這種用法使用了 :not(&) ,就能達成類似 if-else 的目標,除了某些元素之外,通通套用另一組樣式。

心得

必須要等到 iOS16.4 以上,才支援瀏覽器原生的 CSS Nesting,難以避免有人打開網頁後無法正常顯示的問題。
使用者不知道是自己的手機沒升級,看到網頁樣式不正常就打來狗幹窗口,這樣還有人敢用嗎?

而且 SCSS/SASS 常用的 Nesting 寫法,目前瀏覽器原生的 CSS Nesting 還無法完全做到,就更別提 SCSS/SASS 現有的其他功能了。

這功能有點姍姍來遲,遲到甚至調樣式都不一定需要寫 CSS 了,
可能用 TailwindCSS 這種原子式 CSS,
或是一些設計工具產出 code 再修,
或是用 No Code 工具在密密麻麻的屬性視窗中選擇樣式數值之類的,
但這些方式不一定適用所有工作流程,可能還有一堆現有用 SCSS 刻樣式的網站要維護。

除了使用者要將瀏覽器要更新到支援的版本,
才能正常顯示 CSS Nesting 寫的樣式之外,

對於開發人員來說,又有東西需要更新。
像是有些線上或本機的程式碼編輯器,
或是在網頁上幫程式碼加 Syntax highlighting 的套件。
不然碰到這種比較新的寫法,會顯示像是打錯字一樣的提示,或是變色變得怪怪的,
或是每打一行按 Enter 就亂補 } 括號,
會有點討厭喔。

最後又想到還有一種需要寫原生 CSS 的場合,就是排 EDM !
那各種常見的 email client 是否支援 CSS Nesting?
根據 Can I email – CSS Nesting的資料,Gmail 和 Outlook 都是滿江紅,所以還是乖乖寫普通的 CSS 吧。

Tags: #css#css3
分類: 網頁設計

Previous

使用 email 地址檢測服務,防止被拋棄式信箱註冊狂洗優惠

Next

惱人的 Google 通知信系列-網頁無法編入索引-找不到 (404)

相關推薦文章