日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
為什么和CSS-in-JS說拜拜

本文是由 Emotion 的第二大活躍維護者 Sam 分享,本文第一人稱都指的是 Sam。Emotion 是一個廣泛流行的 CSS-in-JS 庫,用于React。文章 Sam 會帶大家深入探討 CSS-in-JS 最初吸引人的原因,以及為什么作者(以及Spot團隊的其他成員)決定放棄它。

創(chuàng)新互聯(lián)建站是一家專業(yè)提供瑞麗企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、H5場景定制、小程序制作等業(yè)務(wù)。10年已為瑞麗眾多企業(yè)、政府機構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進行中。

什么是 CSS-in-JS?

顧名思義,CSS-in-JS 就是在 JS 或 TS 中直接編寫 CSS,為 React 組件提供樣式,如下所示:

// Object Styles  方式
function ErrorMessage({ children }) {
return (
css={{
color: 'red',
fontWeight: 'bold',
}}
>
{children}

);
}

// String Styles 方式
const ErrorMessage = styled.div`
color: red;
font-weight: bold;
`;

styled-components和Emotion是React社區(qū)中最流行的CSS-in-JS庫。雖然我只使用了Emotion,但我相信本文的所有觀點也適用于styled-components。

本文重點介紹運行時CSS-in-JS,這個類別包括 styled-components 和 Emotion。運行時CSS-in-JS 僅僅意味著庫在應(yīng)用程序運行時解釋并應(yīng)用你的樣式。我們會在文章的最后簡要討論編譯時 CSS-in-JS。

CSS-in-JS 的好、壞、丑

在討論 CSS-in-JS 編碼模式及其對性能的影響之前,先來看看為什么有的開發(fā)者會使用 CSS-in-JS,有的不會使用。

好處

1.局部作用域的樣式。在寫普通的CSS時,很容易不小心將樣式應(yīng)用到其它文件中。例如,假設(shè)我們正在寫一個列表,每一行都應(yīng)該有一些 padding 和 border 。我們可能會這樣寫:

   .row {
padding: 0.5rem;
border: 1px solid #ddd;
}

幾個月后,當我們完全忘記了這個列表時,又創(chuàng)建了一個列表。然后也設(shè)置了 ??className="row"??。現(xiàn)在,新組件的行有一個難看的邊框,而我們卻不知道為什么! 雖然這類問題可以通過使用較長的類名或更具體的選擇器來解決,但作為開發(fā)者還是要確保沒有類名沖突。

CSS-in-JS 完全解決了這一問題,它使樣式默認為本地作用域。如果把上面的樣式寫成這樣:

...

這樣 padding 和  border 就不可能應(yīng)用到其它元素了。

2.托管。如果使用普通的CSS,則可以將所有.css文件放在 src/styles 目錄中,而所有的React組件都在 src/components 中。隨著應(yīng)用程序的大小的增長,很難判斷每個組件使用哪些樣式。很多時候,你的CSS中會出現(xiàn)死代碼,因為沒有簡單的方法可以說出這些樣式?jīng)]有使用。

一個更好的組織代碼的方法是將所有與單個組件相關(guān)的東西放在同一個地方。這種做法被稱為colocation (托管)。

問題是,在使用普通的CSS時,很難實現(xiàn) colocation,因為CSS和JavaScript必須放在單獨的文件中,而且無論??.css??文件在哪里,你的樣式都會全局應(yīng)用。另一方面,如果使用CSS-in-JS,可以直接在使用它們的React組件中編寫樣式 如果操作得當,這將極大地提高應(yīng)用程序的可維護性。

3.可以在樣式中使用JavaScript變量。CSS-in-JS 可以在樣式規(guī)則中引用JavaScript變量,例如:

// colors.ts
export const colors = {
primary: '#0d6efd',
border: '#ddd',
/* ... */
};
// MyComponent.tsx
function MyComponent({ fontSize }) {
return (
css={{
color: colors.primary,
fontSize,
border: `1px solid ${colors.border}`,
}}
>
...


);
}

如本示例所示,可以在CSS-in-JS樣式中同時使用 JS 常量(例如 colors)和 React Props/state (例如 fontSize)。

在樣式中使用 JS 常量的能力在某些情況下可以降低重復(fù),因為同一個常量不需要同時定義為CSS變量和 JS 常量。

使用 props 和 state 。

中立

