本文探討如何利用CSS級聯層提升組件的可定制性、效率以及易用性和易理解性。
我熱衷於代碼組織,發現級聯層是明確組織代碼的絕佳方式,因為它直接遵循級聯的讀取順序。更妙的是,除了幫助進行“頂級”組織外,級聯層還可以嵌套,允許我們根據級聯編寫更精確的樣式。
唯一的缺點是你的想像力——沒有什麼能阻止我們過度設計CSS。需要明確的是,你很可能會認為我即將展示的內容是一種過度設計。但我認為我已經找到了平衡點,保持簡單而有序,並樂於分享我的發現。
讓我們以按鈕為例,探討使用CSS編寫組件的模式。按鈕是幾乎每個組件庫中最流行的組件之一。這種流行是有原因的,因為按鈕可用於各種用例,包括:
而且按鈕有多種不同的標記形式,例如<button></button>
、input[type="button"]
和<a></a>
。如果你相信的話,製作按鈕的方法甚至更多。
最重要的是,不同的按鈕執行不同的功能,並且通常會相應地進行樣式設置,以便一種操作的按鈕與另一種操作的按鈕區分開來。按鈕還會響應狀態更改,例如當它們懸停、活動和聚焦時。如果你曾經使用BEM語法編寫過CSS,我們可以在級聯層的上下文中沿類似的思路思考。
<code>.button {} .button-primary {} .button-secondary {} .button-warning {} /* etc. */</code>
好的,現在讓我們編寫一些代碼。具體來說,讓我們創建幾種不同類型的按鈕。我們將從一個.button
類開始,我們可以將其設置為任何我們想要設置為按鈕的元素!我們已經知道按鈕有多種不同的標記形式,因此通用的.button
類是選擇一個或所有這些按鈕最可重用和最可擴展的方式。
<code>.button { /* 所有按钮的通用样式 */ }</code>
在這裡,我們可以插入我們的第一個級聯層!記住,我們首先想要級聯層的原因是它允許我們在評估樣式時設置CSS級聯的讀取順序。我們可以告訴CSS先評估一層,然後是另一層,然後再是另一層——所有這些都按照我們想要的順序進行。這是一個令人難以置信的功能,它賦予我們超級能力來控制瀏覽器應用哪些樣式“勝出”。
我們將此層命名為components
,因為按鈕是一種組件。我喜歡這個名稱的原因是它足夠通用,可以支持我們將來在決定擴展設計系統時添加的其他組件。它隨著我們一起擴展,同時保持與我們將來編寫的可能不是特定於組件的其他樣式的良好關注點分離。
<code>.button {} .button-primary {} .button-secondary {} .button-warning {} /* etc. */</code>
事情變得有點奇怪的地方在這裡。你知道你可以在類內部嵌套級聯層嗎?這完全是一件事。所以,看看這個,我們可以在已經位於其自身層內的.button
類內部引入一個新的層。這就是我的意思:
<code>.button { /* 所有按钮的通用样式 */ }</code>
最終,瀏覽器就是這樣解釋層內層的:
<code>/* 组件顶级层 */ @layer components { .button { /* 所有按钮的通用样式 */ } }</code>
這篇文章不僅僅是關於嵌套樣式的,所以我只想說,當你這樣做時,你的里程可能會有所不同。查看Andy Bell最近關於謹慎使用嵌套樣式的文章。
到目前為止,我們已經在一個級聯層內建立了一個.button
類,該層旨在容納我們設計系統中的任何類型的組件。在該.button
內部是另一個級聯層,這一層用於選擇我們可能在標記中遇到的不同類型的按鈕。我們之前討論過按鈕是<button></button>
、<input>
或<a></a>
,這就是我們如何單獨選擇樣式化每種類型的方法。
我們可以使用:is()
偽選擇器函數,這類似於說:“如果這個.button
是一個<a></a>
元素,則應用這些樣式。”
<code>/* 组件顶级层 */ @layer components { .button { /* 组件元素层 */ @layer elements { /* 样式 */ } } }</code>
我將用適用於所有按鈕的通用樣式填充我們的代碼。這些樣式位於元素層的頂部,因此無論標記如何,它們都將應用於任何和所有按鈕。可以將它們視為默認按鈕樣式。
<code>@layer components { @layer elements { .button { /* 按钮样式... */ } } }</code>
當用戶與默認按鈕交互時,它們應該做什麼?這些是按鈕在用戶與之交互時可能採用的不同狀態,我們需要相應地設置它們的樣式。
我將在元素子層正下方創建一個新的級聯子層,創造性地稱為“states”(狀態):
<code>/* 组件顶级层 */ @layer components { .button { /* 组件元素层 */ @layer elements { /* 所有按钮的通用样式 */ &:is(a) { /* <a>特定样式 */ } &:is(button) { /* <button>特定样式 */ } /* etc. */ } } }</button></a></code>
在這裡暫停並思考一下。我們應該針對哪些狀態?我們想為這些狀態中的每一個更改什麼?
某些狀態可能共享相似的屬性更改,例如:hover
和:focus
具有相同的背景顏色。幸運的是,CSS 為我們提供了解決此類問題的工具,使用:where()
函數根據狀態對屬性更改進行分組。為什麼使用:where()
而不是:is()
? :where()
具有零特異性,這意味著它比:is()
更容易覆蓋,:is()
採用其參數中特異性得分最高的元素的特異性。在編寫可擴展、可維護的CSS時,保持低特異性是一種美德。
<code>.button {} .button-primary {} .button-secondary {} .button-warning {} /* etc. */</code>
但是我們如何以有意義的方式更新按鈕的樣式呢?我的意思是,我們如何確保按鈕看起來像懸停或聚焦?我們只需在其上添加一個新的背景顏色,但理想情況下,顏色應該與元素層中設置的background-color
相關。
因此,讓我們稍微重構一下。之前,我將.button
元素的background-color
設置為darkslateblue
。我想重用該顏色,因此最好將其轉換為CSS變量,以便我們可以一次更新它並使其應用於所有地方。依賴變量是編寫可擴展和可維護CSS的另一個優點。
我將創建一個名為--button-background-color
的新變量,它最初設置為darkslateblue
,然後將其設置為默認按鈕樣式:
<code>.button { /* 所有按钮的通用样式 */ }</code>
現在我們已經將顏色存儲在變量中,我們可以在其他層中將相同的變量設置為按鈕的懸停和焦點狀態,使用相對較新的color-mix()
函數將darkslateblue
轉換為更淺的顏色,當按鈕懸停或聚焦時。
回到我們的狀態層!我們首先在一個名為--state-background-color
的新CSS變量中混合顏色:
<code>/* 组件顶级层 */ @layer components { .button { /* 所有按钮的通用样式 */ } }</code>
然後,我們可以通過更新background-color
屬性來應用該顏色。
<code>/* 组件顶级层 */ @layer components { .button { /* 组件元素层 */ @layer elements { /* 样式 */ } } }</code>
除了元素和狀態層之外,你可能還在尋找組件中某種類型的變化,例如修飾符。這是因為並非所有按鈕都會像你的默認按鈕一樣。你可能想要一個帶有綠色背景顏色的按鈕,供用戶確認決策。或者你可能想要一個紅色的按鈕,在單擊時表示危險。因此,我們可以採用現有的默認按鈕樣式並為這些特定用例修改它們。
如果我們考慮級聯的順序——總是從上到下流動——我們不希望修改後的樣式影響我們剛剛製作的狀態層中的樣式。因此,讓我們在元素和狀態之間添加一個新的修飾符層:
<code>@layer components { @layer elements { .button { /* 按钮样式... */ } } }</code>
與我們處理狀態的方式類似,我們現在可以為每個按鈕修飾符更新--button-background-color
變量。當然,我們可以進一步修改樣式,但我們保持相當簡單,以演示此系統的工作原理。
我們將創建一個新的類,該類將默認按鈕的background-color
從darkslateblue
修改為darkgreen
。同樣,我們可以依賴:is()
選擇器,因為在這種情況下我們需要增加的特異性。這樣,我們就可以用修飾符類覆蓋默認按鈕樣式。我們將此類稱為.success
(綠色是“成功”的顏色)並將其提供給:is()
:
<code>.button {} .button-primary {} .button-secondary {} .button-warning {} /* etc. */</code>
如果我們將.success
類添加到我們的一個按鈕中,它將變成darkgreen
而不是darkslateblue
,這正是我們想要的。由於我們已經在狀態層中進行了一些color-mix()
操作,因此我們將自動繼承這些懸停和焦點樣式,這意味著在這些狀態下darkgreen
會變淺。
<code>.button { /* 所有按钮的通用样式 */ }</code>
我們可以將需要修改的任何CSS屬性重構為CSS自定義屬性,這為我們提供了很大的定制空間。
<code>/* 组件顶级层 */ @layer components { .button { /* 所有按钮的通用样式 */ } }</code>
附註:仔細查看該演示,並查看我是如何使用light-dark()
調整按鈕背景的——然後閱讀Sara Joy的“來到light-dark()一邊”,以全面了解其工作原理!
你怎麼看?你會用它來組織你的樣式嗎?對於一個組件很少的小項目來說,創建級聯層系統可能是過度的。但即使像我們剛才那樣稍微嘗試一下,也能說明我們在管理——甚至馴服——CSS級聯方面擁有多大的能力。按鈕具有欺騙性地複雜,但我們看到了處理從默認樣式到編寫其狀態和修改版本的樣式需要多少樣式。
以上是使用CSS級聯層組織設計系統組件圖案的詳細內容。更多資訊請關注PHP中文網其他相關文章!