下一代響應式Web設計:元件驅動式Web設計

語言: CN / TW / HK

自從著名設計師 Ethan Marcotte( @beep )在 A List Apart 上發表了一篇名為《 Responsive Web Design 》的文章之後,響應式網頁設計 (RWD,即 Responsive Web Design) 的身影就出現在了公眾面前。自此就有了響應式 Web 設計這個概念。從提出這個概念到今天已經有十多年的時間了。在這十多年來,CSS 也發生了巨大的變化,新增了很多新的特性,近兩年尤其如此, 近兩年尤其如此(詳細請參閱 2022 年的 CSS 》一 文)。這些變化,對於響 應式Web設計的開發也有較大的改變。Una Kravets( @Una )大神, 在2021的Google I/O 大會上的分享,提出 新的響應式:元件驅動式 Web 設計 。Web 生態即將進入響應式 Web 設計的新時代,並轉變我們對其含義的看法,也為會Web設計帶來新的變化。元件式驅動 Web 設計(或開發)也被稱為是下一代響應式 Web 設計(或開發)。如果你對這方面話題感興趣的話,請繼續往下閱讀。

文章連結:

  1. 《  Responsive Web Design (地址:https://alistapart.com/article/responsive-web-design/)

  2. 2022 年的 CSS (地址:https://www.w3cplus.com/css/what-is-new-css-in-2022.html)

  3. 《新的響應式:元件驅動式 Web 設計》 (地址:https://io.google/2021/session/a1760fa3-879a-4e98-a616-994ca8d3aab5/?lng=zh-CN)

響應式Web設計的發展歷程

既然要聊響應式Web設計,那麼我們就花一點篇幅和時間簡單地瞭解一下其發展歷程。



眾所周知,自從 Tim Berners-Lee 建立第一個 Web頁面 (大約在1991年8月份左右)到90年代末,Web頁面都是非常簡陋的:

直到90年代末20年代初,Web設計和使用者體驗隨著 CSS 的到來才慢慢地有了美感,Web頁面看起來開始像我們今天使用的網站:

正如上圖所示,越往後,Web 的 UI 越來越豐富,越來越漂亮。這也讓 Web 開發人員不得不在佈局、設計和排版等方面花費更多的時間。雖然 Web 開發人員為 Web 佈局花費不少時間,但在這個過程中,也積累了很多不同的佈局方法。在早期,Web 開發人員主要採用 固定寬度 流式佈局 兩種佈局方案來實現 Web 頁面的佈局。特別是流式佈局,自 Glenn Davis 提出和推廣之後,可謂是轟動一時,並且長期以來,都認為流式佈局就是響應式Web佈局。



流式佈局(Liquid Layout)可以調整Web頁面尺寸以適應不同的顯示器解析度或瀏覽器視窗的大小。



來看一個流式佈局的簡單示例:

 Liquid Page Layout Example  @nickpettit  CodePen

(地址:https://codepen.io/nickpettit/pen/dyZwVg)

地址: https://codepen.io/nickpettit)

地址: https://codepen.io/) 



但流式佈局並不是完美的。使用流式佈局的Web頁面上,內容可能會溢位,在較小的螢幕上文字可能會換行,在較大的螢幕上可能會有很多不必的空白。

大多數流體佈局在 800px x 600px 1280px 寬或更大的螢幕解析度下看起來還不錯。然而,如果我們能把它分割得更細一些,比如為 800px ~ 1024px 1024px ~ 1280px 以及 1280px 以上的解析度提供不同的定製佈局,那效果會更佳。同樣,對於 640px ~ 800px 320px ~ 640px 240px ~ 320px 以及 240px 以下的解析度也可以定製不同的佈局。



大約在 2004 年的時候, Cameron Adams(@themaninblue) (地址:https://c odepen.io/) 在他的博文《 Resolution dependent layout 地址: https://www.themaninblue.com/writing/perspective/2004/09/21/) 提出了基於螢幕解析度來動態構建Web佈局,即 使用JavaScript根據瀏覽器視窗大小載入不同CSS檔案

<!-- Narrow style sheet -->
<link rel="alternate stylesheet" type="text/css" href="css/narrow.css"
title="narrow"/>


<!-- Default style sheet -->
<link rel="stylesheet" type="text/css" href="css/normal.css" title="default"/>


<!-- Wide style sheet -->
<link rel="alternate stylesheet" type="text/css" href="css/wide.css"
title="wide"/>


<!-- Included JavaScript to switch style sheets -->
<script src="scripts/dynamiclayout.js" type="text/javascript"></script>

注意,在所有 <link> 標籤上 title 屬性的值分別為 narrow default wide ,並且在 dynamiclayout.js 中有一個 DynamicLayout() 函式,將會根據 <link> 標籤的 title 屬性的值來呼叫不同的樣式表:

function dynamicLayout(){
var browserWidth = getBrowserWidth();


// Narrow CSS rules
if (browserWidth < 640){
changeLayout("narrow");
}
// Normal (default) CSS rules
if ((browserWidth >= 640) && (browserWidth <= 960)){
changeLayout("default");
}
// Wide CSS rules
if (browserWidth > 960){
changeLayout("wide");
}
}

 @Kevin Hale 的博文《 Dynamic Resolution Dependent Layouts 》詳細介紹該技術。



這種佈局技術後來就以 Cameron Adams 部落格文章標題命名,被稱為 解析度相關的佈局 。這種佈局技術雖然會額外增加開發者(開發者需要為不同定製的佈局提供不同樣式表)工作量,但在CSS媒體查詢流行之前還是很受歡迎的。它也被稱為是早期的 CSS 媒體查詢(通過JavaScript查詢斷點)。



雖然這種依賴動態分辯率佈局的方案可以在不同的解析度下提供更佳的體驗,但隨著 2005年08月10日 Opera 軟體公司推出 Opera Mini 地址: https://www.webdesignmuseum.org/web-design-history/opera-mini-2005) 和 2007年01月09是第一臺   iPhone 地址: https://www.webdesignmuseum.org/web-design-history/steve-jobs-introduced-the-first-iphone-2007) 手機的出現,市場上不同品牌,不同解析度的移動端以及品牌商自己的Web瀏覽器就越來越多。



在這種環境之下,基於動態解析度載入不同的樣式表已不太現實,Web開發者不得不想出其他的方案來適應不同的螢幕尺寸。在很長一段時間,甚至到今日,為了適應不同螢幕的尺寸適配,為移動端單獨建立一個網站,即 移動子域名網站 。比如 Facebook的桌面版本和移動端版本,採用兩個不同的域名來訪問:

如此一來,開發人員要開發兩個版本,相應的工作量就更大了,特別對於要快速響應和試錯的Web應用來說,難度變得更大。



Web開發人員為了能改善這種現象,在 2010 年的時候, Ethan Marcotte(@beep) 基於 John Allsopp(@johnallsopp) 的 《 網頁設計的道(A Dao of Web Design) 地址: https://alistapart.com/article/dao/) ,提出響應式Web設計思路(《 Responsive Web Design 》) 地址: https://alistapart.com/article/responsive-web-design/) 。從此響應式Web設計(Responsive Web Design,簡稱 RWD )的身影就出現在了公眾面前。



 Ethan Marcotte(@beep) 在《 Responsive Web Design 地址: https://alistapart.com/article/responsive-web-design/) 中提到,響應式這個詞源自於建築學領域,原本指的是建築物本身會“響應”實際的使用情況,來自我調整。在Web開發領域,“響應式”的意思就變成了,我們開發的Web頁面會“響應”使用者的裝置尺寸而自動調整佈局。在這篇文章中提到過,我們可以基於 流體網格(Fluid Grids) 靈活的圖片(Flexible Images) 媒體查詢(Media Queries) 三種技術來構建一個響應式Web網站或Web應用。



另外, Ethan Marcotte(@beep) 構建了第一個具有響應式的Web網頁,可以說是響應式Web設計經典案例之一(只可惜現在打不開了):

那通過這個示例,大家對響應式Web設計是什麼樣的有了一個初步的瞭解了。其實,Ethan Marcotte 在他的文章中就提到:



未來我們應該這樣,隨著訪問網頁的裝置增加我們不會為每個裝置單獨設計,而只會做一份設計,把每個裝置作為這份設計要照顧的一個方面



也就是說,每個裝置上都會去追求最佳的使用者體驗,設計會自動適應各個裝置。在過去的時代,設計師精確的知道自己的媒介材質,比如一張 A4 紙張,一個名片,或者一張海報。但是在我們這個多屏時代,Web 設計必須有這樣的思維,我們要為“任意尺寸”而去設計。



自 Ethan Marcotte 提出響應式Web設計思路以及基於不同斷點(CSS 媒體查詢替代JavaScript查詢裝置螢幕分辨)實現不同終端裝置螢幕解析度佈局已有十多年了。大家都說,每十年就會看到一個生態系統迅速的發展,其中 CSS 也不另外。尤其是這兩年,CSS 新增了很多新的特性,比如大家最為期待的容器查詢特性 @container 、級聯分層 @layer 以及 CSS作用域 @scope 等。



正如 Una Kravets ( @Una ) 在2021的Google I/O 大會上的分享 地址: https://io.google/2021/session/a1760fa3-879a-4e98-a616-994ca8d3aab5/?lng=zh-CN) 所說:



隨著使用者偏好查詢、容器查詢以及其他裝置型別查詢的出現(CSS新特性),Web社群即將進入響應式 Web 設計的新時代,並改變我們對其含義的看法。



換句話說,下一代響應式Web設計即將到來,或者說已經來到了我們身邊。

響應式Web設計的現狀

在聊一下代響應式Web設計之前,我們就要對響應式Web設計的現狀有所瞭解。我們分別從兩種不同角色(Web設計師和Web開發者)的角度來看響應式 Web 設計的現狀。



先從 Web 設計師的角色來聊。



時至今日,雖然已是移動終端的天下,但如果要給不同終端提供設計稿的話,Web 設計師還是會依舊為不同的裝置終端提供不同的設計稿。比如,為不同的裝置視窗尺寸(如手機,平板和桌面端)提供不同的設計稿:

我們來看下簡化後的不同版本的設計線框圖,如下所示:

在上圖中,設計師為卡片(Card)提供了三種不同的 UI 效果。雖然卡片在不同裝置視窗下有著不同的UI效果,但他們構成的元素是相同,都有卡片容器、卡片縮圖、卡片標題 和 卡片描述等:

作為Web設計師,你已經使用了多個版本的佈局來展示同一個元件三種不同狀態下的UI變化。可以說把足夠多的資訊傳遞給了Web開發者!到這一步,Web 設計師已給 Web 開發者提供了具有響應式的Web設計稿。



接下來,再從另一種角色(Web開發者)來看響應式Web設計的現狀。對於 Web 開發者而言,要實現上圖中三種狀態下的卡片UI效果非常簡單。藉助 CSS 媒體查詢特性,在不同斷點下調整CSS樣式規則即可:

/* Mobile First */
.card {
display: flex;
flex-wrap: wrap;
gap: 10px;
}


/* Tablet */
@media (min-width: 700px) {
.card {
gap: 20px
}
}


/* Laptop and Desktop */


@media (min-width: 1024px) {
.card {
position: relative
}


.card__thumb {
position: absolute;
inset: 0;
}
}

這種方式只能適合於同一組件獨立存在於不同版本下。就示例的設計稿來看,在桌面端有兩種效果的卡片,為了滿足該設計效果,我們需要額外新增一些類名,在不同狀態下為卡片處理不同的UI效果:

CSS樣式程式碼可能會是像下面這樣:

/* Mobile First */
.card {
display: flex;
flex-wrap: wrap;
gap: 10px;
}


/* Tablet */
@media (min-width: 700px) {
.card--vertical {
gap: 20px
}
}


/* Laptop and Desktop */


@media (min-width: 1024px) {
.card--featured {
position: relative
}


.card--featured .card__thumb {
position: absolute;
inset: 0;
}
}

 看上去是不錯,但問題是,只有當視窗寬度大於一個特定的值時(常指的解析度斷點值),相應的元件變體才會生效,比如當視窗寬度大於 700px 時, .card--vertical 卡片UI效果才生效;當視窗寬度大於 1024px 時, .card--featured 卡片UI效果才生效。換句話說,如果要在平板端看到 .card--featured 卡片效果就無法看到,因為它的媒體查詢在 1024px 或更大的視窗寬度下才會生效。

不僅如此,Web的內容是動態的,有的時候輸出的內容可能和設計預定的卡片數量不相符合,那麼在這種情況之下,要麼會有一個空的空間,要麼卡片會擴充套件以填補容器的剩餘(或可用)空間。比如我們這個示例中,在視窗寬度為 700px 或更大的視窗寬度中, .card--vertical .card--featured 都有可能出現這樣的場景。

針對這樣的場景,Web設計師可能更希望有額外的UI效果給卡片。這部分我們放到下一節來聊。



簡單地說,目前的響應式 Web 設計主要方案還是利用 CSS 媒體查詢特性在不同的終端上提供佈局的切換。雖然他能滿足 Web 頁面佈局大部分場景,但也相對喪失了一些其他能力,比如說將響應式的樣式注入到元件本身的能力。換句話說,基於視窗寬度查詢構建的響應式Web頁面,尤其是響應式元件,其能力是有限的。



   CSS 媒體查詢的不足

在上一節中我們一起探討了 Web 開發者可以藉助於 CSS 媒體查詢特性來查詢視窗寬度(或裝置其他特性)為 Web 頁面在不同終端提供差異化的佈局。但也暴露出很多不足之處,甚至是明顯的能力不足。就拿前面示例來說,卡片元件有三種差異化的UI效果,這些差異化的UI效果是取決於瀏覽器視窗寬度,也就意味著卡片元件不能根據其父容器寬度去調整 UI 風格。這就限制了開發者 只能在視窗寬度大於某個特定值時(斷點) 使用一個元件的特定樣式。例如視窗寬度到達 700px 或大於 700px 時,卡片元件從預設的 .card (水平)狀態切換到垂直( .card--vertical )狀態。也就是說,如果我們想在小於 700px 寬度的視窗下,使用垂直狀態( .card--vertical )卡片效果是不行的:

另外一點就是當服務端吐出的資料和設計師預設的數量不一致時,最終的Web效果有可能不是設計師期望的。比如只有一張卡片、兩張、三張或更多,而設計稿中包含三張,這種情況之下,Web開發的實現的效果可能會像下圖這樣:



正如上圖所示,如果只有一張卡片資料吐出的時候,整個卡片寬度會擴充套件與容器寬度相等(拉伸)。此時,卡片寬度太寬導致用於卡片上的縮圖被拉抻,有可能會使縮圖變得模糊。



事實上呢?這只是Web開發者的一廂情願,設計師真正的意圖可能是像下圖這樣:

在這種場景之下,使用 CSS 媒體查詢特性實現起來會比較棘手,但使用 CSS 容器查詢特性,就會容易地多,我們可以通過查詢卡片父容器來決定如何顯示卡片去解決這些問題。



如果用一然話來概述的話:



雖然 Web 開發者可以使用全域性的視窗資訊來設定元件的樣式,但元件仍然不能擁有自已的樣式,而且當我們的設計系統基於元件而不是基於頁面時,那麼媒體查詢就無能為力!



慶幸的是,生態系統正在改變,而且這兩年尤其突出。比如說,我們一直期望的容器查詢特性就如約而至。如果我們將元件自身的響應式樣式思路從查詢視窗轉換到查詢其祖先容器,是不是前面的問題就可以輕易解決。除此之外,早期的CSS媒體查詢只能查詢視窗寬度和媒體特性,但不能查詢使用者對裝置喜好的設定。不過,這兩年CSS媒體查詢特性也有巨大的變化,我們除了查詢媒介(裝置)特性之外,也可以查詢使用者偏好設定。



正如 Una Kravets 所言:



Web生態再一次讓CSS騰飛,這些新的特性將會讓響應式Web設計注入新的能力。我們也將進入響應式設計的新時代,並轉變我們對其含義的看法。

下一代響應式Web設計

當媒體查詢被運用於 CSS 中時,“響應式Web設計”(Responsive Web Design)一詞就被 Ethan Marcotte 在 2010年創造出來。從那時起,Web設計師和開發人員就開始使用響應式Web設計的方法來設計和開發一個沉浸式的Web頁面或Web應用,以實時適配當今看上去無底洞的終端裝置。

今天,當我們提到響應式Web設計時,首先想到的是 Ethan Marcotte(@beep) 的 《 Responsive Web Design 地址: https://alistapart.com/article/responsive-web-design/) 博文中提到過的基於 流體網格(Fluid Grids) 靈活的圖片(Flexible Images) 媒體查詢(Media Queries) 三種技術來構建一個適應不同螢幕尺寸或不同移動終端裝置的 Web 頁面。

Web 開發者使用 CSS 媒體查詢來改變整個頁面的佈局,並從上到下調整移動手機、平板電腦和桌面端的設計尺寸。這種方法很有效,而且效果很好,但它有一個明顯的缺陷,即 整個螢幕同時響應,或者說整個頁面同時響應 。雖然該響應方式確實對使用者的體驗有一些較大的影響,但不能響應個別使用者的需求,也缺乏將響應式注入元件本身。



好訊息是,生態系統正在改變,而且進步非常迅速。Web 設計師和Web平臺的工程師正在開始用一種新的響應式技術方案來構建Web頁面,這種方案被稱為 元件驅動式Web設計(Component-Driven Web Design)

   元件驅動式Web設計

我們今天使用的響應式 Web 設計方法很快就會被認為是過時的,就像我們從90年代最初的基於表格的HTML開發過渡到現在的感覺一樣。



Web 設計師現在要克服的挑戰是,目前的響應式 Web 設計方法本質上是一種一刀切的方法,把整個頁面和使用者體驗當作一個整體,沒有任何個性化。



基於視窗的媒體查詢(CSS 媒體查詢)給我們提供了許多媒體查詢的能力,但缺少為我們的Web設計提供精細度的能力,並創造一個對使用者、他們的環境和他們在頁面上採取的行動來說是獨特的體驗。我們也缺乏將響應式樣式注入元件本身的能力。



這裡所說的元件是Web上的元素,可以由其他設計元素的集合或分組組成。如果我們把元件看成是由積木組成的,並把這個概念應用到像幻燈片、卡片或內容塊這樣的常見UI元素的構造中,就會更容易理解,在不久的某一天,我們可能會把響應式設計樣式注入單個元件或積木中,以定製和調整使用者的體驗,而不是把一套固定的樣式和規則應用於整個頁面的佈局。



我們可以使用全域性視窗資訊來控制元素的字型大小和最大寬度等樣式,或者調整這些元件的背景影象和佈局,但它們仍然無法控制擁有自己的樣式。當我們的響應式設計系統是基於元件的,而不是基於頁面的時候,這種限制就更難了。



好訊息是,全世界的Web設計師和開發人員正在努力改變響應式Web設計的生態系統。儘管為了改變我們對響應式設計的思考方式以及元件如何適應其周圍環境,需要進行基本的設計思維過程的改變,但響應式設計專業人員處理響應式Web設計的方式正在快速變化。



現在為創新之火推波助瀾的是CSS和靈活佈局的快速發展,比如添加了一些新的查詢規則、Flexbox 和 Grid佈局。這裡所取得的進步正在迅速迎來一個新的響應式Web設計的時代,而這個時代就在地平線之外。



CSS生態快速的發展,即將徹底改變響應式 Web 設計的概念



現在,在我們被引入響應式 Web 設計這個激進的新概念的十多年後,我們又一次見證了響應式設計生態系統的演變,即 CSS新增的特性將直接基於元件而不是基於頁面注入樣式響應能力 。這種能力被稱為 元件驅動Web設計(Component-Driven Web Design) ,基於元件驅動的開發將會成為一種真正流行的開發模式。



為了理解這種開發模式的轉變,併為即將到來的變化浪潮做好準備,讓我們看看在響應式Web設計運動中我們可以期待的變化,以及這可能會如何改變我們對待響應式設計的概念。

   響應使用者的需求

你可能對基於視窗可視區域大小的媒體查詢(通過 min-width max-width min-height max-height orientation aspect-ratio 等)比較熟悉,比如:

@media (max-width: 45rem) {
/* 視窗小於 45rem */
}


@media (min-width: 45rem) {
/* 視窗大於 45rem */
}



這只是 CSS 的 @media 最基礎的一部分規則,事實上, @media 規則大約包含了 24 個可供查詢的特性,其中大約 19 個查詢規則得到較好的支援,詳細的可以閱讀《 圖解CSS: CSS媒體查詢 地址: https://www.w3cplus.com/css/css-media-queries-guide.html) 一文。在這些新增的查詢特性中是用來改善使用者體驗的,比如 Media Queries Level 5 地址: https://www.w3.org/TR/mediaqueries-5/#mf-user-preferences) 規範中的第十一部分,能夠讓你根據使用者自身的特定偏好和需求來設計 Web 體驗。

也意味著這些新增的媒體查詢特性允許你根據使用者的偏好來調整使用者的體驗。



現在很多裝置提供了一些使用者偏好的設定。比如在 Mac 電腦上,使用者可以根據自己喜好做一些設定:



CSS媒體查詢提供了一些使用者喜好的查詢特性,這些特性可以識別出使用者在系統上的偏好設定,幫助Web開發者構建更加健壯和個性化的 Web 體驗,特別是對於那些具有可訪問性需求的使用者。

  • prefers-reduced-motion



Web頁面或應用難免少不了用一些動效來點綴,但有些使用者不喜歡這些動畫效果,甚至對於少數使用者來說,這些動效會讓他們身體不適。這就是為什麼現在大多數裝置都支援一種方法讓使用者根據自己的喜好來做設定。

使用 prefers-reduced-motion 媒體查詢用於檢測使用者的系統是否被開啟了動畫減弱功能。比如下面的這個示例,將會展示一組令人心煩的動畫,不過當你開啟了系統的“減少運動”後就能看到動畫減弱的效果了。

.pulse {
animation: pulse 2s infinite;
}


@media screen and (prefers-reduced-motion: reduce) {
.pulse {
animation: none;
}
}

示例效果演示的是 prefers-reduced-motion 媒體特性如何讓 animation 停止,其實CSS的 transition 也可以實現動畫效果,加上並不是所有裝置對動效都有一個很好的效能支援(畢竟動效是較耗效能的),因此,我們可以像下面這樣來寫CSS:


@media screen and (prefers-reduced-motion: reduce), (update: slow) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}

這段程式碼強制所有使用動畫持續時間或過渡持續時間宣告的動畫以人眼無法察覺的速度結束。當用戶要求減少動畫體驗,或者裝置螢幕重新整理率較低時,比如廉價智慧手機,它就能工作。



另外,Eric Bailey 在他的文章《 Revisiting prefers-reduced-motion, the reduced motion media query 地址: https://css-tricks.com/revisiting-prefers-reduced-motion/) 中提出了一個觀點:

“並不是每一個可以訪問網路的裝置都可以呈現動畫,或者流暢地呈現動畫。”



對於重新整理率低的裝置來說,可能會導致動畫出現問題,比如動畫卡頓。這樣的話,刪除動畫可能是更好的選擇。我們可以將 prefers-reduced-motion update 結合在一起使用:

@media screen and (prefers-reduced-motion: reduce), (update: slow) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}

這段程式碼強制所有使用 animation-duration transition-duration 宣告的動畫以人眼難以察覺的速度結束。當一個人要求減少動效體驗,或者裝置有一個重新整理率較低的螢幕,比如電子墨水或廉價的智慧手機,它就能發揮作用。



但需要注意的是,使用動態減弱並不意味著“沒有動效”,因為動效在Web頁面中傳達資訊能起到至關重要的作用。相反,你應該使用一個堅實的、去除非必須的動效基礎體驗去引導這些使用者,同時逐步增強沒有此項偏好設定的其他使用者的體驗。



如果你對減弱動效效果這方面技術感興趣的話,還可以閱讀:


  1.  Revisiting  prefers-reduced-motion  , the reduced motion media query

    (地址:https://css-tricks.com/revisiting-prefers-reduced-motion/)

    (地址:https://css-tricks.com/revisiting-prefers-reduced-motion/)

    (地址:https://css-tricks.com/revisiting-prefers-reduced-motion/) 

  2.  Meeting “2.2.2 Pause, Stop, Hide” with  prefers-reduced-motion 

    (地址:https://hidde.blog/meeting-2-22-pause-stop-hide-with-prefers-reduced-motion/)

    (地址:https://hidde.blog/meeting-2-22-pause-stop-hide-with-prefers-reduced-motion/)

  3.  Respecting Users’ Motion Preferences

    (地址:https://www.smashingmagazine.com/2021/10/respecting-users-motion-preferences/) 

  4.  Designing With Reduced Motion For Motion Sensitivities

    (地址:https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/) 

  5.  Accessible Web Animation: The WCAG on Animation Explained

    (地址:https://css-tricks.com/accessible-web-animation-the-wcag-on-animation-explained/) 

  6.  Accessible Animations in React

    (地址:https://www.joshwcomeau.com/react/prefers-reduced-motion/)

  • prefers-color-scheme



你可能知道了,macOS系統和iOS13之後,蘋果裝置具備 Dark Mode效果 (地址:https://www.w3cplus.com/blog/tags/700.html) ,就是使用者可以根據自己的喜好來選擇系統提供的色系:



使用 prefers-color-scheme 查詢特性可以讓你對使用者是否打開了裝置上Dark Mode來做出響應。換句話說,給Web頁面或應用新增Dark Mode只需要幾行程式碼即可。首先我們預設載入的主題是亮色系,我們可以在 :root 中宣告亮色系所需要的顏色,比如:

:root {
--text-color: #444;
--background-color: #f4f4f4;
}

然後通過媒體查詢 prefers-color-scheme: dark 為暗色系重置所需要的顏色:

@media screen and (prefers-color-scheme: dark) {
:root {
--text-color: rgba(255,255,255,.8);
--background-color: #121212;
}
}

使用 prefers-color-scheme 來定製不同外觀主題時,還可以和 theme-color 以及 color-scheme 結合起來使用。這將能控制系統應用的(比如瀏覽器)主題顏色:



color-scheme 這個 CSS 屬性和 <meta> name theme-color 是相同的。它們都是讓開發者更容易根據使用者的喜好設定來控制 Web應用或頁面的主題,即 允許開發者根據使用者喜好設定新增特定的主題樣式 。其實 color-scheme 屬性和 相應的 <meta> 標籤與 prefers-color-scheme 相互作用,它們在一起可以發揮更好的作用。最重要的一點是, color-scheme 完全決定了預設的外觀,而 prefers-color-scheme 則決定了可樣式化的外觀



假設你有下面這樣的一個簡單頁面:

<head>
<meta name="color-scheme" content="dark light">
<style>
fieldset {
background-color: gainsboro;
}
@media (prefers-color-scheme: dark) {
fieldset {
background-color: darkslategray;
}
}
</style>
</head>
<body>
<p>
Lorem ipsum dolor sit amet, legere ancillae ne vis.
</p>
<form>
<fieldset>
<legend>Lorem ipsum</legend>
<button type="button">Lorem ipsum</button>
</fieldset>
</form>
</body>

頁面上 <style> 中的CSS程式碼,把 <fieldset> 元素的背景顏色設定為 gainsboro ,如果使用者更喜歡暗色模式,則根據 prefers-color-scheme 媒體查詢,將 <fieldset> 的背景顏色設定為 darkslategray



通過 <meta name="color-scheme" content="dark light"> 元資料的設定,頁面告訴瀏覽器,它支援深色( dark )和亮色( light )主題,並且優先選擇深色主題。



根據作業系統是設定為深色還是亮色模式,整個頁面在深色上顯示為淺色,反之亦然,基於使用者代理樣式表。開發者沒有額外提供 CSS 來改變段落文字或頁面的背景顏色。



請注意, <fieldset> 元素的背景顏色是如何根據是否啟用了深色模式而改變的,它遵循了開發者在頁面上提供的內聯樣式表的規則。它要麼是 gainsboro ,要麼是 darkslategray



上圖是亮色模式( light )下,由開發者和使用者代理指定的樣式。根據使用者代理的樣式表,文字是黑色的,背景是白色的。 <fieldset> 元素的背景顏色是 gainsboro ,由開發者在內聯的式表中指定的顏色。

上圖是暗色模式( dark )下,由開發者和使用者代理指定的樣式。根據使用者代理的樣式表,文字是白色的,背景是黑色的。 <fieldset> 元素的背景色是 darkslategray ,由開發者在內聯樣式表中指定的顏色。



按鈕 <button> 元素的外觀是由使用者代理樣式表控制的。它的顏色被設定為 ButtonText 系統顏色,其背景顏色和邊框顏色被設定為 ButtonFace 系統顏色。



現在注意 <button> 元素的邊框顏色是如何變化的。 border-top-color border-bottom-color 的計算值從 rgba(0,0,0,.847) (偏黑)切換到 rgba(255, 255, 255, .847) (偏白),因為使用者代理根據顏色方案動態地更新 ButtonFace 。同樣適用於 <button> 元素的 color 屬性,它被設定為相應的系統顏色 ButtonText



看上去不錯,但這也引出另一個新的概念, 系統顏色 (地址:https://drafts.csswg.org/css-color/#css-system-colors)

有關於系統顏色這方面的不在這裡詳細闡述,如果你感興趣的話可以閱讀:

  1.  系統偏好設定的那些事兒

    (地址:https://www.w3cplus.com/css/css-system-things.html) 

  2. Windows High Contrast Mode, Forced Colors Mode And CSS Custom Properties

    (地址:https://www.smashingmagazine.com/2022/03/windows-high-contrast-colors-mode-css-custom-properties/) 

  3. Styling for Windows high contrast with new standards for forced colors

    (地址:https://blogs.windows.com/msedgedev/2020/09/17/styling-for-windows-high-contrast-with-new-standards-for-forced-colors/) 

  4. Operating System and Browser Accessibility Display Modes

    (地址:https://www.a11yproject.com/posts/operating-system-and-browser-accessibility-display-modes/)

  • prefers-reduced-data



不是每個人都能幸運地擁有快速、可靠或無限的資料(流量)套餐。



你可能有過出差旅行的經歷,也可能碰到了手機資料不夠用,那麼訪問一個重圖片的網站是很糟糕的(雖然說現在流量對於大家來說不是很大的事情,花錢總是能擺平的)。不過,一旦 prefers-reduced-data 得到支援,那麼這個頭痛的事情就可以避免了,也可以幫使用者省下一定的費用。因為,該特性可以讓使用者跳過大圖或高解析度的影象。

.image { 
background-image: url("images/heavy.jpg");
}


@media (prefers-reduced-data: reduce) {
.image {
background-image: url("images/light.avif");
}
}

當用戶在裝置上開啟了“Low Data Mode”(低資料模式),會載入佔流量更低的 light.avif 影象,可以幫助iPhone上的應用程式減少網路資料的使用:

插個題外話,上面提到的這三個媒體查詢特性主要是運用於 CSS 中,但它們還可以和 HTML 的 <picture> 元素的 <source> 標籤元素結合起來使用。可以根據使用者對裝置的偏好設定來選擇不同的圖片源:

<!-- 根據 prefers-color-scheme 為不同模式選擇不同圖片 -->
<picture>
<source srcset="dark.png" media="(prefers-color-scheme: dark)">
<source srcset="light.png" media="(prefers-color-scheme: light)">
<img src="light.png" alt="" />
</picture>


<!-- 根據 prefers-reduced-motion 為使用者呈現動圖或靜態圖 -->
<picture>
<source srcset="animation.jpg" media="(prefers-reduced-motion: reduce)">
</source>
<img srcset="animation.gif" alt="" />
</picture>


<!-- 根據 prefers-reduced-data 為使用者選擇不同的圖片 -->
<picture>
<source srcset="light.jpg" media="(prefers-reduced-data: reduce)" />
<img src="heavy.jpg" alt="" srcset="[email protected] 2x" />
</picture>
  • prefers-contrast

prefers-contrast 媒體查詢主要用於檢測使用者是否要求系統增加或減少相鄰顏色之間的對比度。比如一些喜歡閱讀電子書的使用者,在閱讀與文字背景對比度相差不大的文字時會遇到困難,他們更喜歡較大的對比度,利於閱讀。



比如像下面這個示例:

.contrast {
background-color: #0958d8;
color: #fff;
}


@media (prefers-contrast: high) {
.contrast {
background-color: #0a0db7;
}
}
  • 其他與使用者偏好有關的媒體特性



從W3C規範中不難發現,規範中提供了六個有關於使用者偏好的媒體查詢特性:

我們來看一個 forced-colors 的示例,該示例來自於 Eric 的 《 Windows High Contrast Mode, Forced Colors Mode And CSS Custom Properties 》一文:



  Modal dialog with Forced Color mode tweaks  @smashingmag  CodePen

地址: https://codepen.io/smashingmag/pen/zYPVjPa)

地址: https://codepen.io/smashingmag)

地址: https://codepen.io/)



提取使用 forced-colors 的示例程式碼:

// SCSS
.c-dialog__content {
background-color: var(--dialog-color-background);
box-shadow: 0 1rem 2rem 0 #00000099;
outline: var(--dialog-border-width) solid var(--dialog-border-color);
padding: var(--dialog-padding-outer);
width: min(90vw, 38rem);
z-index: 1;


@media (forced-colors: active) {
--dialog-border-width: var(--size-300);
}
}

forced-colors 媒體查詢特性中重新定義了 --dialog-border-width 的值。這樣做的原因是一個非常有意思的調整。它把細的焦點框( outline )變成了一個粗的。這樣調整有助於顯示模態框的外部邊界,並傳達它是漂浮在頁面其他內容之上的資訊。強制色彩模式刪除了模態框的盒子陰影( box-shadow ),所以我們不能在這種專門的瀏覽模式下依賴這種視覺效果:

如果你對上面提到的媒體查詢特性感興趣的話,可以深入閱讀下面這幾篇文章:



  1.  Media features

    地址: https://web.dev/learn/design/media-features/) 

  2.  CSS媒體查詢新特性

    地址: https://www.w3cplus.com/css/new-css-media-queries.html) 

  3.  系統偏好設定的那些事兒

    地址: https://www.w3cplus.com/css/css-system-things.html) 

  4.  圖解CSS: CSS媒體查詢

    地址: https://www.w3cplus.com/css/css-media-queries-guide.html)

   響應容器的需求

CSS 的 媒體查詢 引發了一場響應式設計的革命,為開發者提供了一種方法來查詢使用者代理或裝置環境的各個方面,比如視窗的大小或使用者偏好來改變 Web 頁面的風格。直到現在,媒體查詢還做不到讓元素的樣式能根據一個最近的容器的大小來改變樣式風格。也正因此,大家一直期待的容器查詢來了。



很難想象,從基於頁面的響應式設計(媒體查詢)到基於容器的響應式設計(容器查詢)的轉變,對設計生態系統的發展會起到什麼作用?



為了回答這個問題,接下來我們分幾個方面來介紹,希望能給大家帶來一定的思考,從而得到自己想要的答案。



  • 容器查詢的發展歷程



正如我在《 2022年的CSS 地址: https://www.w3cplus.com/css/what-is-new-css-in-2022.html) 一文中所提到的那樣。一直以來,CSS 容器查詢都是大家期待的一個特性,在這幾年的CSS發展報告中,他一直位居第一:

自 2010 年 @Ethan Marcotte 首次提出 響應式Web設計(RWD) 地址: https://alistapart.com/article/responsive-web-design/) 的設計理念(概念),Web設計就進入現代Web佈局時代。開發者可以根據 CSS 媒體查詢特性 (通常是視窗寬度、媒體裝置特性等)來為Web頁面定製不同的表現形式,比如可以根據使用者瀏覽內容的裝置特性來呈現不同的佈局、不同的字型大小和不同的圖片等。

但對於 Web 設計師或Web開發者來說,在現代Web設計或佈局中仍然缺少一特性, 頁面的設計不能夠響應其容器的寬度(或其他特性) 。也就是說,如果Web開發者能夠根據容器寬度來改變UI樣式,那就更好了。容器查詢將在很大程度上幫助 Web 開發者更好的完成他們的工作,在為Web開發基於元件程式碼時,其遺漏(容器查詢特性的缺失)是一個巨大的限制。



正因此,有關於容器查詢的特性在社群中的探討就沒有停止過。



早在 2019 年底, @Zach Leatherman 在尋找 容器查詢起源 (地址:https://www.zachleat.com/web/origin-container-queries/) 時,找到的最早有關於容器查詢的解決方案是 @Andy Hume 基於 JavaScript 的選擇器查詢和響應式容器的解決方案 (地址:https://github.com/ahume/selector-queries)



2015 年, @Mat ‘Wilto’ Marquis在響應式圖片社群小組引入了 <picture> 元素,將響應式圖片帶到了響應式 Web 設計的世界,他在《Container Queries: Once More Unto the Breach》 (地址:https://alistapart.com/article/container-queries-once-more-unto-the-breach/) 一文中概述了元素查詢的挑戰和使用案例演示了容器查詢的特性。



然後,在2017年, @Ethan Marcotte 寫了一篇 關於容器查詢相關的文章 (地址:https://ethanmarcotte.com/wrote/on-container-queries/) ,並提出了這樣的看法:



在他最初關注的響應式 Web 設計的文章之後的幾年裡,Web設計師和開發人員的工作越來越集中在元件上,而不是整個頁面,這使得媒體查詢不那麼理想。



從那時起,雖然有很多人主張使用媒體查詢,但容器查詢向前推進的速度還是不夠理想。 @L. David Baron 在《 Thoughts on an implementable path forward for Container Queries (地址:https://github.com/dbaron/container-queries-implementability) 中簡明扼要地解釋了容器查詢向前推進慢的問題出在哪?



容器查詢要求樣式取決於元件的大小,但考慮到 CSS 的工作原理,元件中的樣式會影響其大小。任意打破這個迴圈,既會產生奇怪的結果,又會干擾瀏覽器的工作,還會增加瀏覽器優化的成本。



除了 @David Baron 之外,2018年6月, @Greg Whitworth在荷蘭阿姆斯特丹舉辦的 CSS Day + UX Special (地址:https://noti.st/events/elQrNX/css-day-ux-special) 活動上的主題分享《Over the moon for container queries》 (地址:https://noti.st/gregwhitworth/UDul7E/over-the-moon-for-container-queries) 中也解釋了容器查詢在Web平臺上推進慢的相關原因。更重要的是,@Greg Whitworth還提供了使用新的 JavaScript API 和 CSS 的新技術來實現容器查詢的特性。@David Barrrron 也提出了一個可以避免這種困境的策略 (地址:https://github.com/dbaron/container-queries-implementability) ,更重要的是 @Miriam Suzanne在 @David Baron 的策略基礎上提出了 @container 方法 ( 地址: https://github.com/oddbird/css-sandbox/blob/main/src/rwd/query/explainer.md)( 地址:https://github.com/oddbird/css-sandbox/blob/main/src/rwd/query/explainer.md)



@container 方法通過對被查詢的元素應用大小和佈局的限制來實現。任何具有尺寸和佈局限制的元素都可以通過一個新的 @container 規則進行查詢,其語法與現有的媒體查詢類似。



這個提議已經被 W3C 的 CSS 工作組採納 (地址:https://drafts.csswg.org/css-contain-3/) ,並已經新增到 CSS Containment Module Level 3 (地址:https://www.w3.org/TR/css-contain-3/) 模組中。有關於該功能的相關問題和各網格平臺推進進度, 可以點選這裡查閱 (地址:https://github.com/w3c/csswg-drafts/projects/18)

雖然 CSS Containment Module Level 3 還是 FPWD 版本,規範中所描述的語法不是最終版本,直到寫這篇文章,其語法規則還在變,因此文章中所展示的語法有可能會變以及相關的示例有一天就無效了:

  • 什麼是容器查詢



CSS 容器查詢最大的特點是:



容器查詢允許開發者定義任何一個元素為包含上下文,查詢容器的後代元素可以根據查詢容器的大小或計算樣式的變化來改變風格!



換句話說,一個查詢容器是通過使用容器型別屬性( container-type container )指定要能的查詢型別來建立的。適用於其後代的樣式規則可以通過使用 @container 條件組規則對其進行查詢來設定條件。



容器查詢為響應式設計提供了一種更加動態的方法 。這意味著,如果你將此卡片元件放在側邊欄或放在頁面主體內部的網格中,則該元件本身根據容器而不是視口進行響應式的資訊展示。

首先,把卡片放到一個容器元素中,比如 .card__container

<!-- HTML -->
<div class="card__container">
<div class="card">
<img src="https://picsum.photos/2568/600?random=1" width="2568" height="600" alt="" class="card__thumbnail" />
<div class="card__badge">Must Try</div>
<h3 class="card__title">Best Brownies in Town</h3>
<p class="card__describe">High quality ingredients and best in-class chef. Light, tender, and easy to make~</p>
<button class="card__button">Order now</button>
</div>
</div>

也就是說,當卡片元件被放在一個容器中時,代表著它被包含在該容器中,比如上面程式碼中的 .card__container 。這也意味著,我們可以使用 CSS 的 container 來查詢 .card__container 的寬度,並在 @container .card 設定不同的樣式規則。從而達到設計師真正的意圖:



比如,容器寬度( .card__container )分別在 >400px >550px >700px 時為 .card 設定不同樣式:

程式碼可能像下面這樣:

/* Default */
.card {
// ...
}


/* CSS Container Queries*/
.card__container {
container-type: inline-size;
}


/* container's width > 400px*/
@container size(width > 400px) {
.card {
// ...
}
}


/* container's width > 550px*/
@container size(width > 550px) {
.card {
// ...
}
}


/* container's width > 700px*/
@container size(width > 700px) {
.card {
// ...
}
}

  Untitled  @airen  CodePen

(地址:https://codepen.io/airen/pen/ZEvoBYL)

(地址:https://codepen.io/airen)

(地址:https://codepen.io/)



拖動卡片右下角的滑塊,改變 .card__container 容器大小,你可以看到卡片元件( .card )UI效果的變化:



@container 規則,其工作方式與使用 @media 的媒體查詢類似,但相反, @container 查詢父容器以獲取資訊,而不是視口和瀏覽器的 UserAgent

  • 容器查詢的使用



到目前為止,CSS 容器查詢的語法規則已經經歷了多個版本更新,上面示例中展示是最新的使用方式。下面這幾篇文章中可以索引到其每個版本的使用方式的差異:



  1.  初探CSS容器查詢

    (地址:https://www.w3cplus.com/css/container-queries.html) 

  2.  容器查詢給設計帶來的變化

    (地址:https://www.w3cplus.com/css/container-queries-for-design.html) 

  3.  容器查詢中的  container   @container 

    (地址:https://www.w3cplus.com/css/container-queries-with-container-and-at-container.html)

接下來,通一個容器查詢卡片的示例來向大家展示如何使用 CSS 容器查詢。



定義一個包含性上下文



要使用 CSS 容器查詢特性,首先要定義一個包含性上下文(Containment Context)。這個有點類似於使用 Flexbox 和 Grid 佈局(定義Flexbox 或 Grid 上下文使用的是 display 屬性),只不過,定義一個包含性的上下文使用的不是我們熟知的 display 屬性,而是一個新的CSS屬性,即 container



在一個元素上顯式使用 container 可以告訴瀏覽器以後要針對這個容器進行查詢,以及具體如何查詢該特定的容器。比如,上面演示的示例中,我們在 .card__container 元素上( .card 的父容器)顯式設定了 container-type 的值為 inline-size

.card__container {
container-type: inline-size
}

上面的程式碼告訴瀏覽器,可以基於 .card__container 容器的內聯軸(Inline Axis)方向尺寸變化進行查詢。也就是說,當 .card__container 容器寬度大小變化到指定的某個值時,其後代元素的樣式就可以進行調整。



container-type container 屬性中的一個子屬性,另外,還可以顯式使用 container-name 來命名你的容器,即給一個包含性上下文指定一個具體的名稱:



.card__container {
container-name: card
}

這種方式對於同一個上下文中有多個包含性上下文時非常有意義,可以更明確地知道哪些查詢會影響元素。



你可以使用簡寫屬性 container ,只不過需要在 container-type container-name 之間新增斜槓分割符 /

.card__container {
container-type: inline-size;
container-name: card;
}


/* 等同於 */
.card__container {
container: inline-size / card;
}

如果一個容器查詢被應用到一個沒有定義的包含祖先元素上,查詢將無法應用。也就是說,無論是 body 還是 html 元素,都沒有預設的回退包含上下文。另外,定義包含上下文名稱時不能是 CSS 的關鍵詞,比如 default inherit initial 等。



注意: container-name 可以省略,如果省略將會使用其初始值 none ,但 container-type 不可省略,如果省略的話則表示未顯式宣告包含性上下文!

定義一個容器查詢



現在我們知道使用 container (或其子屬性 container-type container-name )對一個元素顯式宣告包含上下文(對一個元素應用包含性)。



有了這個包含性上下文之後,就可以使用 CSS 的 @ 規則 @container 來對應用了包含性元素進行查詢,即對容器進行查詢。 @container 規則的使用和 @media 以及 @supports 相似:

@container containerName size(width > 45rem) {
/* 應用了包含性上下文後代元素的 CSS */
}


@container size(width > 45rem) {
/* 應用了包含性上下文後代元素的 CSS */
}


這兩種方式都是正確的使用姿勢,第一個示例中的 containerName 指的是 container-name 顯式宣告的包含性上下文的名稱。如果在 @container 中沒有指定查詢的容器名稱,那麼這個查詢將是針對離樣式變化最近的聲明瞭包含性上下文的元素進行查詢。比如:


@container size(width > 30em) {
.card {
border-radius: 20px;
}
}

表示這個查詢將是針對 .card 元素最近的顯式聲明瞭包含性上下文的元素進行查詢。



程式碼中的 size() 函式是容器查詢中的新語法規則。這也是容器查詢語法變化之一,即 對查詢型別進行了更明確的規定 。因為規範已經提高到不僅可以根據尺寸( size )屬性查詢,還可以根據樣式( style )屬性進行查詢。




正如 Terrible Mia(容器查詢規範設計者)在 Twitter 上分享的一樣,可以使用
style() 函式對樣式進行查詢:

@container style(--card: large) {
/* CSS Style */
}


@container size(width > 30em) and style(--card: large) {
/* CSS Style */
}



到寫這篇文章的時候,還沒有瀏覽器支援對樣式進行查詢。另外,示例中用於 @container 的查詢條件 (width > 30em) 相當於 (min-width: 30em) 。使用數學表示式要比使用 min-width max-width 更易於理解,自 Media Queries Level 4 (地址:https://www.w3.org/TR/mediaqueries-4/#mq-range-context) 開始, 在 @media 規則中,也可以使用我們熟悉的數學表示式,比如 >= <= 等來替代以往不易於理解的 min- max-



上面示例程式碼中同時出現 container @container ,但他們並不是指的同一個屬性,前者是一個CSS屬性,後者是一個CSS程式碼塊。而且兩者有本質的區別:



  1. container container-type container-name 的簡寫屬性,用來顯式宣告某個元素是一個查詢容器,並且定義查詢容器的型別(可以由 container-type 指定)和查詢容器的名稱(由 container-name 指定)。

  2. @container (帶有 @ 規則),它類似於條件CSS中的 @media @supports 規則,是一個條件組規則,其條件是一個容器查詢,它是大小( size )和(或)樣式( style )查詢的布林組合。只有當其條件為真( true ), @container 規則塊中的樣式都會被使用者代理運用,否則將被視為無效,被使用者代理忽略。

容器查詢卡片



我想大家對容器查詢的理論和概念有了一個初步的認識。接下來,我們把這些東西放到一起,來具體看看前面展示的容器卡片示例是如何實現的。



自從響應式 Web 設計的出現以及移動終端裝置越來越多,在設計中也有移動端優先(Mobile First)還是桌面端優先(Desktop First)的爭執:





如果你對這方面討論感興趣,可以閱讀 Ahmad Shadeed 的 《 The State Of Mobile First and Desktop First 》一文。

(地址:https://ishadeed.com/article/the-state-of-mobile-first-and-desktop-first/)



就我個人而言,到目前為止,在開發跨元件狀態的“斷點”時,將容器查詢與考慮“移動端優先”的設計是最有意義的。也就是說,將最窄的檢視作為預設樣式,然後通過容器查詢處理更大寬度的樣式更新。

如上圖所示,我們從左往右來實現卡片不同狀態斷點下的UI效果。先從最窄的卡片開始(最左側,Default 狀態)。構建這個卡片元件,所需要的 HTML 結構如下:

<div class="card__container">
<div class="card">
<img src="https://picsum.photos/2568/600?random=1" width="2568" height="600" alt="" class="card__thumbnail" />
<h3 class="card__title">Container Queries Rule</h3>
<p class="card__describe">Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?</p>
<button class="card__button">Order now</button>
</div>
</div>

我們通過 CSS Grid 來完成卡片的佈局。先從最窄的開始,新增下面CSS程式碼:


.card {
display: grid;
gap: 1rem;
margin: 5vh auto;
border-radius: 0.5rem;
box-shadow: 0 0.25rem 0.5rem -0.15rem hsla(0 0% 0% / 55%);
background-color: #fff;
}


.card__thumbnail {
max-width: 100%;
aspect-ratio: 16 / 9;
height: auto;
object-fit: cover;
border-radius: 0.5rem 0.5rem 0 0;
}


.card__title {
font-weight: 700;
font-size: clamp(1.2rem, 1.2rem + 3vw, 1.5rem);
padding: 0 20px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}


.card__describe {
color: #666;
line-height: 1.4;
padding: 0 20px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}


.card__button {
display: inline-flex;
justify-content: center;
align-items: center;
border: none;
border-radius: 10rem;
background-color: #feca53;
padding: 10px 20px;
color: #000;
text-decoration: none;
box-shadow: 0 3px 8px rgb(0 0 0 / 7%);
transition: all 0.2s linear;
font-weight: 700;
justify-self: end;
margin: 0 20px 20px 0;
cursor: pointer;
}


.card__button:hover {
background-color: #ff9800;
}

正如上面的效果所示,卡片元件可以隨著其容器( .card__container )寬度自動變化,在窄屏下效果看上去還不錯,但在寬屏下,效果看上去有點怪怪的。不過不用擔心,這僅是最初的效果。我們期望的是通過容器查詢的特性,在容器不同斷點下改變卡片元件的佈局。按照前面所介紹的,我們需要先建立一個包含性上下文,即在 .card__container 上使用 container 顯式宣告該元素是一個包容性上下文。



.card__container {
container: inline-size;
}

效果如下:

  Untitled  @airen  CodePen

(地址:https://codepen.io/airen/pen/MWrXNGM)

(地址:https://codepen.io/airen)

(地址:https://codepen.io/)



可以在上面示例中嘗試拖動卡片右下角滑塊改變卡片容器寬度,你將看到的效果如下:

有了這樣一個卡片元件之後,如果將其放在不同的位置,即使是同一頁面,同一視窗斷點下,也會根據其容器斷點自動匹配最為適合的佈局(或UI效果)。比如:

  Untitled  @airen  CodePen

(地址:https://codepen.io/airen/pen/WNdKgMK)

(地址:https://codepen.io/airen)

(地址:https://codepen.io/)



嘗試調整上面示例中視窗的大小:

  • 媒體查詢 vs. 容器查詢



通過上面的示例的介紹,我想你對容器查詢特性已經有了一個較清晰的認識了。從使用角度來看,容器查詢和媒體查詢是非常的相似,那麼有人可能會問,有了容器查詢是不是就不再需要媒體查詢特性了呢?在回答這個問題之前,我們簡單的來看兩者的差異。



眾所周知,媒體查詢查詢的瀏覽器視窗寬度(當然還有其他查詢特性),而容器查詢查詢的是元件其父容器(具有包含性上下文的祖先元素)的寬度(或樣式)。下圖可能可以清晰的闡述兩者的差異:





就我個人認為,兩者不是誰替代誰的關係,更應該是兩者共存的關係。容器查詢特性的出現,我們可以不再侷限於視窗斷點來調整佈局或UI樣式,還可以基於容器斷點來調整佈局或UI。換句話說,媒體查詢是一種巨集觀的佈局(Macro Layout),可以用於整體頁面佈局;而容器查詢可以調整元件的每個元素,建立了一種微觀的佈局(Micro Layout)。



  • 容器查詢解決的是什麼問題?



眾所周知,響應式設計的概念的核心是 CSS 媒體查詢的出現,它允許開發者根據瀏覽器視窗的尺寸來設定各種樣式規則。也正因此,響應式設計和CSS媒體查詢開啟了更多的 Web 佈局解決方案,以及多年來圍繞響應視窗尺寸建立的最佳實踐。而且,近些年來,設計系統和元件庫也得到了更廣泛的普及。對於更多開發者而言,更大的期望是:



一次建成,隨地部署!



這也意味著一個單獨開發的 Web 元件可以在任何情況下工作,以使建立複雜的介面更加有效和一致。只不過,這些元件會組合在一起,形成一個Web頁面或Web應用介面。目前,在只有媒體查詢的情況下,往往需要額外的一層來協調跨視窗大小變化的元件的突變。在這些情況下,你可能不得不在更多的斷點下使用更多的類名來設定不同的樣式規則。甚至更慘的是,即使這樣做仍然很多情況之下也無法達到最理想的UI表面。



很多時候,響應式Web設計不是關於瀏覽器視窗尺寸而是關於容器的尺寸大小,比如:



慶幸的是,CSS容器查詢的出現,使我們超越了只考慮瀏覽器視窗尺寸的範圍,並允許任何元件或元素對定義的容器尺寸做出響應。因此,雖然你可能仍然使用響應式來給Web頁面佈局,但Web頁面的任何一個元件都可能通過容器查詢來定義自己的樣式變化。然後,它可以根據它是在一個窄的還是寬的容器中顯示,來調整它的樣式。



容器查詢使我們不再只考慮瀏覽器視窗尺寸大小,而是允許任何元件或元素對定義的容器尺寸做出響應!



也就是說,有了CSS容器查詢,你就能以一種非常精確和可預測的方式定義一個元件的全部樣式。



  • 設計時考慮容器查詢



雖然響應式設計給Web設計師帶來了更多的可有性,但響應式設計還是有很多的侷限性。對於Web設計師而言,更期待的是能夠根據元件容器尺寸來提供不同的設計風格。依舊拿卡片元件來舉例:



也就是說,CSS容器查詢特性來了之後,作為一名Web設計師,在設計Web頁面(或元件)時,就需要基於容器尺寸考慮如何設計。這樣一來,可以向Web開發人員提供元件的細節和變化,Web開發人員也可以基於這些細節進行編碼(進行開發)。



不過,這並不意味著容器查詢特性之後響應式設計是就失去了意義。在未來,容器查詢和響應式設計是共存的,簡單地說,Web設計師在設計元件時可能會將元件分為以下幾個部分:



  1. 基於視窗(CSS媒體查詢)

  2. 基於容器(CSS容器查詢)

  3. 通用型(不受影響的元件)

比如:

在未來,Web設計師給Web開發者投喂的設計稿可能就會像下圖這樣了:

或許因為容器查詢的到來,設計師在設計Web的時候,也可能會做出相應的調整。投餵給Web開發的設計稿也可能會和以往的模式有所差異。那麼這個時候,Web開發者就需要具備正確理解設計師的意圖了。比如,Web設計師可能在未來的設計中會提供向下圖的卡片元件設計:



作為Web開發人員,看到上圖設計效果,需要改變以往對設計圖意圖的理解,不能繼續執著於基於視窗尺寸來調整元件UI。

上圖是基於視窗的一種開發模式,需要為卡片元件設定不同的類名,並且基於視窗尺寸,在相應的類名下調整卡片元件UI。有了容器特性時,我們可以基於現代的Web佈局技術,比如Flexbox或Grid佈局,讓卡片元件基於其容器來調整其UI:



正如上圖所示,可以基於視窗大小採用CSS媒體查詢特性,Flexbox或Grid佈局等技術改變卡片容器 .card__container 的大小,從而讓卡片元件根據其容器尺寸大小做出相應響應。



擁有一個能根據其父容器尺寸做出響應(UI調整)的元件是非常有用的,正如你看到的,我們可以只構建一個元件,就可以滿足不同視窗佈局下的設計訴求!

  • 容器查詢不應該讓元件變得複雜化



元件是有由很多個元素組合在一起構成的:



雖然容器查詢特性到來,可以讓元件根據其容器尺寸來做出響應,但要記住的是,做出響應變化應該要有一個度。如果過度設計的話,對於Web開發人員而言,與其使用容器查詢特性來實現UI響應,還不如重新構建一個獨立的全新元件。拿使用者資訊元件( UserProfile )為例,元件內部結構保持不變,或者至少不會增加新的結構,只需稍加調整,比如調整佈局就可以實現不同的UI效果,或者讓內部元素顯示隱藏切換等。在這種情景之中,採用容器查詢特性才能顯現其魅力:



  • 作用域樣式



為了完善容器查詢特性,CSS 工作組還在積極討論作用域樣式(Scoped Styles) (地址:https://css.oddbird.net/scope/) ,以幫助為元件提供適當的名稱空間來避免衝突。

作用域樣式允許傳遞和特定於元件的樣式,以避免命名衝突,許多框架和外掛(如CSS模組)已經允許我們在框架內這樣做。這個規範現在允許我們用可讀的CSS為元件編寫本機封裝的樣式,而無需調整標記。

/* @scope (<root>#) [to (<boundary>#)]? { … } */


@scope (.tabs) to (.panel) {
:scope {
/* targeting the scope root */
}


.light-theme :scope .tab {
/* contextual styles */
}
}

我自己對作用域樣式也瞭解的不怎麼多,所以在這裡不做過多闡述,以免錯誤不斷。



作用域樣式可以通過不同名稱空間樣式傳遞給特定的元件,以避免命名衝突。其實在 CSS 中另一個與容器查詢同樣被受期待的特性,級聯分層,即 @layer 也可以用來解決命名衝突,樣式衝突的問題。該特性已得到了 Safari 和 Chrome 瀏覽器支援。如果你對該話題感興趣的話,可以閱讀《初探 CSS 的級聯層( @layer )》 (地址:https://www.w3cplus.com/css/css-layer.html) 一文。



   響應外形的需求

新一代響應式Web設計除了響應使用者需求,容器需求之外,還有另一個響應需求,那就是外形的響應需求。



什麼是外形響應需求呢?



摺疊裝置在市場上已經存在了近三年,你可能已經接觸過像下圖這樣的一些裝置:

大致主要分為兩種型別,雙屏可摺疊裝置(如 Microsoft Surface Duo)和單屏可摺疊裝置(如 Huawei Mate XS):



在多螢幕或可摺疊裝置上,Web應用或Web頁面在這些裝置上的開啟姿勢也將會有所不同,應用可以單屏顯示,也可以跨屏顯示:



換句話說,我們的應用或頁面要具備這種跨越螢幕的能力,也要具備響應這種跨越的能力,以及還可能需要具備邏輯分隔內容的能力等。



可以說,多螢幕或摺疊屏裝置開啟了更廣闊的螢幕空間以及用獨特的姿勢將使用者帶入到另一個世界。針對於這種裝置,除了使用者之外,對於UI設計師,使用者體驗師和Web開發人員都需要重新面臨解鎖前所未有的Web體驗。這也將是近十年來,Web開發帶來最大的變化之一,以及開發人員所要面臨的最大挑戰之一。



在這裡我們針對多螢幕和摺疊屏裝置的響應,就稱之為響應外形的需求。這也是響應式 Web 設計的一部分。



由於可摺疊裝置相對來說是新型裝置,面對這些新型裝置時很多開發者並沒有做好相應的知識儲備,甚至是不知道從何入手。事實上呢?有些Web開發者已經開始在為我們制定這方面的API,除了文章開頭提到的 三星(Samsung) @Diego González 英特爾(Intel Corporation) @Kenneth Rohde Christiansen 之外還有 微軟(Microsoft) @Bogdan Brinza @Daniel Libby @Zouhir Chahoud 。只不過對於Web開發者來說,現在這些制定的規範(CSS相關的特性)和Web API(JavaScript API)還很新,不確定因素過多,甚至差異性也比較大。



到目前為止主要分為兩個部分。其中一個部分是《 可用於雙螢幕和摺疊屏的Web API (地址:https://www.w3cplus.com/mobile/introducing-dual-screen-foldable-web-apis.html) 介紹的相關API,它是由微軟(Microsoft)的 @Bogdan Brinza、 @Daniel Libby和 @Zouhir Chahoud一起制定的,更適用於“有縫”的摺疊處裝置;另一部分是目前處於W3C規範ED階段的 螢幕摺疊 API (地址:https://w3c.github.io/device-posture/) ,它更適用於“無縫”的摺疊裝置。



 @argyleink 在Github上發起了一個使用 CSS媒體特性來檢測摺疊屏的討論 (地址:https://github.com/w3c/csswg-drafts/issues/4141) 。也就是說,Web開發者可以使用@media相關的特性來識別摺疊屏,為摺疊屏的型別(比如“有縫”和“無縫”)提供相應的媒體查詢。



比如,我們可以使用 screen-spanning 這個特性可以用來幫助Web開發人員檢測“根檢視”是否跨越多個相鄰顯示區域,並提供有關這些相鄰顯示區域配置的詳細資訊。

也可以使用 screen-fold-posture screen-fold-angle 兩個媒體查詢來對無縫裝置進行查詢:

還可以使用 horizontal-viewport-segments vertical-viewport-segments 查詢視口的數量:

 



horizontal-viewport-segments vertical-viewport-segments 是最新的兩個查詢特性,它們將替代最初的 screen-spanning 這個媒體查詢特性!



除此之外,還可以通過一些摺疊姿勢來進行查詢:



除了CSS媒體查詢之外,還引入了六個新的CSS環境變數,以幫助開發者計算顯示區域的幾何形狀,計算鉸鏈區域被物理特徵遮擋的幾何形狀:

上圖中展示的這六個CSS環境變數將替代以前的 env(fold-top) env(fold-left) env(fold-width) env(fold-height)



對於Web開發者來說,我們可以像下面這樣來使用:

// 有縫摺疊
@media (spanning: single-fold-vertical) {
// CSS Code...
}


// 無縫摺疊
@media (screen-fold-posture: laptop){
// CSS Code...
}


// 摺疊角度查詢
@media (max-screen-fold-angle: 120deg) {
// CSS Code...
}


// 視口數量查詢
@media (horizontal-viewport-segments: 2) {
// CSS Code...
}
@media (vertical-viewport-segments: 2) {
// CSS Code...
}


在現代佈局中,將這些媒體查詢特性、CSS環境變數和CSS Grid佈局結合在一起,就可以很輕易的滿足外形響應的需求變化。比如:

:root {
--sidebar-width: 5rem;
}


@media (spanning: single-fold-vertical) {
:root {
--sidebar-width: env(viewport-segment-left 0 0);
}
}


main {
display: grid;
grid-template-columns: var(--sidebar-width) 1fr;
}

Stephanie 在她的最新博文《 Building Web Layouts For Dual-Screen And Foldable Devices (地址:https://www.smashingmagazine.com/2022/03/building-web-layouts-dual-screen-foldable-devices/) 中也向大家提供了一個示例, 演示了按螢幕數量(  horizontal-viewport-segments: 2  )查詢的示例 (地址:https://www.stephaniestimac.com/demos/smashing-ds-demo/)

.recipe {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: minmax(175px, max-content);
grid-gap: 1rem;
}


.recipe-meta {
grid-column: 1 / 4;
}


img {
grid-column: 1 / 4;
}


.recipe-details__ingredients {
grid-row: 3;
}


.recipe-details__preparation {
grid-column: 2 / 4;
grid-row: 3;
}


@media (horizontal-viewport-segments: 2) {
.recipe {
grid-template-columns: env(viewport-segment-width 0 0) 1fr 1fr;
grid-template-rows: repeat(2, 175px) minmax(175px, max-content);
}


.recipe-meta {
grid-column: 1 / 2;
}


img {
grid-column: 2 / 4;
grid-row: 1 / 3;
}


.recipe-details__ingredients {
grid-row: 2;
}


.recipe-details__preparation {
grid-column: 2 / 4;
grid-row: 3;
}


}

上面是從示例中擷取的有關於佈局的關鍵程式碼。最終效果如下:

如果你對多屏或摺疊屏這方面技術感興趣的話,還可以閱讀:



  1.  聊聊安卓摺疊屏給互動設計和開發帶來的變化

    (地址:https://www.w3cplus.com/mobile/mobile-folding.html) 

  2. 可摺疊Web可能會給我們帶來的變化

    (地址:https://www.w3cplus.com/mobile/css-foldable-display.html) 

  3. 可用於雙螢幕和摺疊屏的Web API

    (地址:https://www.w3cplus.com/mobile/introducing-dual-screen-foldable-web-apis.html) 

  4. 摺疊屏相關的Web API

    (地址:https://www.w3cplus.com/mobile/introducing-dual-screen-foldable-web-apis.html) 

  5. Foldable CSS and JavaScript update for web developers

    (地址:https://devblogs.microsoft.com/surface-duo/foldable-css-javascript-edge-96/) 

  6. Building Web Layouts For Dual-Screen And Foldable Devices

    (地址:https://www.smashingmagazine.com/2022/03/building-web-layouts-dual-screen-foldable-devices/) 



技術的變革是永無止境的,我們將來要面對的使用者終端也絕不會僅現於目前能看到的終端裝置和媒介,就好比現在運用於遊戲行業的 VR(虛擬現實)和 AR(增強現實)裝置。雖然現在 VR 和 AR 用於其他行業的場景還很少見,但我們可以預見,在 VR 和 AR 裝置越來越成熟和更多的裝置釋出之後,我們就能看到 VR 和 AR 就像我們已經看到幾十年前的觸控式螢幕裝置一樣。或許有一天,你設計(或開發)的Web頁面或應用就需要能在 VR 和 AR 裝置上有一個較好的呈現。

上圖來自於《 UX Case Study: Metaverse Banking VR / AR Design Concept of the Future (地址:https://www.theuxda.com/blog/how-online-banking-design-should-work-ux-case-study) 一文。UXDA的專業金融使用者體驗架構師和設計師團隊向您介紹第一個混合現實銀行概念,包括VR和AR銀行設計、平板電腦、可穿戴裝置、桌面和移動銀行UI / UX。



在這裡,我想表達的是,未來的響應式 Web 設計要響應的外形需求可能會更豐富,更復雜。

總結

響應式 Web 設計已經將 Web 帶到了今天人們所能接觸到的每一個連線的螢幕上。Web設計師和創意開發者用創造性的思維、大膽的想法和某種無畏的精神探索、測試和迭代他們的想法,使線上體驗更有吸引力、更容易訪問和更智慧,推動了設計方法的發展。就好比這裡所提到的 元件驅動式Web設計。

元件驅動式 Web 設計的到來或者說 CSS 容器查詢、作用域樣式、級聯層控制等特性的出現,這些先進的特性使我們有機會從頁面佈局、全域性樣式和使用者樣式中孤立元件樣式,從而實現更具彈性的響應式設計。這意味著你現在可以使用基於頁面的媒體查詢設計巨集觀佈局,包括多屏或摺疊屏的細微差異;同時使用基於容器查詢給元件設計微觀上佈局,並新增基於使用者偏好的媒體查詢,來實現基於使用者的獨特偏好和需求的定製化體驗。



這就是下一代響應式 Web 設計,也就是 元件驅動式 Web 設計(或開發)。它結合了巨集觀佈局和微觀佈局,最重要的是,也將使用者定製化和尺寸外形都考慮到了。



這些變化中的任何一個都將構成我們對web設計方式的重大轉變。但它們結合在一起,意味著我們甚至在概念化響應性設計方面的一個巨大轉變。是時候思考不止步於視口大小的響應性設計了,並開始考慮所有這些新方向,來獲得更好的基於元件和定製化的體驗。



也就是說。如果我們將這些元件驅動的功能納入設計系統,並從整體上改變我們對待 Web 設計的方式,我們就可以利用這些功能以及更多的功能來改善每一個登陸你網站的訪問者的使用者體驗。我們可以為他們提供真正個性化的體驗,提高參與度和轉化率,並最終提高使用者對你的品牌的感知。



我們不再是為使用者群體設計。我們對 "受眾"一詞的理解將發生變化,因為內容和體驗將為一個人而不是許多人的受眾而變得高度集中。



元件驅動的響應式 Web 設計將使 Web 真正的可移植,並能適應甚至還沒有發明的裝置。與其在今天的技術範圍內追趕和設計,我們將只為使用者設計。



最後,希望文章中提到的概念和技術對你有所幫助。

團隊介紹

我們是F(X) Team團隊,F(x) Team ,F(x) 指函式 F(x) ,是機器學習中常出現的符號,深度學習的本質也是求 f(x) 的最優解,意味擁有不同特徵的成員經過 fx 團隊神奇作⽤,不斷“訓練”,⼀起找到前端智慧化團隊的最優解。我們致力於前端智慧化領域的探索和實踐,賦能淘寶、天貓、聚划算等日常與大促(如雙 11 )業務,是淘系前端智慧化實踐的領路人,也是阿里經濟體前端委員會智慧化方向的核心團隊。我們在 D2C(Design to Code) 領域開放了  Imgcook  平臺,逐步釋放阿里生態的前端生產力;同時我們也與 Google 的 tensorflow 團隊保持長線合作,基於 tfjs-node 之上,開源了我們的前端演算法工程框架 Pipcook,引領前端行業向智慧化時代邁進。 

✿    拓展閱讀

者|大貘

編輯| 橙子君