這是一項熱門的新技術(shù)。許多Web開發(fā)者,包括我自己,一般會社區(qū)中最熱門的新趨勢。部分原因是這樣的,因為在很多情況下,新的庫和框架已經(jīng)被證明比它們的前輩有巨大的改進(想想React比早期的庫如jQuery提高了多少生產(chǎn)力就知道了)。

另一方面,我們對新工具的癡迷是害怕錯過下一個大事件,在決定采用一個新的庫或框架時,我們可能忽略了真正的缺點。我認為這肯定是CSS-in-JS被廣泛采用的一個因素--至少對我來說是這樣。

不好

1.CSS-in-JS增加了運行時的開銷。當組件渲染時,CSS-in-JS庫必須將樣式 "序列化"為可以插入到文檔中的普通CSS。很明顯,這需要占用額外的CPU周期,但這是否足以對應(yīng)用程序的性能產(chǎn)生明顯的影響?我們在下一節(jié)中深入研究這個問題。

2 CSS-in-JS增加的包的大小。這是一個明顯的問題--每個訪問你網(wǎng)站的用戶都必須下載CSS-in-JS庫的JavaScript。Emotion 的最小壓縮量是7.9 kB?,styled-components 是12.7 kB。

3.CSS-in-JS會打亂React DevTools。對于每個使用css prop 的元素,Emotion會渲染組件。如果你在許多元素上使用css prop,Emotion 的內(nèi)部組件會使React DevTools變得非?;靵y,如圖所示。

1.頻繁插入CSS規(guī)則迫使瀏覽器做很多額外的工作。React核心團隊成員、React Hooks的最初設(shè)計師Sebastian Markb?ge在React 18工作組中寫了一篇非常有見地的討論,內(nèi)容是關(guān)于CSS-in-JS庫需要如何改變才能與React 18一起工作,以及總體上關(guān)于運行時CSS-in-JS的未來。特別是,他說:

在并發(fā)渲染中,React可以在渲染之間向瀏覽器讓步。如果在一個組件中插入一個新的規(guī)則,如果React 讓步了,那么瀏覽器就必須看看這些規(guī)則是否適用于現(xiàn)有的樹。所以它會重新計算樣式規(guī)則。然后React渲染下一個組件,然后該組件發(fā)現(xiàn)了一個新的規(guī)則,再次發(fā)生。引用 這有效地導(dǎo)致在React渲染時,每一幀都要針對所有DOM節(jié)點重新計算所有CSS規(guī)則。這是很慢的。

這個問題最糟糕的地方在于,它不是一個可修復(fù)的問題(在運行時CSS-in-JS的上下文中)。運行時CSS-in-JS庫通過在組件渲染時插入新的樣式規(guī)則來工作,這在基本層面上不利于性能。

2.對于CSS-in-JS,可能出錯的地方還有很多,尤其是在使用SSR或組件庫的時候。在Emotion的GitHub倉庫里,我們收到了大量這樣的問題。

我正在使用Emotion與服務(wù)器端渲染和MUI/Mantine/(另一個Emotion驅(qū)動的組件庫),它不能工作,因為...

雖然每個問題的根本原因各不相同,但有一些共同的原因:

  • Emotion的多個實例被同時加載。即使多個實例都是同一版本的Emotion,這也會導(dǎo)致問題。(issue)
  • 組件庫通常不能完全控制插入樣式的順序。(issue)
  • Emotion的SSR支持在React 17和React 18之間的工作方式不同。為了與React 18的流式SSR兼容,這是必要的。(issue)

這些復(fù)雜性只是冰山一角。

性能

運行時 CSS-in-JS既有明顯的優(yōu)點也有明顯的缺點。為了理解我們的團隊為什么要放棄這項技術(shù),我們需要探索CSS-in-JS的實際性能影響。

本節(jié)重點介紹Emotion 對性能的影響,因為它被用于 Spot 代碼庫。因此,如果認為下給出的性能數(shù)據(jù)也適用于你的代碼庫,那就錯了--有很多方法可以使用Emotion,而且每一種方法都有自己的性能特點。

渲染內(nèi)的序列化與渲染外的序列化

樣式序列化是指Emotion將CSS字符串或?qū)ο髽邮睫D(zhuǎn)換為可以插入文檔的普通CSS字符串的過程。在序列化過程中,Emotion也會計算出一個普通CSS的哈希值--這個哈希值就是你在生成的類名中看到的,例如css-15nl2r3。

