このドキュメントには、サーバーサイドレンダリングとタイプスクリプトをサポートする現在のすべてのCSS-in-JSソリューションの詳細な分析が含まれています。
比較に使用するベースライン参照は、CSSモジュールアプローチです。
next.jsを、リソースを構築するためのSSRフレームワークとして使用しています。
最後の重要な側面は、完全なタイプスクリプトサポートを備えたタイプセーフティです。
?最終更新: 2021年8月
?概要を短くするには、 CSSトリックに関する記事を確認できます。
https://css-tricks.com/a-thorough- analysis-of-css-in-js/
?代わりにビデオを好む場合は、 Ngpartyczからの私の講演をチェックアウトできます。
https://www.youtube.com/watch?v=c7uwghrax9a
結論にジャンプする前に、目標と免責事項をチェックアウトしてください。
CSS言語とCSSモジュールには、特にタイプセーフコードが必要な場合は、いくつかの制限があります。これらの制限の一部には変化のソリューションがあり、他のものはただ迷惑なものであるか、理想的ではありません。
スタイルをコンポーネントと共同で配置することはできません
これは、多くの小さなコンポーネントを執筆するときにイライラする可能性がありますが、それは取引ブレーカーではありません。ただし、 component.jsファイルとcomponent.cssファイルの間を往復し、特定のクラス名を検索し、 「スタイル定義に移行する」ことができないことの経験は、重要な生産性の欠点です。
スタイリングとメディアのクエリには、セレクターの複製が必要です
もう1つのイライラする事実は、擬似クラスや要素、またはメディアクエリを定義する際にCSSクラスを複製する必要性です。これらの制限を、SASS、Less、StylusなどのCSSプリプロセッサを使用して、コンテキストスタイリングを可能にして、 &親セレクターをサポートすることができます。
. button {}
/* duplicated selector declaration for pseudo classes/elements */
. button : hover {}
. button :: after {}
@media ( min-width : 640 px ) {
/* duplicated selector declaration inside media queries */
. button {}
}スタイルの使用法は、定義から切断されます
CSSモジュールを使用してIntellisenseはありません。CSSクラスがcomponent.cssファイルで定義されているものを取得し、コピーパステを必要なツールにし、DXを下げます。また、安全性が不足しているため、リファクタリングを非常に面倒にします。
CSSでタイプセーフデザイントークンを使用することは自明ではありません
JS/TSで定義されているデザイントークン(タイプセーフティの恩恵を受けるため)は、CSSで直接使用することはできません。
この問題には少なくとも2つの回避策がありますが、どちらもエレガントではありません。
.module.cssで使用してもIntellisenseや型安全性は得られません。.cssファイルに分割します。この分析には、特定の目標があります。
さらに具体的には、次のようなさまざまなCSS-in-JSソリューションの使用を体験したかったのです。
props (別名コンポーネントバリアント)に基づく動的スタイル、またはユーザー入力からこの分析は、客観的であり、感染していないことを目的としています。
?ここには何が見つかりませんか?
?ここで何が見つかりますか?
ライブラリは特定の順序で提示されません。 CSS-in-JSの短い歴史に興味がある場合は、Max StoiberによるCSS-in-JSの洞察に満ちた話の過去、現在、未来をチェックアウトする必要があります。
| 1。コロケーション | 2。DX | 3。 tag` ` | 4。 { } | 5。TS | 6。 & ctx | 7。ネスト | 8。テーマ | .css | 10。 <style> | 11。アトミック | className | 13。 <Styled /> | cssプロップ | 15。不可知論者 | 16。ページサイズのデルタ | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CSSモジュール | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | |||||||||
| スタイルJSX | ✅ | ? | ✅ | ? | ✅ | ✅ | ✅ | +2.8 kB / +12.0 kB | ||||||||
| スタイルのコンポーネント | ✅ | ? | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +13.4 kB / +39.0 kB | ||||
| 感情 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +6.5 kB / +20.0 kB | ||
| Typestyle | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | ✅ | ✅ | +2.1 kB / +8.0 kB | |||||
| フェラ | ✅ | ? | ? | ✅ | ? | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +11.9 kB / +43.0 kB | |||
| ステッチ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | +5.3 kB / +17.0 kB | |||
| JSS | ✅ | ✅ | ? | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | +18.2 kB / +60.0 kB | |||
| グーバー | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | +1.1 kB / +4.0 kB | ||
| コンパイル | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | ✅ | +3.5 kB / +9.0 kB | |||
| リナリア | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +2.7 kB / +6.0 kB | ||||
| バニラ抽出物 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | ✅ | +0.0 kB / -2.0 kB |
コンポーネントと同じファイル内のスタイルを定義する機能。スタイルを別のファイルに抽出してインポートすることもできます。
概要概要まで
2つの主要な側面を含む開発者エクスペリエンスを指します。
概要概要まで
tag` ` (タグ付きテンプレート)ESタグ付きテンプレートを使用して、スタイルを文字列として定義するためのサポート:
kebab-case使用します。stringのように見えます。概要概要まで
{ } (オブジェクトスタイル)プレーンJavaScriptオブジェクトを使用して、スタイルをオブジェクトとして定義するためのサポート:
camelCaseを使用します。概要概要まで
組み込み、または@typesパッケージを介して、タイプスクリプトサポートが含まれます。
Propsジェネリック(ダイナミックスタイルを定義するときにコンポーネントプロップタイプへのタイプセーフアクセスを取得);概要概要まで
& CTX(コンテキストスタイル)コンテキストスタイルのサポートにより、プレーンCSSで必要に応じて、セレクターを繰り返す必要なく、擬似クラスと要素とメディアクエリを簡単に定義できます。
& Parent Selectorをサポートできます。概要概要まで
任意のネストされたセレクターのサポート:
概要概要まで
設計システムのトークンのテーマまたは管理のための組み込みサポート。
この機能をテストしていないため、どの図書館がドキュメントでサポートを表明するメモを取っています。
概要概要まで
.css (静的CSS抽出)定義されたスタイルは、静的.cssファイルとして抽出されます。
概要概要まで
<style>タグ定義されたスタイルは、ドキュメントの<head>に<style>タグ内に注入されます:
概要概要まで
アトミックCSSクラスを生成する能力、したがってスタイルの再利用性を高め、重複を減らす:
概要概要まで
classNameライブラリAPIは、コンポーネントまたは要素に追加する必要があるstringを返します。
概要概要まで
<Styled /> APIは、生成されたclassNameを含むラッパー(またはStyled )コンポーネントを作成します。
button_stylesやlist_stylesなどの定数ではなく、 StyledButtonやStyledListなどのコンポーネントを作成することになります。概要概要まで
cssプロップ特別なcssプロップを使用してスタイルを渡すことができます。インラインスタイルを定義する方法も同様ですが、ライブラリは舞台裏でユニークなCSSクラス名を生成します。
概要概要まで
フレームワークなしで、またはフレームワークを使用して使用を許可します。一部のライブラリは、Reactのみ専用に構築されています。
注:ステッチや感情文書のような一部のライブラリは、使用のみを反応させるだけですが、フレームワークの不可知論者であるコアがあります。
概要概要まで
next.jsを使用したインデックスページの生産ビルド全体について、 CSSモジュールと比較して、KBの合計ページサイズの差(転送されたGZIPTおよびMINIFIED / MINIFIED /非圧縮および模倣)の違い:
注:すべてのビルドはnext.js 11.1.0で行われ、値はネットワークとリソースサイズを介して転送されたChrome Devtoolsネットワークタブから取得されます。
概要概要まで
次の観察結果は、すべてのソリューションに適用されます(わずかな指摘された例外を除く)。
特定のルートでのみ使用されるコンポーネントは、そのルートに対してのみバンドルされます。これは、next.jsがすぐに実行するものです。
すべてのソリューションは、専用のAPIを備えたグローバルスタイルを定義する方法を提供します。
すべてのソリューションは、サーバー側のレンダリングサポートを提供し、next.jsと簡単に統合できます。
すべてのソリューションは、すぐにベンダー固有のプレフィックスを自動的に追加します。
すべてのソリューションは、CSSモジュールのように一意のクラス名を生成します。これらの名前を生成するために使用されるアルゴリズムは、ライブラリ間で大きく異なります。
Cardコンポーネントの.headingスタイルには常に.Card_heading_h7Ys5ハッシュがあります)。.heading-0-2-1 、 .input-0-2-2 )またはアルファベット文字( a, b, c, ... aa, ab, acなど)のいずれかを増加させるカウントを使用し、このアプローチをよりパフォーマンスしますが、非公式のクラス名になります(潜在的な欠点があるかどうかはわかりません)。 ラジウムとグラマーが使用する、古いアプローチであるインラインスタイルはどれも生成されません。このアプローチはCSSクラスよりもパフォーマンスが低く、スタイルを定義するための主要な方法として推奨されていません。また、インラインスタイルではサポートされていないため、JSイベントハンドラーを使用して擬似クラスをトリガーすることを意味します。どうやら、最近のすべての最新のソリューションはこのアプローチから離れました。
すべてのソリューションは、必要なほとんどのCSSプロパティをサポートしています:擬似クラスと要素、メディアクエリ、キーフレームは、私たちがテストしたものです。
ほとんどのソリューションは、SSR中に「重要なCSSを抽出する」ことができると自分自身を販売しています。私たちが最初に考えたように、これは倍以上の重要なCSS抽出を指すものではないことに注意してください。
彼らが実際にすること:
100%の静的CSSでは、実際には利点がありません。サーバー上の要素が非常に少ない動的ページと、ほとんどのコンポーネントがクライアントで動的にレンダリングされると、利点が増加します。
例外:静的CSS抽出を使用するライブラリ。
これらの機能がコアWebバイタルとパフォーマンスメトリックに一般的にどのように影響するかを理解することは、考慮すべき非常に重要な要素であり、クライアントにスタイルを提供する方法がおそらく最大の影響を与えるため、これを詳細に分析しましょう。
また、考慮する必要がある2つの異なるシナリオがあります。
.js 、 .css 、メディアなど)。 .cssファイル抽出.css静的ファイルを生成するソリューションは、通常、ページの<head>に<link>タグとして含めることができますが、基本的にブロックリソースをレンダリングします。これは、 FCP 、 LCP 、およびその他のメトリックに大きく影響します。
?空のキャッシュ
ユーザーが空のキャッシュを持っている場合、 FCPとLCPに悪影響を与える必要があります。
<body>のレンダリングを遅らせ、熱心に解析され、一部のリソースはすでに事前に取得されています。他の<head>リソース(追加の.cssまたは.jsファイル)を並行して取得できることは事実ですが、これは一般的に悪い練習です。
?フルキャッシュ
ただし、その後の訪問では、 .cssリソース全体がキャッシュされるため、 FCPとLCPはプラスの影響を受けます。
キーポイント
このソリューションは、次の場合に適しているようです。
.cssファイルが含まれている可能性もあります。<style>タグ噴射スタイルSSRの間、スタイルはページの<head>に<style>タグとして追加されます。ほとんどのライブラリは重要なCSS抽出を実行するため、これらは通常、ページに必要なすべてのスタイルが含まれているわけではないため、これらのstyles通常、前述の.css静的ファイル全体よりも小さくする必要があることに注意してください。
?空のキャッシュ
CSSバイトが少なく、それらは.htmlファイルにインラリングされているため、 FCPとLCPが高速になります。
.cssファイルの追加のリクエストは必要ないため、ブラウザはブロックされていません。.jsファイルリクエストをドキュメントの最後に移動すると、 <head>リクエストを実行しないため、レンダリングは非常に高速に発生します。.css抽出では必要ありませんでした。.jsファイルにバンドルされています(これには、 <style>タグ +その他内に既に出荷されているすべての重要なCSSが含まれます)。 ?フルキャッシュ
ユーザーのキャッシュがいっぱいになった場合、追加の.jsファイルはすでにキャッシュされているため、フェッチする必要はありません。
ただし、ページがSSREDの場合、ドキュメントの<style>タグでレンダリングされたインライン化された重要なCSSは、キャッシュできる静的HTMLを扱う場合を除き、再びダウンロードされます。
ただし、デフォルトでは、キャッシュされているかどうかに関係なく、すべてのページHTTPリクエストに追加のバイトを出荷します。
キーポイント
このソリューションは、次の場合に適しているようです。
ほとんどのソリューションは、未使用のコード/スタイルを削除すると言います。これは半分だけです。
特に10年前に書いていたように、Plain .cssファイルと比較する場合、未使用のコードは蓄積するのがより困難です。しかし、CSSモジュールと比較すると、違いはそれほど大きくありません。任意のセレクターまたはネストされたスタイルを定義するオプションを提供するソリューションは、コンポーネント内で使用されているかどうかにかかわらず、それらをバンドルします。テストされたすべてのソリューションを使用して、未使用のSSRスタイルを出荷することができました。
CSS構文はタイプチェックされておらず、静的に分析できないため、Trueおよび完全な未使用のコード削除を実装することは困難です。また、コンポーネントの動的な性質により、特定のシナリオでは、特にマークアップが動的にレンダリングされている場合は、事実上不可能になります。
& span :子孫の要素。&:nth-child() :特定の擬似セレクター。& .bg-${color} :動的セレクター;.parent & :親のセレクター;基本的に、コンポーネントを削除するとき、またはそれをインポートしなくなったときのコード削除です。スタイルはコンポーネントの直接的な依存関係であるため、それは暗黙の動作です。コンポーネントがなくなると、そのスタイルもなくなります。
CSSをDOMに注入し、JavaScriptから更新する2つの方法があります。
<style>タグを使用するこのアプローチは、dom( <head>または<body>のどこかのいずれか)に1つ以上の<style>タグを追加することを意味し、.appendChild()を使用して<style>ノードを追加し、さらに.textcontent、.innerhtmlで<style>タグ(s)を更新します。
<style>タグのみを使用して、コンテンツ全体を更新すると、CSSルールの小さなセットのみを実際に変更した場合、DOM全体を更新するのが遅くなる可能性があります。DEVELOPMENTモードでこのソリューションを使用しています。これは、より良いデバッグエクスペリエンスを提供するためです。PRODUCTIONでも使用します。 CSSStyleSheetの使用JSSが最初に使用したこの方法では、 CSSStyleSheet.insertRule()を使用してCSSSルールをCSSOMに直接注入します。
<style>注入されるかを確認するのはもう少し困難です。<style>タグを選択する必要があります。$0でアクセスできます(または、Dom APIを使用して、他の方法で参照を取得します)。<style>タグにアクセス.sheet.cssRulesに含まれるCSSルールの配列を表示するには。PRODUCTIONに使用しています。DEVELOPMENTモードでも使用します。 同じコンポーネントが2つの異なるルートでインポートされている場合、クライアントに2回送信されます。これは確かにバンドラー/ビルドシステムの制限であり、私たちの場合はnext.jsであり、 CSS-in-JSソリューションとは関係ありません。
next.jsでは、ルートレベルでコードスプリッティが機能し、特定のルートに必要なすべてのコンポーネントをバンドリングしますが、公式のブログとweb.devによると、コンポーネントがページの50%以上で使用されている場合は、 commonsバンドルに含まれます。ただし、この例では、2ページがそれぞれButtonコンポーネントをインポートしており、 commonsバンドルではなく各ページバンドルに含まれています。スタイリングに必要なコードはコンポーネントにバンドルされているため、この制限はスタイルにも影響を与えるため、これを念頭に置く価値があります。
これは十分に確立され、成熟した、しっかりしたアプローチです。間違いなく、特にコンポーネントベースのアプリケーションでCSSを構築および整理するためのBEM、SMACCS、OOCSS、またはその他のスケーラブルなCSS方法論を大幅に改善します。
2015年に発売|概要に戻ります
contextコンテキスト対応コードの完了
frame枠が不可知論されます
スタイル/コンポーネントのコロケーションはありません
タイプスクリプトサポートはありません
原子CSSはありません
テーマのサポートはありません
スタイル定義方法
ネスティングのスタイル
スタイルは方法を適用します
classNamestyledコンポーネントcss Propスタイル出力
.cssファイル抽出<style>タグインジェクションこれは、以下のすべてのCSS-in-JSソリューションを比較するときに考慮するベースラインです。私たちが埋めようとしているこのアプローチの限界をよりよく理解するための動機をチェックアウトしてください。
| 転送 / gzip | 圧迫されていません | |
|---|---|---|
| インデックスページサイズ | 76.7 kb | 233 kb |
Page Size First Load JS
┌ ○ / 2.19 kB 68.7 kB
├ └ css/1d1f8eb014b85b65feee.css 450 B
├ /_app 0 B 66.5 kB
├ ○ /404 194 B 66.7 kB
└ ○ /other 744 B 67.2 kB
└ css/1c8bc5a96764df6b92b4.css 481 B
+ First Load JS shared by all 66.5 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.40892d.js 555 B
├ chunks/webpack.ddd010.js 822 B
└ css/a92bf2d3acbab964f6ac.css 319 B
非常にシンプルな解決策は、ドキュメント用の専用のWebサイトを持っていません。すべてがGitHubにあります。人気はありませんが、next.jsの組み込みソリューションです。
バージョン: 4.0 | Vercelによって維持| 2017年に発売|ドキュメントを表示| ...概要に戻ります
✅スタイル/コンポーネントのコロケーション
?コンテキストアウェアコードの完了:構文の強調表示とコード完了を取得するには、エディター拡張機能が必要です
?タイプスクリプトサポート: @types追加インストールできますが、APIは最小限です。
原子CSSはありません
テーマのサポートはありません
フレームワーク不可知論者ではありません
スタイル定義方法
ネスティングのスタイル
スタイルは方法を適用します
classNamestyledコンポーネントcss Propスタイル出力
.cssファイル抽出<style>タグインジェクションelementsもターゲットにすることができ、彼らのために一意のクラス名を生成します(ただし、それが良い練習かどうかはわかりません)全体として、私たちはプレーンCSSを書くように感じました。コンポーネントとともにスタイルを定義できるという追加の利点があるため、追加の.cssファイルは必要ありません。実際、これはライブラリの哲学です。コンポーネントファイル内のCSS構文をサポートしています。文字列補間を使用して、関数のJS/TS定数を使用できます。ダイナミックスタイルを使用することは、最終的には単純なJavaScriptであるため、非常に簡単です。これらすべての利点は非常に低価格で、かなり小さなバンドルが頭上で得られます。
欠点は、プレーンCSSを書くことの全体的な経験です。ネストをサポートせずに、疑似クラス/要素とメディアクエリが管理するのがかなり面倒になります。
| 転送 / gzip | 圧迫されていません | |
|---|---|---|
| インデックスページサイズ | 79.5 kb | 245 kb |
| 対CSSモジュール | +2.8 kb | +12 kb |
Page Size First Load JS
┌ ○ / 2.65 kB 72.6 kB
├ /_app 0 B 70 kB
├ ○ /404 194 B 70.2 kB
└ ○ /other 1.18 kB 71.2 kB
+ First Load JS shared by all 70 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.a4b061.js 4.12 kB
└ chunks/webpack.61f1b6.js 778 B
確かに、最も人気のある成熟したソリューションの1つであり、優れたドキュメントがあります。タグ付きテンプレートを使用して、デフォルトでスタイルを定義しますが、オブジェクトも使用できます。また、定義されたスタイルとともに新しいコンポーネントを作成するstyledコンポーネントアプローチを普及させました。
バージョン: 5.3 | Max Stoiberとその他によって維持されています| 2016年に発売|ドキュメントを表示| ...概要に戻ります
✅スタイル/コンポーネントのコロケーション
✅タイプスクリプトサポート: @types 、EnculationTeptedを介して追加インストールする必要があります
✅内蔵テーマのサポート
frame枠が不可知論されます
?コンテキストアウェアコードの完了:エディター拡張機能/プラグインが必要です
原子CSSはありません
スタイル定義方法
ネスティングのスタイル
スタイルは方法を適用します
classNamestyledコンポーネントcssプロップスタイル出力
.cssファイル抽出<style>タグインジェクションPropsバリエーションなどに基づいて動的なスタイルを混合する)スタイルのコンポーネントは、定義されたスタイルを含む新しいコンポーネントを作成するstyledメソッドを使用して、スタイリングコンポーネントへの新しいアプローチを提供します。 CSSを書くことは気にしないので、CSSモジュールから来ると、スタイルを定義するために、よりプログラム的な新しい方法を学ぶ必要があります。 stringとobject構文の両方を可能にするため、既存のスタイルを移行することとプロジェクトをゼロから開始するためのかなり柔軟なソリューションです。また、メンテナーは、この分野のイノベーションのほとんどに追いついているかなり良い仕事をしました。
ただし、採用する前に、バンドルサイズには一定のコストがかかることに注意する必要があります。
| 転送 / gzip | 圧迫されていません | |
|---|---|---|
| インデックスページサイズ | 90.1 kb | 272 KB |
| 対CSSモジュール | +13.4 kb | +39 kb |
Page Size First Load JS
┌ ○ / 2.52 kB 83.1 kB
├ /_app 0 B 80.6 kB
├ ○ /404 194 B 80.8 kB
└ ○ /other 1.06 kB 81.7 kB
+ First Load JS shared by all 80.6 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.731ace.js 14.7 kB
└ chunks/webpack.ddd010.js 822 B
おそらく、最も包括的で、完全で柔らかいソリューション。 TypeScriptで完全に構築された詳細なドキュメントは、非常に成熟しており、機能が豊富で、よく整備されています。
バージョン: 11.4 |ミッチェル・ハミルトンとその他によって維持されています| 2017年に発売|ドキュメントを表示| ...概要に戻ります
✅スタイル/コンポーネントのコロケーション
typeptipscriptサポート
✅内蔵テーマのサポート
Context-Awareコードの完了: styledコンポーネントアプローチを使用するには、追加のエディタープラグインが必要です
frame枠が不可知論されます
原子CSSはありません
スタイル定義方法
ネスティングのスタイル
スタイルは方法を適用します
className ( @emotion/cssを使用)styledコンポーネントcssプロップスタイル出力
.cssファイル抽出<style>タグインジェクションcss Propは開発中に優れた人間工学を提供しますが、React 17の新しいjsx変換に基づいて新しいアプローチであるように思われ、それを構成することは些細なことではなく、セットアップが異なり、ボイラープレートを意味します(すぐに変化し、簡単になります) styledアプローチを使用すると、バンドルに3 kB追加されます。これは、別のパッケージからインポートされているためです。styledを分割する方法がわからないため、コンポーネントバリアントcss非常に汚染された重複スタイルをもたらします。 全体的な感情は、非常に堅実で柔軟なアプローチのようです。小説css Propアプローチは、開発者に優れた人間工学を提供します。ダイナミックスタイルとタイプスクリプトを使用することは非常に簡単で直感的です。スタイルを定義するときにstringsとobjects両方をサポートすると、プレーンCSSから移動するとき、またはゼロから始めるときに簡単に使用できます。バンドルオーバーヘッドは無視できませんが、特に提供する豊富な一連の機能を考慮する場合は、他のソリューションよりもはるかに小さいことは間違いありません。
パフォーマンスに焦点を当てているのではなく、開発者エクスペリエンスに焦点を当てているようです。完璧な「バランスのとれた」ソリューションのように見えます。
| 転送 / gzip | 圧迫されていません | |
|---|---|---|
| インデックスページサイズ | 83.2 kb | 253 kb |
| 対CSSモジュール | +6.5 kb | +20 kb |
Page Size First Load JS
┌ ○ / 2.5 kB 76.4 kB
├ /_app 0 B 73.9 kB
├ ○ /404 194 B 74.1 kB
└ ○ /other 1.07 kB 74.9 kB
+ First Load JS shared by all 73.9 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.6cb893.js 23.3 kB
├ chunks/pages/_app.b6d380.js 7.68 kB
└ chunks/webpack.ddd010.js 822 B
タイプチェックにのみ焦点を当てた最小限のライブラリ。これはフレームワーク不可欠なものです。そのため、動的スタイルを処理するための特別なAPIがありません。 There are React wrappers available, but the typings feels a bit convoluted.
Version: 2.1 | Maintained by Basarat | Launched in 2017 | View Docs | ... back to Overview
✅ Styles/Component co-location
✅ TypeScript support
✅ Context-aware code completion
✅ Framework agnostic
? Built-in Theming support : uses TS namespaces to define theming, which is not a recommended TS feature even by the author himself, or by TS core team member Orta Therox.
No Atomic CSS
Styles definition method(s)
Styles nesting
Styles apply method(s)
classNamestyled componentcss propStyles output
.css file extraction<style> tag injection <style> tag with all the styles, and replaces it on update, and apparently it doesn't use insertRule() , not even in production builds, which might be an important performance drawback in large & highly dynamic UIs Overall TypeStyle seems a minimal library, relatively easy to adopt because we don't have to rewrite our components, thanks to the classic className approach. However we do have to rewrite our styles, because of the Style Object syntax. We didn't feel like writting CSS, so there is a learning curve we need to climb.
With Next.js or React in general we don't get much value out-of-the-box, so we still need to perform a lot of manual work. The external react-typestyle binding doesn't support hooks, it seems to be an abandoned project and the typings are too convoluted to be considered an elegant solution.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 78.8 kB | 241 kB |
| vs. CSS Modules | +2.1 kB | +8 kB |
Page Size First Load JS
┌ ○ / 2.44 kB 72.1 kB
├ /_app 0 B 69.7 kB
├ ○ /404 194 B 69.9 kB
└ ○ /other 975 B 70.7 kB
+ First Load JS shared by all 69.7 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.5b0422.js 3.81 kB
└ chunks/webpack.61f1b6.js 778 B
It appears to be a mature solution, with quite a number of users. The API is intuitive and very easy to use, great integration for React using hooks.
Version: 11.6 | Maintained by Robin Weser | Launched in 2016 | View Docs | ... back to Overview
✅ Styles/Component co-location
✅ Built-in Theming support
✅ Atomic CSS
✅ Framework agnostic
? TypeScript support : it exposes Flow types, which work ok, from our (limited) experience
? Context-aware code completion : styles defined outside the component require explicit typing to get code completion
Styles definition method(s)
Styles nesting
Styles apply method(s)
classNamestyled componentcss propStyles output
.css file extraction<style> tag injection a , b , ...)Fela looks to be a mature solution, with active development. It introduces 2 great features which we enjoyed a lot. The first one is the basic principle that "Style as a Function of State" which makes working with dynamic styles feel super natural and integrates perfectly with React's mindset. The second is atomic CSS class names, which should potentially scale great when used in large applications.
The lack of TS support however is a bummer, considering we're looking for a fully type-safe solution. Also, the scaling benefits of atomic CSS should be measured against the library bundle size.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 88.6 kB | 276 kB |
| vs. CSS Modules | +11.9 kB | +43 kB |
Page Size First Load JS
┌ ○ / 2.84 kB 81.7 kB
├ /_app 0 B 78.9 kB
├ ○ /404 194 B 79 kB
└ ○ /other 1.43 kB 80.3 kB
+ First Load JS shared by all 78.9 kB
├ chunks/framework.2191d1.js 42.4 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.32bc1d.js 12.6 kB
└ chunks/webpack.ddd010.js 822 B
Very young library, solid, modern and well-thought-out solution. The overall experience is just great, full TS support, a lot of other useful features baked in the lib.
Version: 0.2.5 (beta) | Maintained by Modulz | Launched in 2020 | View Docs | ... back to Overview
✅ Styles/Component co-location
✅ TypeScript support
✅ Context-aware code completion
✅ Built-in Theming support
✅ Framework agnostic : (available with @stitches/core )
Atomic CSS
Styles definition method(s)
Styles nesting
Styles apply method(s)
classNamestyled componentcss prop (used only to override styled components)Styles output
.css file extraction<style> tag injection variants (for predefined styles), or styles created inside the component to get access to the propsStitches is probably the most modern solution to this date, with full out-of-the-box support for TS. Without a doubt, they took some of the best features from other solutions and put them together for an awesome development experience. The first thing that impressed us was definitely the documentation. The second, is the API they expose which is close to top-notch. The features they provide are not huge in quantity, but are very well-thought-out.
However, we cannot ignore the fact that it's still in beta. Also, the authors identify it as "near-zero runtime" , but at +9 kB gzipped it's debatable.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 82.0 kB | 250 kB |
| vs. CSS Modules | +5.3 kB | +17 kB |
Page Size First Load JS
┌ ○ / 2.43 kB 75.2 kB
├ /_app 0 B 72.8 kB
├ ○ /404 194 B 73 kB
└ ○ /other 984 B 73.8 kB
+ First Load JS shared by all 72.8 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.ff82f0.js 6.93 kB
└ chunks/webpack.61f1b6.js 778 B
Probably the grandaddy around here, JSS is a very mature solution being the first of them, and still being maintained. The API is intuitive and very easy to use, great integration for React using hooks.
Version: 10.7 | Maintained by Oleg Isonen and others | Launched in 2014 | View Docs | ... back to Overview
✅ Styles/Component co-location
✅ Built-in Theming support
✅ Framework agnostic
✅ TypeScript support
✅ Context-aware code completion
No Atomic CSS
Styles definition method(s)
Styles nesting
Styles apply method(s)
classNamestyled component (available with additional plugin)css propStyles output
.css file extraction<style> tag injection react-jss package, which is used with React/Next.js, depends on jss-preset-default, which includes many plugins by default, so you don't need to manually add some of the plugins;react-jss uses className by default. There's also styled-jss that uses Styled Components approach, but it has no types, and couldn't make it work on top of react-jss ;injectSheet API (or we couldn't find it anywhere);The API is similar in many ways to React Native StyleSheets, while the hooks helper allows for easy dynamic styles definition. There are many plugins that can add a lot of features to the core functionality, but attention must be payed to the total bundle size, which is significant even with the bare minimum only.
Also, being the first CSS-in-JS solution built, it lacks many of the modern features that focuses on developer experience.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 94.9 kB | 293 kB |
| vs. CSS Modules | +18.2 kB | +60 kB |
Page Size First Load JS
┌ ○ / 2.45 kB 88 kB
├ /_app 0 B 85.6 kB
├ ○ /404 194 B 85.8 kB
└ ○ /other 992 B 86.6 kB
+ First Load JS shared by all 85.6 kB
├ chunks/framework.2191d1.js 42.4 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.5f0007.js 19.2 kB
└ chunks/webpack.9c89cc.js 956 B
A very light-weight solution, with a loads of features.
Version: 2.0 | Maintained by Cristian Bote | Launched in 2019 | View Docs | ... back to Overview
✅ Styles/Component co-location
✅ Built-in Theming support
✅ TypeScript support
✅ Context-aware code completion
✅ Framework agnostic
No Atomic CSS
Styles definition method(s)
Styles nesting
Styles apply method(s)
classNamestyled component ( see details below )css prop ( is supported, but requires a separate babel plugin )Styles output
.css file extraction<style> tag injection <style> tag with all the styles, and appends to it on update, and apparently it doesn't use insertRule() , not even in production builds, which might be an important performance drawback in large & highly dynamic UIs Looking at Goober you cannot ask yourself what kind of magic did Cristian Bote do to fit all the features inside this tiny library. It is really mind blowing. It is marketed as being "less than 1KB" , which is not entirely accurate, but still... it's the smallest library we've tested.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 77.8 kB | 237 kB |
| vs. CSS Modules | +1.1 kB | +4 kB |
Page Size First Load JS
┌ ○ / 2.77 kB 71.1 kB
├ /_app 0 B 68.3 kB
├ ○ /404 194 B 68.5 kB
└ ○ /other 2.39 kB 70.7 kB
+ First Load JS shared by all 68.3 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.5ee014.js 2.42 kB
└ chunks/webpack.61f1b6.js 778 B
A rather new library, having the huge Atlassian platform supporting and probably using it. Many existing features, even more in development, or planned for development.
Version: 0.6 | Maintained by Atlassian | Launched in 2020 | View Docs | ... back to Overview
✅ Styles/Component co-location
✅ TypeScript support
✅ Context-aware code completion
✅ Atomic CSS
Not Framework agnostic
No Built-in Theming support (at least at the moment, but it is planned)
Styles definition method(s)
Styles nesting
Styles apply method(s)
className (only supported with a custom ClassNames component)styled componentcss propStyles output
.css file extraction (currently under development, will be shipped in 2021)<style> tag injection css prop is seamless and trivial, not requiring any special setup (unlike Emotion) <head> during SSR - instead they are placed right before the element using them in the <body> , which could potentially provide slightly faster Paint metrics, such as FCP, or LCP, because the browser can start rendering the body faster and incrementally, not waiting for the entire block of styles to be parsedClassNames API, which enables us to apply styles as class name strings, is a bit convoluted and weird at first sight. Compiled is a very promising library. Considering that it offers both atomic CSS, and it plans to support static .css extraction, with excellent TypeScript support and style co-location, it would be quite unique (having only style9 as a direct competitor).
Also, we cannot ignore that is has Atlassian supporting its development, which puts a (slightly) bigger weight on the confidence level.
The total bundle overhead is pretty small, the runtime library being quite light-weight. With static .css file extraction, this could potentially become even smaller.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 80.2 kB | 242 kB |
| vs. CSS Modules | +3.5 kB | +9 kB |
Page Size First Load JS
┌ ○ / 2.11 kB 71.8 kB
├ /_app 0 B 66.5 kB
├ ○ /404 194 B 66.7 kB
└ ○ /other 888 B 70.6 kB
+ First Load JS shared by all 66.5 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.ebe095.js 576 B
├ chunks/webpack.ddd010.js 822 B
└ css/a92bf2d3acbab964f6ac.css 319 B
Linaria is all about static CSS extraction and avoiding any runtime overhead.
Version: 3.0 (beta) | Maintained by Callstack | Launched in 2018 | View Docs | ... back to Overview
✅ Styles/Component co-location
✅ TypeScript support
✅ Context-aware code completion
✅ Framework agnostic
✅ Built-in Theming support
No Atomic CSS
Styles definition method(s)
Styles nesting
Styles apply method(s)
classNamestyled componentcss propStyles output
.css file extraction<style> tag injection Linaria is highly inspired from Astroturf, combining various features from other libraries.
Version 3 is currently in Beta, not sure what the changelog is compared to v2. It's still in development by the React/Native geeks at Callstack.io , but we couldn't find which of the big players use it in production.
It seems to have a slightly larger overall page size ( 2.9 KB ), but we didn't investigate where does this come from. Also, there's an open question if this overhead is fixed or if it scales.
PS: thanks to Daniil Petrov for his PR with the Next.js integration
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 79.4 kB | 239 kB |
| vs. CSS Modules | +2.7 kB | +6 kB |
Page Size First Load JS
┌ ○ / 4.99 kB 71.5 kB
├ └ css/16f3e95ede28dcc048f2.css 423 B
├ /_app 0 B 66.5 kB
├ ○ /404 194 B 66.7 kB
└ ○ /other 3.59 kB 70.1 kB
└ css/3064299bff08067ec7dd.css 427 B
+ First Load JS shared by all 66.5 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.b2b078.js 23.1 kB
├ chunks/pages/_app.98e8c3.js 598 B
├ chunks/webpack.ddd010.js 822 B
└ css/7739287c04a618ea0c54.css 295 B
Modern solution with great TypeScript integration and no runtime overhead. It's pretty minimal in its features, straightforward and opinionated. Everything is processed at compile time, and it generates static CSS files. Successor of Treat, also be called "Treat v3", is developed and maintained by the same authors.
Version: 1.2 | Maintained by Seek OSS | Launched in 2021 | View Docs | ... back to Overview
✅ TypeScript support
✅ Built-in Theming support
✅ Context-aware code completion
✅ Framework agnostic
? Atomic CSS : can be achieved with Sprinkles
No Styles/Component co-location : styles must be placed in an external .css.ts file
Styles definition method(s)
Styles nesting
Styles apply method(s)
classNamestyled componentcss propStyles output
.css file extraction<style> tag injection & > span ), which might be seen as a downside, but it actually discourages bad-practices like specificity wars , which should be avoided when scaling CSS (however, this is impossible to be statically type-checked without pattern matching , so it will throw a runtime exception)variants based on predefined types, or inline styles for user-defined styles We felt a lot like using CSS Modules: we need an external file for styles, we place the styles on the elements using className , we handle dynamic styles with inline styles , etc. However, we don't write CSS, and the overall experience with TypeScript support is magnificent, because everything is typed, so we don't do any copy-paste . Error messages are very helpful in guiding us when we do something we're not supposed to do.
vanilla-extract is built with restrictions in mind, with a strong user-centric focus, balacing the developer experience with solid TypeScript support. It's also worth mentioning that Mark Dalgleish, co-author of CSS Modules, works at Seek and he's also a contributor.
The authors vision is to think of vanilla-extract as a low-level utility for building higher-level frameworks, which will probably happen in the future.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 76.7 kB | 231 kB |
| vs. CSS Modules | +0.0 kB | -2 kB |
Page Size First Load JS
┌ ○ / 2.09 kB 68.5 kB
├ └ css/37c023369f5e1762e423.css 370 B
├ /_app 0 B 66.4 kB
├ ○ /404 194 B 66.6 kB
└ ○ /other 611 B 67 kB
└ css/a56b9d05c6da35ff125f.css 386 B
+ First Load JS shared by all 66.4 kB
├ chunks/framework.895f06.js 42 kB
├ chunks/main.700159.js 23.1 kB
├ chunks/pages/_app.bfd136.js 565 B
├ chunks/webpack.61f1b6.js 778 B
└ css/23b89d9ef0ca05e4b917.css 286 B
We know there are a lot of other libraries out there, besides the ones covered above. We're only covered the ones that have support for React , support for SSR , an easy integration with Next.js , good documentation and a sense of ongoing support and maintenance . Please checkout our goals.
Treat was initially included in the analysis with v1.6, but removed for a few reasons:
The main difference between vanilla-extract and Treat is that the latter supports IE and legacy browsers as well.
Style9 is a new library, inspired by Facebook's own CSS-in-JS solution called stylex. Style9 is unique because it's the only open source library that supports both .css static extraction + atomic CSS, and/or styles co-location. It has TS support and easy to integrate with Next.js.
However, it has quite a few limitations (at least as of Feb 2021) that makes it practically unusable in a real production application that we would want to scale, both in code & team size:
Enum or POJO , only constant primitives are supported, which is a big deal breaker ;classNames lib, but not dynamically/computed/expression based;Some upsides:
As a conclusion, it wants to be a powerful solution with very interesting and unique set of features, but it's not mature yet. As far as we see, it's currently mostly designed towards more static solutions. Dynamic styling seems to be difficult to handle, at least for the moment.
Not an actual CSS-in-JS library, more like a replacement for traditional CSS styling. It uses atomic CSS classes (some of them having multiple properties) that we attach to html elements. We don't write CSS, instead we use a different DSL to specify styles, pseudo classes, media queries, etc.
The reason we didn't include it in our thorough review is because it doesn't fully meet our goals:
.ts files to include them in tailwind.config (cannot import any file, cannot require .ts )tailwind.config directly offers no type-safety when importing it, or using resolveConfigrounded , place-self/content , divide , ring )::after pseudo elements are trickySome upsides:
tailwind.configTailwind seems to be more than a styling tool , it also offers some out-of-the-box utils + a ready-made design system that you can use right away.
It's not a popular solution, the approach is similar to React Native StyleSheets way of styling components. Has built-in TypeScript support and a simple API.
I got it started with Next.js, but it feels fragile. The Glamor official example throws an error regarding rehydrate . When commenting it out, it works, but not sure what the consequences are.
Didn't manage to start it with Next.js + TypeScript. The official example uses version 3, while today we have version 6. The example doesn't work, because the API has changed.
The solution looked interesting, because it is supposed to be very light-weight.
Didn't manage to start it with Next.js + TypeScript. There was an official example that used an older version of Next.js, but the example if not there anymore.
The solution is not that popular, but it was the first to use .css extraction with collocated styles.
Looks promising, atomic css and light-weight. It has a working Next.js example, but we didn't consider it because it lacks any documentation.
It looks like a not so popular solution, which also lacks support for TypeScript. It looks like the maintainers work at Uber and they use it internally. It focused on generating unique atomic CSS classes, which could potentially deduplicate a lot of code.
The project was put in Maintenance Mode. They recommend other solutions.
The project was discontinued in favor of Emotion.
Each implementation sits on their own branch, so we can have a clear separation at built time.
# install dependencies
yarn
# for development
yarn dev
# for production
yarn build
yarn startTo get in touch, my DMs are open @pfeiffer_andrei.
Special thanks and appreciations go to everyone that helped putting this document together, and making it more accurate: