2023-2024 的 CSS 有什麼新的語法?

Eason Lin
14 min readJun 23, 2024

--

Photo by Kalen Emsley on Unsplash

大家好,今年很快地又要過半了。這篇文我想來簡單整理一下近期的 CSS 有什麼相對較新的、我個人覺得很新鮮的語法。

2023-2024 的 CSS 新增了什麼有趣的新語法?

block 的元素可以垂直置中了

約莫今年四月,在 Firefox 完成實作後,所有主瀏覽器已經讓 Block Element 支援垂直置中的功能。例如:

div 的 display 預設就是 block

如果在元素高度為固定的情況,以往我傾向用 Flexbox 去做到垂直置中,現在使用 align-content: center 就能做到了;當然,使用 padding 去做上下內距相等值的拓寬也可以。

文件參閱:https://developer.mozilla.org/en-US/docs/Web/CSS/align-content

支援度:https://caniuse.com/mdn-css_properties_align-content_block_context

Subgrid

Grid 是一種網格模組,SubGrid 就是在父層的 Grid 裡面再套一個 Grid,區別在於它會對齊父網格的行和列定義,並繼承父層如 gap 的部分屬性,例如:

<div class="container">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
<div class="subgrid-container">
<div class="subgrid-item">Subgrid Item 1</div>
<div class="subgrid-item">Subgrid Item 2</div>
<div class="subgrid-item">Subgrid Item 3</div>
</div>
<div class="item">Item 4</div>
<div class="item">Item 5</div>
<div class="item">Item 6</div>
</div>
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: auto;
gap: 10px;
border: 2px solid black;
padding: 10px;
}

.item {
border: 1px solid #333;
padding: 20px;
background-color: #f0f0f0;
}

.subgrid-container {
display: grid;
grid-column: 1 / 4;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
border: 2px dashed red;
}

.subgrid-item {
border: 1px solid #666;
padding: 10px;
background-color: #e0e0e0;
}
實際渲染畫面

這邊可以看到:

.subgrid-container {
display: grid;
grid-column: 1 / 4;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
border: 2px dashed red;
}

我們使用 grid-column: 1 / 4 讓其佔用三個網格。

grid-template-columns 我們採用了 subgrid,因此它會沿用父層的 grid-template-columns: 1fr 1fr 1frgap: 10px

相較於這篇文章的其他新 CSS 語法,subgrid 適用於更進階和複雜的 CSS 排版,其功能也相當多且強大,有空會再寫一篇文專門介紹。

文件參閱:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid

支援度:https://caniuse.com/css-subgrid

更靈活的 CSS 變數

如果在開發上是使用原生 CSS 而非例如 CSS Modules 或 Sass 等工具或庫,應該會對這樣的語法不陌生:

:root {
--blue: #6495ED;
}

p {
color: var(--blue);
}

若在樣式生效的 block 內有宣告變數,CSS 會繼承並選用該樣式:

<p>text outside container with color: var(--blue);</p>
<div class="container">
<p>text inside container with color: var(--blue);</p>
</div>
:root {
/* 較淺的藍色*/
--blue: #6495ED;
}

.container p {
/* 較深的藍色*/
--blue: #000080;
}

p {
color: var(--blue);
}
實際渲染結果

CSS 的 var 可以做到 fallback 避免因為變數不存在導致樣式失效的情況:

h3 {
/* 採用 red */
color: var(--primary-color, red);
}

h4 {
/* 採用 blue*/
--primary-color: blue;
color: var(--primary-color, red);
}

我們可以使用 @property 來定義變數要不要進行繼承。例如:

<div class="parent">
<span>Parent element</span>
<div class="child">
<span>Child element with inheritance disabled for --box-color.</span>
</div>
</div>
@property --box-color {
syntax: "<color>";
/* 因為這裡設定 inherits 為 false, 所以 child 不會繼承 parent 的 --box-color */
inherits: false;
initial-value: gold;
}

.parent {
--box-color: silver;
background-color: var(--box-color);
}

.child {
width: 80%;
height: 40%;
background-color: var(--box-color);
}
實際渲染畫面

在這個例子中,雖然說 .parent 有定義 --box-colorsilver,但因為我們運用 @property --box-colorinherits 設為 false.child 就不會採用 .parentsilver,而是會採用 gold 作為初始值。

文件參閱:https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties

支援度:https://caniuse.com/mdn-css_at-rules_property

:has()

:has 是 CSS 的一個 pseudo class,括號中可以傳入一個選擇器作為參數。例如:

