原文連結:https://css-tricks.com/the-many-ways-to-include-css-in-javascript-applications/,作者:Dominic Magnifico
如有翻譯不準確,請多指正。
歡迎來到這個在前端開發領域極具爭議性的話題!我相信讀到這篇文章的大多數人都曾遇到過關於#如何在JavaScript應用程式中處理CSS#相關的熱門問題。
在這篇文章之前,我想聲明一句:沒有什麼硬性標準可以確定在React、Vue或Angular應用程式中處理CSS的哪一種方法是最好的。每個項目都是不同的,每個方法都有自己的優點!這樣說好像有點含糊不清,但我知道的是,我們所處的開發社區中有很多人去不斷尋求新信息,他們希望以更加有意義的方式推動web向前發展。
暫且把關於這個主題先入為主的概念放在一邊,讓我們來看看迷人的CSS體系結構世界吧!
首先讓我們一起來盤點一下這些方法
簡單地搜索「如何將CSS添加到[在此處插入框架]」就能出現一系列關於如何將樣式應用於項目的意見。為了幫助大家進行篩選摘除,我們將從各更高級的角度研究一些常用的方法及其目的。
選項1:傳統樣式表
我們完全可以用一種熟悉的方式開始:一個傳統樣式表,完全可以在應用程式之中連結一個外部樣式表,這樣就可以完工了。
我們可以按照我們的習慣編寫CSS,然後繼續我們的生活。這根本沒有什麼問題,但是隨著應用程式越來越大、越來越複雜,維護單個樣式表就越來越難了。解析數千行CSS(這些CSS負責設計整個應用程式的樣式)對於從事該項目的任何開發人員來說都是一件痛苦的事情。
樣式級聯看起來很美好但它也變得很難管理,因為你或項目上的其他開發者編寫的一些樣式會在應用程式的其他部分引入回歸。我們之前也遇到過這些問題,並且引入了Sass之類的東西(以及最近的PostCSS)來幫助我們處理這些問題。
我們可以繼續沿著這條路走下去,利用PostCSS的強大功能來編寫非常模塊化的CSS部分,這些部分通過@import規則串在一起。這需要在webpack配置中進行一些工作才能正確設置,但這些事情大家肯定可以處理!
無論你決定用哪種編譯器,你都可以通過標題中的標記獲得一個包含應用程式所有樣式的CSS文件。根據應用程式的複雜程度,這個文件可能會變得非常臃腫,難以異步加載,並且應用程式的其餘部分會出現租用者阻塞。(當然,阻塞並不總是一件壞事,但是為了所有的意圖和目的,我們將在這裡泛化一點,儘可能避免渲染阻塞腳本和樣式。)
這並不是說這種方法毫無優點,對於小型應用程式,或者由不太關注前端的團隊構建的應用程式,單個樣式表可能是一個不錯的選擇。它在業務邏輯和應用程式風格之間提供了清晰的分離,而且由於它不是由我們的應用程式生成的,因此完全在我們的控制範圍內,以確保我們編寫的內容與輸出的內容完全一致。此外,瀏覽器緩存單個CSS文件相當容易,因此返回的用戶在下次訪問時不必重新下載整個文件。
但是假設我們正在尋找一個更健壯的CSS架構,它允許我們利用工具的強大功能。它可以幫助我們管理一個需要更多微妙方法的應用程式,輸入CSS模塊。
選項2:CSS模塊
單個樣式表中的一個相當大的問題是回歸的風險。編寫使用相當非特定選擇器的CSS可能最終會改變應用程式中完全不同區域的另一個組件。這就是所謂的「作用域樣式」派上用場的地方。
帶作用域的樣式允許我們以程序化的方式生成特定於組件的類名。因此,將這些樣式限定到該特定組件,以確保其類名是唯一的。這將導致自動生成的類名,例如header__2lexd。最後一點是一個哈希值,它是唯一的,因此即使你有另一個名為header的組件,也可以對其應用標題類,並且我們的作用域樣式將生成一個新的哈希後綴,如下所示:header__15qy_。
CSS模塊提供了控制生成的類名的方法(具體取決於實現),但是我將把這個問題留給CSS模塊文檔來討論。
所有這些都完成之後,我們仍然在生成一個CSS文件,該文件通過<link>標頭中的標記傳遞給瀏覽器。這帶來了同樣的潛在缺點(渲染阻塞、文件大小膨脹等),當然也有好處主要是緩存作用。但是,由於這種方法的作用域樣式附帶了另一個警告:刪除全局作用域——至少在最初是這樣。
假設你想使用.screen-reader-text全局類,該類可以應用於應用程式中的任何組件。如果使用CSS模塊,則必須使用:global偽選擇器,該選擇器將其中的CSS明確定義為可被應用程式中其他組件全局訪問的對象。只要將包含global聲明塊的樣式表導入到組件的樣式表中,就可以使用該全局選擇器。這不是一個很大的缺點,但是需要逐漸適應。
這是一個:global偽選擇器的示例:
你可能會冒著將一堆用於字體,表格以及大多數站點的通用元素的全局選擇器放到一個單獨的global選擇器中的風險。幸運的是,通過諸如PostCSSNested或Sass之類的魔術,你可以將部分代碼直接導入選擇器中,以使事情更簡潔:
這樣,你可以不使用:global選擇器來編寫局部文件,而直接將其直接導入到主樣式表中。
需要習慣的另一點是如何在DOM節點中引用類名。我將在這裡以Vue,React和Angular的各個文檔為例。我還將為你提供一些示例,說明這些類引用在React組件中的使用方式:
同樣,CSSModules方法具有一些很好的用例。對於希望利用範圍樣式,同時保持靜態但已編譯樣式表的性能優勢的應用程式,CSS模塊可能是最適合你的選擇!
在這裡也要注意,CSS模塊可以與你喜歡的CSS預處理功能結合使用。Sass,Less,PostCSS等都可以使用CSS模塊集成到構建過程中。
但是,假設你的應用程式可以通過包含在JavaScript中而受益。也許獲得對組件各種狀態的訪問權並根據不斷變化的狀態做出反應也將是有益的。如果你也想輕鬆地將關鍵CSS集成到的應用程式中去,那就輸入CSS-in-JS吧。
選項3:CSS-in-JS
CSS-in-JS是一個相當廣泛的主題。有幾個包可以使CSS-in-JS的編寫變得儘可能輕鬆。像JSS、Emotion和樣式組件之類的框架只是構成本主題的眾多包中的一小部分。
作為大多數這些框架的粗略解釋,CSS-in-JS基本上以相同的方式運行。你編寫與單個組件關聯的CSS,並且構建過程將編譯該應用程式。發生這種情況時,大多數CSS-in-JS框架只會輸出在任何給定時間在頁面上呈現的組件的關聯CSS。CSS-in-JS框架通過在應用程式的<head>中的<style>標記內輸出該CSS來實現此目的。這為你提供了一個非常重要的CSS加載策略!另外,很像CSS模塊,樣式是作用域的,並且類名是散列的。
當你在應用程式中導航時,已卸載的組件將從<head>中刪除其樣式,而已裝入的傳入組件將在其位置附加其樣式。這為你的應用程式提供了性能優勢的機會。它刪除一個HTTP請求,不會阻止渲染,並確保你的用戶在任何給定時間僅下載他們需要的內容以查看該頁面。
CSS-in-JS提供的另一個有趣的機會是能夠引用各種組件狀態和功能以呈現不同的CSS。這可能很簡單,例如根據某些狀態變化來複製類切換,也可能像主題化一樣複雜。
因為CSS-in-JS是一個相當熱門的話題,所以我意識到人們正在嘗試採用許多不同的方法。現在,我分享了許多其他人對CSS的高度評價,尤其是在利用JavaScript編寫CSS方面。我對這種方法的最初反應是相當負面的。我不喜歡交叉汙染兩者的想法,但我想保持開放的態度。
讓我們來看看我們作為前端開發人員需要的一些功能,甚至可以考慮採用這些方法。
1. 如果我們要編寫CSS-in-JS,則必須編寫真實的CSS。多個軟體包提供了編寫模板文字CSS的方法,但是要求你用駝峰式大小寫屬性-即padding-left變成paddingLeft。那不是我個人願意犧牲的東西。
2. 某些CSS-in-JS解決方案要求你在要設置樣式的元素上內聯編寫樣式。這樣做的語法,尤其是在複雜的組件中,開始變得非常忙碌,而這又不是我願意犧牲的東西。
3. 使用CSS-in-JS必須為我提供強大的工具,否則這些工具很難通過CSS模塊或dangol的樣式表來完成。
4. 我們必須能夠利用具有前瞻性的CSS(例如嵌套和變量)。我們還必須能夠合併Autoprefixer之類的東西以及其他附加組件,以增強開發人員的體驗。
對於框架,有很多要求,但是對於那些一生中大部分時間都圍繞著我們喜歡的語言來研究和實現解決方案的人來說,我們必須確保我們能夠繼續以最好的語言編寫相同的語言我們可以快速瀏覽一下使用樣式化組件的React組件的外觀:
我們還需要解決CSS-in-JS解決方案的潛在缺點——而且絕對不要試圖引發更多的鬧劇。使用這樣的方法,我們很容易陷入一個陷阱,這會導致我們得到一個膨脹的JavaScript文件,其中可能包含數百行CSS——而這一切甚至在開發人員看到任何組件的方法或其HTML結構之前就已經出現了。
然而,我們可以將此視為一個機會,來非常仔細地檢查我們是如何以及為什麼以這種方式構建組件的。通過更深入地考慮這一點,我們可以潛在地利用它,並使用更多可重用組件編寫更簡潔的代碼。
此外,此方法絕對模糊了業務邏輯和應用程式樣式之間的界限。但是,有了一個有據可查且經過深思熟慮的體系結構,該項目中的其他開發人員可以輕鬆地採用這種想法,而不會感到不知所措。
寫在最後
有多種方法可以處理任何項目上的CSS體系結構的難題,並且可以在使用任何框架時進行處理。作為開發人員,我們擁有如此眾多的選擇,這既令人興奮,又令人難以置信。但是,我認為,最終我們會在超短的社交媒體對話中迷失的首要原因是——每種解決方案都有其優點和效率低下的弊病。這是關於我們如何謹慎,周到地實施使我們自己/或其他可能接觸代碼的開發人員的系統的感謝,感謝我們花時間建立該結構。