雖然我沒有測量過這一點,但我相信影響Emotion如何執(zhí)行的最重要因素之一是樣式序列化是在React渲染循環(huán)內(nèi)部還是外部執(zhí)行的。

Emotion文檔中的例子是在render里面進行序列化的,像這樣。

function MyComponent() {
return (
css={{
backgroundColor: 'blue',
width: 100,
height: 100,
}}
/>
);
}

每次MyComponent渲染的時候,對象的樣式都會被再次序列化。如果MyComponent頻繁地渲染(例如每次按鍵),重復(fù)的序列化可能會有很高的性能代價。

一個更有效的方法是把樣式移到組件之外,這樣序列化就會在模塊加載時一次性發(fā)生,而不是在每次渲染時。這可以通過@emotion/react的css函數(shù)來實現(xiàn):

const myCss = css({
backgroundColor: 'blue',
width: 100,
height: 100,
});

function MyComponent() {
return
;
}

當然,這種方式就無法在樣式中訪問 props,所以錯過了CSS-in-JS的主要賣點之一。

在Spot,我們在render中進行了樣式序列化,所以下面的性能分析將集中于這種情況。

對Member Browser 進行基準測試

現(xiàn)在通過對Spot的一個真正的組件進行分析來使事情具體化。我們將使用 Member Browser,這是一個相當簡單的列表視圖,可以顯示你的團隊中的所有用戶。

為了測試:

  • Member Browser 顯示20個用戶。
  • React.memo 周圍的列表項目將被刪除,并且強制最上面的組件每秒鐘渲染一次,并記錄前10次渲染的時間。
  • React嚴格模式是關(guān)閉的。(它可以效地讓我們在分析器中看到的渲染時間翻倍)。

我使用React DevTools對該頁面進行了分析,前10次渲染時間的平均值為54.3ms。

我個人的經(jīng)驗是,一個React組件的渲染時間應(yīng)該在16毫秒以內(nèi),因為每秒60幀的1幀是16.67毫秒。Member Browser 目前是這個數(shù)字的3倍多,所以它是一個相當重量級的組件。

這個測試是在M1 Max CPU上進行的,它比普通用戶的速度要快很多。我得到的54.3毫秒的渲染時間在性能較差的機器上可能很容易達到200毫秒。

使用火焰圖(FlameGraph)分析程序性能

下面是上述測試中單個列表項的火焰圖:

正如你所看到的,有大量的組件被渲染--這些是我們的 "tyle primitives",使用css prop。雖然每個只需要0.1-0.2毫秒的渲染時間,但由于組件的總數(shù)非常大,所以這就增加了。

不使用 Emotion,對 Member Browser 進行測試

為了了解這種昂貴的渲染有多少是由Emotion造成的,我使用Sass Modules而不是Emotion重寫了Member Browser 的樣式。(Sass模塊在構(gòu)建時被編譯成普通的CSS,所以使用它們幾乎沒有性能損失)。

我重復(fù)了上述同樣的測試,前10次渲染的平均時間為27.7ms。這比原來的時間減少了48%!

所以,這就是我們與CSS-in-JS 說拜拜的原因:運行時的性能成本實在是太高了。

重復(fù)我上面的免責聲明:這個結(jié)果只直接適用于Spot代碼庫和我們使用Emotion的方式。如果你的代碼庫以一種更有效的方式使用Emotion(例如在render之外的樣式序列化),你可能會看到從方程中移除CSS-in-JS后的更小好處。

下面是一些數(shù)據(jù),供那些好奇的人參考:

我們新的樣式系統(tǒng)

在我們下定決心不再使用CSS-in-JS之后,一個新的問題就會出現(xiàn):我們應(yīng)該用什么來代替?理想情況下,我們希望樣式系統(tǒng)的性能與普通CSS類似,同時盡可能多地保留CSS-in-JS的優(yōu)點:

  • 局部作用域
  • 樣式與它們所應(yīng)用的組件放在同個地方
  • 可以在樣式中使用 JS 變量

如果你仔細看了那一節(jié),你會記得我說過,CSS Module 還提供了局部作用域的樣式和同位。而且,CSS Module 可以編譯成普通的CSS文件,所以使用它們沒有運行時的性能成本。