<section>
<article>
<h1>Morning Times</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
</p>
</article>
<article>
<h1>Morning Times</h1>
<h3>Get ready to be surprised!</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
</p>
</article>
</section>
section {
display: flex;
gap: 20px;
}
article {
border: 2px solid #000;
padding: 16px;
}
h1 {
font-size: 48px;
}
h1,
h3,
p {
margin: 0;
}

h1:has(+ h3) {
color: red;
}
實際渲染畫面

+ 是接續兄弟選擇器(Next-sibling combinator),若撰寫 a + b { /* ... */ } ,當 a 的下一個兄弟元素為 b,內部樣式就會生效。

以上述例子來看,

h1:has(+ h3) {
color: red;
}
<article>
<h1>Morning Times</h1>
<h3>Get ready to be surprised!</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
</p>
</article>

這段 HTML 就會生效;相對地若 h1 的下一個元素不是 h3 便不會生效。以下範例會讓擁有 h3 子元素的 article 套上黃色背景:

article:has(h3) {
background-color: yellow;
}

文件參閱:https://developer.mozilla.org/zh-CN/docs/Web/CSS/:has

支援度:https://caniuse.com/css-has

:is()

:is 中可以傳入多個選擇器做為參數,簡化共用樣式的冗長寫法。例如:

<ul class="red-text">
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
</ul>

<ol class="red-text">
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
<li>Lorem ipsum dolor sit amet.</li>
</ol>
:is(ol, ul).red-text li {
color: red;
}
實際渲染畫面

:is 會選擇列表中任意一個選擇器可以選擇的元素。這樣講有點抽象,例如:

:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) :is(ul, menu, dir) {
color: red;
}

當這樣寫的時候,上一層會選擇下一層每一個參數的選擇器:

也就是類似於這樣的寫法:

/* 等同下列樣式: */
ol ol ul,
ol ul ul,
ol menu ul,
ol dir ul,
ol ol menu,
ol ul menu,
ol menu menu,
ol dir menu,
ol ol dir,
ol ul dir,
ol menu dir,
ol dir dir,
ul ol ul,
ul ul ul,
ul menu ul,
ul dir ul,
ul ol menu,
ul ul menu,
ul menu menu,
ul dir menu,
ul ol dir,
ul ul dir,
ul menu dir,
ul dir dir,
menu ol ul,
menu ul ul,
menu menu ul,
menu dir ul,
menu ol menu,
menu ul menu,
menu menu menu,
menu dir menu,
menu ol dir,
menu ul dir,
menu menu dir,
menu dir dir,
dir ol ul,
dir ul ul,
dir menu ul,
dir dir ul,
dir ol menu,
dir ul menu,
dir menu menu,
dir dir menu,
dir ol dir,
dir ul dir,
dir menu dir,
dir dir dir {
color: red;
}

文件參閱:https://developer.mozilla.org/zh-CN/docs/Web/CSS/:is

支援度:https://caniuse.com/css-matches-pseudo

巢狀

我們已經可以直接在原生的 CSS 檔案中寫巢狀了,這個功能在去年年底已經被所有主流瀏覽器實作出來。

CSS Nesting is here!(Finally…)

文件參閱:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting

支援度:https://caniuse.com/css-nesting

預處理器/後處理器死了嗎?

不論國內外,我們總能每隔幾天就看到有人在說 “PHP is dead.”, “jQuery is dead” 這類的論述;在 CSS 巢狀正式被實作時,我確實也看過有人在 Medium 發文說 “Stop using CSS preprocessor” 這類的論述,我個人針對不論是前面兩個與 CSS 較無相關或是不要再使用預處理器這類的論述都是比較持反對意見的,原因很簡單:

所有知名的庫、框架、工具甚至程式語言都是為了解決特定問題而誕生的。

CSS 相較幾年前確實有了不少躍進,然而相對於預處理器,像是 Mixin, for 這類很常用的語法目前依然是不支援的;此外當然還有像是 autoprefixer 這類解決跨瀏覽器 CSS 屬性問題的工具。

此外,雖說主流瀏覽器都會在使用者不知道的情況下偷偷更新,但像是 iPhone 有些人會刻意卡在某個版本,Safari 沒有一起更新的狀態下,就會有瀏覽器舊導致部分樣式無法採用的窘境,因此在執行上是否要用新的 CSS 語法,還是要與需求方確認最低需要支援的瀏覽器版號,避免提升後續的維護成本。

--

--

Eason Lin
Eason Lin

Written by Eason Lin

Frontend Web Developer | Books

No responses yet