2024年6月11日至13日,CSS 工作組 (CSSWG) 在西班牙科魯尼亞舉行了今年的第二次面對面會議,會議議程涵蓋了 CSS 語言的諸多新特性和改進。繼2023年帶來嵌套、容器查詢和样式查詢以及has:
選擇器等令人矚目的進步之後,2024年將迎來更多突破性更新。無論像內聯條件語句這樣的新特性剛剛起步,還是長期項目即將收尾,2024年已經充滿了令人興奮的發展——而我們才剛剛進入7月份!
本文將分享一些在本次會議上探討的、我認為最有趣和最重要的 CSS 新特性。需要注意的是,這並非會議討論的精確記錄,而是對會議中重點關注的 CSS 主要主題的概述。實際上,這些特性已經醞釀多年,討論主要集中在具體案例和新增強功能上,而不是定義完整的規範;在一個會議中完成這項工作是不可能的。
您可以查看 CSSWG 會議議程上討論的具體問題。
if()
函數的前景自從 CSS 自定義屬性在 2016 年左右獲得可靠的支持以來,人們就嘗試了許多方法,在不依賴 JavaScript 的情況下根據自定義屬性值應用特定樣式。最早的條件樣式解決方法之一是 Roman Komarov 在 2016 年的“CSS 變量的條件”中提出的。從那時起,許多其他的“技巧”都被記錄下來,用於在 CSS 中進行條件聲明(包括 Ana Tudor 在 CSS-Tricks 上提出的極其巧妙的方法)。事實上,CSSWG 成員 Lea Verou 在她最近的文章“CSS 中的內聯條件語句,現在?”中列出了討論和比較這些解決方法的完整列表。
可以肯定的是,社區一直渴望一種使用自定義屬性應用樣式的條件方法。如今,我們有了一個能夠完成這項任務的樣式查詢規範,但它有一些與瀏覽器支持無關的限制。最大的限制是什麼? 我們無法直接設置被查詢容器的樣式,因此我們需要在 HTML 中圍繞該容器添加某種包裝元素。
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
……以及樣式查詢:
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
if()
函數可能的樣子在 CSSWG 方面,早在 2018 年就討論過添加 if()
函數。在今年 6 月 13 日——是的,六年後——CSSWG 決定開始為 CSS 開發 if()
函數。儘管它看起來不錯,但至少在兩年內不要指望在瀏覽器中看到 if()
! (這是 Lea 的非官方估計。)我們可能需要等待更長時間才能獲得足夠的瀏覽器支持,才能在生產環境中可靠地使用它。規範草案才剛剛開始,許多事情必須首先通過測試。作為參考,CSS 變量工作草案始於 2012 年,直到 2016 年才獲得廣泛的瀏覽器支持。
語法方面,if()
可能會藉鑑 JavaScript 和其他編程語言的三元運算符,結構如下:
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
……其中 a 是我們正在檢查的自定義屬性,b 和 c 是可能的條件返回值。要檢查樣式,將使用內聯樣式 style(--my-property: value)
。
<code>if(a ? b : c)</code>
即使 CSS 中不使用 ?
,並且 :
在其他地方也有不同的含義,我認為這種語法是大多數人最熟悉的,更不用說它還允許無縫的條件鏈接。
<code>.forecast { background-color: if(style(--weather: clouds) ? var(--clouds-color): var(--default-color)); }</code>
if()
函數的改進儘管這些可能不會出現在初始版本中,但了解 if()
在現在和未來某個時間點可能發生的變化仍然很有趣:
style()
查詢檢查自定義屬性,但我們也可以使用內聯 media()
查詢檢查媒體特性,或者使用內聯 support()
檢查用戶代理是否支持特定屬性。 <code>.forecast { background-color: if( style(--weather: clouds) ? var(--clouds-color): style(--weather: sunny) ? var(--sunny-color); style( --weather: rain) ? var(--rain-color): var(--default-color) ); }</code>
if()
中,例如,如果我們在 clamp()
或 round()
函數中,我們可以進行計算而無需 calc()
。 去年,視圖過渡 API 使我們能夠在導航網頁和狀態之間創建無縫過渡。無需組件或框架,無需動畫庫——只需使用少量的 JavaScript 和純 HTML 和 CSS 即可。視圖過渡的第一個實現很久以前就已集成到瀏覽器中,但它基於 Chrome 定義的實驗性函數,並且僅限於兩個狀態之間的過渡(單頁視圖過渡),而不支持不同頁面之間的過渡(即多頁視圖過渡),而這正是我們大多數開發人員所渴望的。模仿原生應用程序行為的可能性令人興奮!
這就是為什麼 CSS 視圖過渡模塊級別 2 如此出色,也是為什麼它是本文中介紹的所有 CSS 新增功能中最受我喜愛的原因。是的,此特性帶來了開箱即用的跨頁面無縫過渡,但真正重要的是它消除了實現此功能對框架的依賴。我們可以回溯到純 CSS 和 JavaScript,而不是使用庫——例如 React 一些路由庫。
當然,在某些複雜程度上,視圖過渡 API 可能力不從心,但對於我們只想進行頁面過渡而無需承擔引入框架的性能成本的無數情況來說,它非常出色。
當我們從同一來源導航到兩個頁面之間時,會觸發視圖過渡。在這種情況下,導航可能是單擊鏈接、提交表單或使用瀏覽器按鈕來回移動。相比之下,在同一來源頁面之間使用搜索欄之類的操作不會觸發頁面過渡。
兩個頁面——我們要離開的頁面和我們要導航到的頁面——都需要使用 @view-transition
at-rule 並將 navigation
屬性設置為 auto
來選擇加入過渡:
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
當兩個頁面都選擇加入過渡時,瀏覽器會對這兩個頁面進行“快照”,並將“之前”頁面平滑地淡入“之後”頁面。
在該視頻中,您可以看到舊頁面如何淡入新頁面,這要歸功於一整套新的偽元素,這些偽元素在過渡過程中持續存在,並使用 CSS 動畫來產生效果。瀏覽器將使用唯一的 view-transition-name
屬性對元素的快照進行分組,該屬性在我們可以引用的過渡上設置唯一標識符,並且該標識符捕獲在包含頁面上所有過渡的 ::view-transition
偽元素中。
您可以將 ::view-transition
視為所有頁面過渡的 :root
元素,它將同一默認動畫上的所有頁面過渡部分組合在一起。
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
請注意,每個過渡都位於一個 ::view-transition-group
中,該組包含一個 ::view-transition-image-pair
,而該對又包含“舊”和“新”頁面快照。我們可以根據需要在其中添加任意數量的組,並且它們都包含一個帶有兩個快照的圖像對。
快速示例:讓我們使用 ::view-transition
“根”作為參數來選擇頁面上的所有過渡,並在舊快照和新快照之間創建滑動動畫。
<code>if(a ? b : c)</code>
如果我們在頁面之間導航,則整個舊頁面將向左滑動,而整個新頁面將從右側滑入。但是我們可能希望阻止頁面上的某些元素參與過渡,因為它們在頁面之間持續存在,而其他所有內容都從“舊”快照移動到“新”快照。
這就是 view-transition-name
屬性的關鍵所在,因為我們可以對某些元素進行快照,並將它們放入與其他所有內容分開的 ::view-transition-group
中,以便單獨處理它們。
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
您可以在 GitHub 上找到它的實時演示。請注意,在我撰寫本文時,瀏覽器支持僅限於 Chromium 瀏覽器(即 Chrome、Edge、Opera)。
對於跨文檔視圖過渡,我們有很多值得期待的事情。例如,如果我們有幾個具有不同 view-transition-name
的元素,我們可以為它們提供一個共享的 view-transition-class
來在一個位置設置它們的動畫樣式——甚至可以使用 JavaScript 進一步自定義視圖過渡,以檢查頁面是從哪個 URL 進行過渡並相應地進行動畫處理。
在 CSS 中相對於另一個元素定位元素似乎是一件輕而易舉的事情,但實際上需要根據一系列神奇數字來混合使用內邊距屬性(頂部、底部、左側、右側)才能獲得正確的結果。例如,在懸停時在元素左側彈出一個小工具提示可能在 HTML 中看起來像這樣:
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
……以及使用當前方法的 CSS:
<code>if(a ? b : c)</code>
不得不更改元素的定位和內邊距值並不是世界末日,但這確實感覺應該有一種更簡單的方法。此外,最後一個示例中的工具提示非常脆弱;如果屏幕太小或我們的元素太靠左,則工具提示將隱藏或溢出屏幕邊緣。
CSS 錨點定位是 CSSWG 會議上討論的另一個新特性,它有望使這類事情變得容易得多。
基本思想是我們建立兩個元素:
這樣,我們就有一種更聲明式的方法來關聯一個元素並將其相對於錨定元素定位。
首先,我們需要使用新的 anchor-name
屬性創建我們的錨點元素。
稍微更改一下我們的標記:
<code>.forecast { background-color: if(style(--weather: clouds) ? var(--clouds-color): var(--default-color)); }</code>
我們為其指定一個唯一的虛線縮進作為其值(就像自定義屬性一樣):
<code>.forecast { background-color: if( style(--weather: clouds) ? var(--clouds-color): style(--weather: sunny) ? var(--sunny-color); style( --weather: rain) ? var(--rain-color): var(--default-color) ); }</code>
然後,我們使用 position-anchor
屬性以及 fixed
或 absolute
定位將 .tooltip
關聯到 .anchor
。
<code>.my-element { width: if(media(width > 1200px) ? var(--size-l): var(--size-m)); }</code>
.tooltip
目前位於 .anchor
的頂部,但我們應該將其移動到其他位置以防止這種情況。移動 .tooltip
的最簡單方法是使用新的 inset-area
屬性。讓我們假設 .anchor
位於 3×3 網格的中間,我們可以通過為其分配行和列來在網格中定位工具提示。
inset-area
屬性為 .tooltip
在特定行和列中的位置採用兩個值。它使用物理值(例如 left、right、top 和 bottom)以及根據用戶的書寫模式的邏輯值(例如 start 和 end)以及共享的 center 值進行計數。它還接受引用 x 和 y 坐標的值,例如 x-start 和 y-end。所有這些值類型都是表示 3×3 網格上空間的方法。
例如,如果我們希望 .tooltip
相對於錨點的右上角定位,我們可以像這樣設置 inset-area
屬性:
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
最後,如果我們希望我們的工具提示跨越網格的兩個區域,我們可以使用 span-
前綴。例如,span-top
將 .tooltip
放置在網格的頂部和中心區域。如果我們希望跨越整個方向,我們可以使用 span-all
值。
我們沒有錨點的示例問題之一是工具提示可能會溢出屏幕。我們可以使用另一個新屬性(這次稱為 position-try-options
)結合新的 inset-area()
函數來解決此問題。
(是的,有一個 inset-area
屬性和一個 inset-area()
函數。這是我們必須記住的一個!)
position-try-options
屬性接受逗號分隔的回退位置列表,用於當 .tooltip
溢出屏幕時。我們可以提供一系列 inset-area()
函數,每個函數都包含與 inset-area
屬性相同的屬性值。現在,每次工具提示超出屏幕時,都會“嘗試”下一個聲明的位置,如果該位置導致溢出,則會嘗試下一個聲明的位置,依此類推。
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
這是一個非常新穎的概念,需要一些時間來理解。 CSSWG 成員 Miriam Suzanne 在一段非常值得觀看的視頻中與 James Stuckey Weber 坐下來討論和嘗試錨點定位。
如果您正在尋找 TL;DW,Geoff Graham 對該視頻做了筆記。
為了簡潔起見,這裡沒有介紹錨點定位的許多方面,特別是新的 anchor()
函數和 @try-position
at-rule。 anchor()
函數返回錨點邊緣的計算位置,這提供了對工具提示內邊距屬性的更多控制。 @try-position
at-rule 用於定義要在 position-try-options
屬性上設置的自定義位置。
我的直覺是,對於絕大多數用例來說,使用 inset-area
將足夠強大。
前面我說過,本文不會對 CSSWG 會議上進行的討論進行精確的複述,而只是對 CSS 的新規範的廣泛介紹,由於其新穎性,這些規範必然會在這些會議上出現。甚至還有一些特性我們根本沒有時間在本綜述中進行審查,這些特性仍在討論中(咳嗽,砌體)。
有一點可以肯定的是:規範不是在某個真空環境中在一兩次會議上製定的;它需要數十位優秀的作者、開發人員和用戶代理的共同努力,才能將我們每天在 CSS 工作中使用的內容——更不用說我們將來會使用的內容——變為現實。
我還有機會與 CSSWG 的一些優秀的開發人員交談,我發現他們從會議中獲得的最大收穫很有趣。您可能會期望 if()
位於他們的列表頂部,因為這是社交媒體上正在討論的內容。但 CSSWG 成員 Emilio Cobos 告訴我,例如,letter-spacing
屬性本質上是有缺陷的,並且沒有簡單的解決方案可以解決它與 CSS 當前定義的 letter-spacing
和在瀏覽器中的使用方式相一致的問題。這包括將普通屬性轉換為簡寫屬性可能對代碼庫造成危險的事實。
我們可能認為微不足道的每一個細節都會被仔細分析,以造福網絡並出於對網絡的熱愛。而且,正如我前面提到的,這些事情並非在封閉的真空環境中發生。如果您對 CSS 的未來有任何興趣——無論是跟上 CSS 的發展還是積極參與其中——請考慮以下任何資源。
以上是上次CSSWG會議之後,CSS的東西I&#039;的詳細內容。更多資訊請關注PHP中文網其他相關文章!