在我看來,CSS模塊的主要缺點是,說到底,它們?nèi)匀皇瞧胀ǖ腃SS--而普通的CSS缺乏改善DX和減少代碼重復(fù)的功能。雖然嵌套選擇器即將出現(xiàn)在CSS中,但它們還沒有出現(xiàn),而這個功能對我們來說是一個巨大開發(fā)質(zhì)量的提升。

幸運的是,這個問題有一個簡單的解決方案--Sass模塊,它只是用Sass編寫的CSS模塊。你可以得到CSS模塊的局部范圍的樣式和Sass強大的構(gòu)建時間功能,而且基本上沒有運行時間成本。這就是為什么Sass模塊將成為我們未來的通用樣式解決方案。

實用類

對于從Emotion切換到Sass Modules,團隊的一個擔心是,應(yīng)用極其常見的樣式,如display: flex,會不太方便。以前,我們會寫。

...

為了只使用Sass模塊做到這一點,我們必須打開.module。SCSS文件并創(chuàng)建一個應(yīng)用樣式display: flex和align-items: center的類。雖然不是世界末日,但確實不那么方便了。

如果只使用Sass模塊,我們不得在新建.module.scss文件,并創(chuàng)建一個類,應(yīng)用樣式display: flex 和 align-items: center。這并不是災(zāi)難,但肯定不那么方便。

為了改進DX,我們決定引入一個實用類系統(tǒng)。實用類就是是在元素上設(shè)置一個單一的CSS屬性的CSS類。通常情況下,結(jié)合多個實用類來獲得所需的樣式。對于上面的例子,可以這樣寫。

...

Bootstrap和Tailwind是提供實用程序類的最流行的CSS框架。這些庫在其實用程序系統(tǒng)中投入了大量的設(shè)計工作,所以采用其中一個而不是推出我們自己的實用程序是最有意義的。我已經(jīng)使用Bootstrap多年了,所以我們選擇了Bootstrap。雖然你可以把Bootstrap的實用類作為一個預(yù)建的CSS文件,但我們需要定制這些類來適應(yīng)我們現(xiàn)有的樣式系統(tǒng),所以我把Bootstrap源代碼的相關(guān)部分復(fù)制到我們的項目中。

我們使用Sass模塊和實用類的新組件已經(jīng)有幾個星期了,對它相當滿意。DX與Emotion相似,而運行時的性能則大大優(yōu)于Emotion。

關(guān)于編譯時CSS-in-JS的說明

本文主要介紹運行時的CSS-in-JS庫,如 Emotion 和s tyled-components。最近,我們看到越來越多的CSS-in-JS庫在編譯時將樣式轉(zhuǎn)換為普通CSS。這些庫包括:

  1. Compiled
  2. Vanilla Extract
  3. Linaria

這些庫旨在提供類似于運行時CSS-in-JS的好處,而沒有性能成本。

雖然我自己沒有使用過任何編譯時的CSS-in-JS庫,但我仍然認為它們與Sass模塊相比有缺點。以下是我在觀察Compiled時看到的缺點:

  • 樣式仍然是在組件第一次掛載時插入的,這迫使瀏覽器在每個DOM節(jié)點上重新計算樣式。(這個缺點已經(jīng)在 "丑"一節(jié)中討論過了)。
  • 像本例中的 color prop 這樣的動態(tài)樣式不能在構(gòu)建時提取,所以Compiled使用 style prop(又稱內(nèi)聯(lián)樣式)將該值添加為CSS變量。眾所周知,當應(yīng)用許多元素時,內(nèi)聯(lián)樣式會導(dǎo)致次優(yōu)的性能
  • 該庫仍然將模板組件插入你的React樹中,如圖所示。這將使React DevTools變得混亂,就像運行時的CSS-in-JS一樣。

總結(jié)

任何技術(shù)一樣,它有其優(yōu)點和缺點。歸根結(jié)底,作為一個開發(fā)者,你應(yīng)該評估這些優(yōu)點和缺點,然后就該技術(shù)是否適合你的使用情況做出一個明智的決定。對于我們Spot公司來說,Emotion的運行時性能成本遠遠超過了DX的好處,特別是當你考慮到Sass模塊+實用類的替代方案仍然有一個很好的DX,同時提供巨大的性能。


當前標題:為什么和CSS-in-JS說拜拜
標題URL:http://m.5511xx.com/article/cdipepi.html