Dokumen ini berisi analisis mendalam dari semua solusi CSS-in-JS saat ini, yang mendukung rendering sisi server dan naskah .
Referensi dasar yang akan kami gunakan untuk perbandingan adalah pendekatan modul CSS .
Kami menggunakan Next.js sebagai kerangka kerja SSR untuk membangun sumber daya.
Aspek penting terakhir adalah ketegangan tipe dengan dukungan TypePript lengkap.
? Pembaruan Terakhir: Agustus 2021
? Untuk mendapatkan ikhtisar yang lebih pendek, Anda dapat memeriksa artikel tentang trik CSS :
https://css-tricks.com/a-horough-analysis-of-css-in-js/
? Jika Anda lebih suka video, Anda dapat memeriksa ceramah saya dari NgPartyCZ :
https://www.youtube.com/watch?v=c7uwghrax9a
Silakan periksa tujuan & penafian kami sebelum melompat ke kesimpulan.
Modul Bahasa CSS dan CSS memiliki beberapa keterbatasan, terutama jika kita ingin memiliki kode jenis-aman. Beberapa keterbatasan ini memiliki solusi alteratif, yang lain hanya menjengkelkan atau kurang dari ideal :
Gaya tidak dapat ditempatkan bersama dengan komponen
Ini bisa membuat frustrasi ketika menulis banyak komponen kecil, tetapi ini bukan pemecah kesepakatan. Namun, pengalaman bergerak bolak-balik antara file component.js dan file component.css , mencari nama kelas yang diberikan, dan tidak dapat dengan mudah "pergi ke definisi gaya" , adalah kelemahan produktivitas yang penting.
Styling Pseudos dan Media Queries membutuhkan duplikasi pemilih
Fakta yang membuat frustrasi lainnya adalah kebutuhan untuk menduplikasi kelas CSS kami ketika mendefinisikan kelas dan elemen semu , atau kueri media . Kami dapat mengatasi keterbatasan ini menggunakan preprosesor CSS seperti Sass, Less atau Stylus , yang mendukung & pemilih induk, memungkinkan gaya kontekstual .
. button {}
/* duplicated selector declaration for pseudo classes/elements */
. button : hover {}
. button :: after {}
@media ( min-width : 640 px ) {
/* duplicated selector declaration inside media queries */
. button {}
} Penggunaan Gaya terputus dari definisi
Kami tidak mendapatkan Intellisense dengan modul CSS, tentang kelas CSS apa yang didefinisikan dalam file component.css , menjadikan copy-paste alat yang diperlukan, menurunkan DX. Itu juga membuat refactoring menjadi sangat rumit , karena kurangnya keamanan.
Menggunakan token desain tipe-aman di CSS adalah non-sepele
Token desain apa pun yang didefinisikan dalam JS/TS (untuk mendapatkan manfaat dari jenis-keamanan) tidak dapat langsung digunakan dalam CSS.
Setidaknya ada 2 solusi untuk masalah ini, tak satu pun dari mereka yang elegan:
.module.css ..css .Ada tujuan khusus yang kami cari dengan analisis ini:
Menjadi lebih spesifik, kami ingin mengalami penggunaan berbagai solusi CSS-in-JS mengenai:
props komponen (alias. Varian komponen), atau dari input penggunaAnalisis ini dimaksudkan untuk objektif dan tidak teropini :
? Apa yang tidak akan Anda temukan di sini?
? Apa yang akan Anda temukan di sini?
Perpustakaan tidak disajikan dalam urutan tertentu. Jika Anda tertarik dengan riwayat singkat CSS-in-Js , Anda harus memeriksa masa lalu, sekarang, dan masa depan CSS-in-Js Talk Wawasan oleh Max Stoiber.
| 1. CO -LOCKASI | 2. DX | 3. tag` ` | 4. { } | 5. TS | 6. & CTX | 7. bersarang | 8. Tema | 9. .css | 10. <style> | 11. Atom | 12. className | 13. <Styled /> | 14. css Prop | 15. Agnostik | 16. Delta Ukuran Halaman | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Modul CSS | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | |||||||||
| JSX yang ditata | ✅ | ? | ✅ | ? | ✅ | ✅ | ✅ | +2.8 kB / +12.0 kB | ||||||||
| Komponen gaya | ✅ | ? | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +13.4 kB / +39.0 kB | ||||
| Emosi | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +6.5 kB / +20.0 kB | ||
| Typestyle | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | ✅ | ✅ | +2.1 kB / +8.0 kB | |||||
| Fela | ✅ | ? | ? | ✅ | ? | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +11.9 kB / +43.0 kB | |||
| Jahitan | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | +5.3 kB / +17.0 kB | |||
| JSS | ✅ | ✅ | ? | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | +18.2 kB / +60.0 kB | |||
| Goober | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | +1.1 kB / +4.0 kB | ||
| Disusun | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | ✅ | +3.5 kB / +9.0 kB | |||
| Linaria | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +2.7 kB / +6.0 kB | ||||
| vanilla-ekstrak | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ? | ✅ | ✅ | +0.0 kB / -2.0 kB |
Kemampuan untuk mendefinisikan gaya dalam file yang sama dengan komponen. Perhatikan bahwa kami juga dapat mengekstrak gaya ke dalam file terpisah dan mengimpornya, jika kami lebih suka.
⬆️ untuk ikhtisar
Mengacu pada pengalaman pengembang yang mencakup 2 aspek utama:
⬆️ untuk ikhtisar
tag` ` (Tagged Template)Dukungan untuk mendefinisikan gaya sebagai string , menggunakan Templat ES Tagged:
kebab-case untuk nama properti, seperti halnya sintaks CSS biasa;string biasa;⬆️ untuk ikhtisar
{ } (Gaya objek)Dukungan untuk mendefinisikan gaya sebagai objek , menggunakan objek JavaScript biasa:
camelCase untuk nama properti, seperti yang akan kami lakukan di React Native;⬆️ untuk ikhtisar
Dukungan TypeScript, baik bawaan, atau melalui paket @types , yang harus mencakup:
Props Generik, jika berlaku (dapatkan jenis akses yang aman ke jenis proponik komponen saat mendefinisikan gaya dinamis);⬆️ untuk ikhtisar
& CTX (gaya kontekstual)Dukungan untuk gaya kontekstual yang memungkinkan kita untuk dengan mudah mendefinisikan kelas & elemen semu dan kueri media tanpa perlu mengulangi pemilih, sebagaimana diperlukan dalam CSS biasa:
& Parent;⬆️ untuk ikhtisar
Dukungan untuk pemilih bersarang sewenang -wenang :
⬆️ untuk ikhtisar
Dukungan bawaan untuk bertema atau mengelola token untuk sistem desain.
Kami belum menguji fitur ini , jadi kami hanya mencatat perpustakaan mana yang mengekspresikan dukungan mereka di dokumen mereka.
⬆️ untuk ikhtisar
.css (ekstraksi CSS statis) Gaya yang ditentukan diekstraksi sebagai file .css statis:
⬆️ untuk ikhtisar
<style> Gaya yang ditentukan disuntikkan di dalam tag <style> di <head> dokumen:
⬆️ untuk ikhtisar
Kemampuan untuk menghasilkan kelas CSS atom , sehingga meningkatkan penggunaan kembali gaya, dan mengurangi duplikasi:
⬆️ untuk ikhtisar
className API perpustakaan mengembalikan string yang harus kami tambahkan ke komponen atau elemen kami;
⬆️ untuk ikhtisar
<Styled /> API membuat komponen pembungkus (atau Styled ) yang mencakup className yang dihasilkan:
StyledButton atau StyledList alih -alih konstanta seperti button_styles atau list_styles , jadi tentang penamaan itu hampir sama;⬆️ untuk ikhtisar
css Prop Mengizinkan gaya yang lewat menggunakan prop css khusus, serupa bagaimana kami akan mendefinisikan gaya inline, tetapi perpustakaan menghasilkan nama kelas CSS yang unik di belakang layar:
⬆️ untuk ikhtisar
Memungkinkan penggunaan tanpa, atau dengan kerangka kerja apa pun. Beberapa perpustakaan dibangun khusus hanya untuk bereaksi.
Catatan : Beberapa perpustakaan seperti jahitan atau dokumen emosi hanya bereaksi penggunaan, meskipun mereka memiliki inti yang kerangka kerja agnostik.
⬆️ untuk ikhtisar
Perbedaan ukuran halaman total dalam KB (ditransfer Gzipped & Minified / Uncompressy & Minified) dibandingkan dengan modul CSS , untuk seluruh halaman produksi indeks menggunakan Next.js:
Catatan: Semua bangunan dilakukan dengan Next.js 11.1.0 dan nilainya diambil dari tab Jaringan Chrome Devtools, ditransfer melalui jaringan vs sumber daya.
⬆️ untuk ikhtisar
Pengamatan berikut berlaku untuk semua solusi (dengan pengecualian kecil).
Komponen yang hanya digunakan dalam rute tertentu hanya akan dibundel untuk rute itu. Ini adalah sesuatu yang dilakukan oleh Next.js.
Semua solusi menawarkan cara untuk mendefinisikan gaya global, beberapa dengan API khusus.
Semua solusi menawarkan dukungan rendering sisi server dan mudah diintegrasikan dengan Next.js.
Semua solusi secara otomatis menambahkan awalan spesifik vendor di luar kotak.
Semua solusi menghasilkan nama kelas yang unik, seperti yang dilakukan modul CSS. Algoritma yang digunakan untuk menghasilkan nama -nama ini sangat bervariasi antara perpustakaan:
.heading STYLE DARI KOMPONEN Card AKAN SELALU memiliki hash .Card_heading_h7Ys5 );.heading-0-2-1 , .input-0-2-2 ), atau huruf alfabet ( a, b, c, ... aa, ab, ac , dll), membuat pendekatan ini lebih berkinerja, tetapi menghasilkan nama kelas yang tidak diproten (tidak dapat mengetahui apakah ini memiliki potensi tunduk atau tidak); Tidak ada solusi yang menghasilkan gaya inline, yang merupakan pendekatan yang lebih tua, digunakan oleh Radium & Glamor. Pendekatan ini kurang kinerja daripada kelas CSS, dan tidak disarankan sebagai metode utama untuk mendefinisikan gaya. Ini juga menyiratkan menggunakan penangan acara JS untuk memicu kelas semu, karena gaya inline tidak mendukungnya. Rupanya, semua solusi modern saat ini pindah dari pendekatan ini.
Semua solusi mendukung sebagian besar properti CSS yang Anda perlukan: kelas & elemen semu , kueri media dan kerangka kunci adalah yang telah kami uji.
Sebagian besar solusi memasarkan diri mereka sebagai mampu "mengekstraksi CSS kritis" selama SSR. Harap dicatat bahwa ini tidak merujuk pada ekstraksi CSS kritis di atas, seperti yang kami pikirkan pada awalnya.
Apa yang sebenarnya mereka lakukan:
Dengan 100% CSS statis, sebenarnya tidak akan ada manfaatnya. Dengan halaman dinamis yang membuat sangat sedikit elemen di server, dan sebagian besar komponen diterjemahkan secara dinamis pada klien, manfaatnya meningkat.
Pengecualian : Perpustakaan yang menggunakan ekstraksi CSS statis.
Memahami bagaimana fitur -fitur ini memengaruhi vital web inti dan metrik kinerja secara umum adalah faktor yang sangat penting untuk dipertimbangkan, dan cara gaya dikirimkan ke klien mungkin memiliki dampak terbesar, jadi mari kita analisis ini secara rinci.
Juga, ada 2 skenario berbeda yang perlu kita pertimbangkan:
.js , .css , media, dll); .css Solusi yang menghasilkan file statis .css , yang biasanya Anda sertakan sebagai tag <link> di <head> halaman Anda, pada dasarnya adalah sumber daya pemblokiran. Ini sangat mempengaruhi FCP , LCP, dan metrik lainnya yang mengikuti.
? Cache kosong
Jika pengguna memiliki cache kosong, hal -hal berikut perlu terjadi, berdampak negatif FCP dan LCP :
<body> , bahkan jika seluruh HTML sudah dimuat, dan bahkan mungkin diurai dengan penuh semangat, dan beberapa sumber daya sudah diambil sebelumnya; Memang benar bahwa Anda dapat mengambil dalam sumber daya <head> paralel lainnya (file .css atau .js tambahan), tetapi ini umumnya merupakan praktik yang buruk;
? Cache penuh
Namun, pada kunjungan berikutnya, seluruh sumber daya .css akan di -cache, sehingga FCP dan LCP akan terkena dampak positif.
Poin -poin penting
Solusi ini tampaknya lebih cocok saat:
.css umum yang dapat di -cache saat mengunjungi halaman lain;<style> tag styles yang disuntikkan Selama SSR , Styles akan ditambahkan sebagai tag <style> di <head> halaman. Perlu diingat bahwa ini biasanya tidak termasuk semua gaya yang diperlukan untuk halaman, karena sebagian besar perpustakaan melakukan ekstraksi CSS yang kritis, sehingga styles ini biasanya harus lebih kecil dari seluruh file statis .css yang dibahas sebelumnya.
? Cache kosong
Karena kami mengirimkan lebih sedikit byte CSS, dan mereka diinline di dalam file .html , ini akan menghasilkan FCP dan LCP yang lebih cepat:
.css , sehingga browser tidak diblokir;.js lainnya ke akhir dokumen, <head> tidak akan melakukan permintaan apa pun, jadi rendering akan terjadi sangat cepat;.css statis:.js bersama dengan komponen, selama hidrasi (ini termasuk semua CSS kritis yang sudah dikirimkan di dalam tag <style> lainnya); ? Cache penuh
Ketika cache pengguna penuh, file .js tambahan tidak akan memerlukan pengambilan, karena sudah di -cache.
Namun, jika halaman tersebut ssred , CSS kritis yang dilengkapi dengan tag <style> dokumen akan diunduh lagi, kecuali kami berurusan dengan HTML statis yang dapat di -cache juga, atau kami berurusan dengan caching HTML pada infrastruktur kami.
Tetapi, secara default, kami akan mengirimkan byte tambahan pada setiap halaman permintaan http, terlepas dari apakah itu di -cache atau tidak.
Poin -poin penting
Solusi ini tampaknya lebih cocok saat:
Sebagian besar solusi mengatakan mereka menghapus kode/gaya yang tidak digunakan . Ini hanya setengah benar .
Kode yang tidak digunakan memang lebih sulit untuk terakumulasi, terutama jika Anda membandingkannya dengan file .css yang biasa seperti yang kami gunakan untuk menulis satu dekade yang lalu . Tetapi jika dibandingkan dengan modul CSS, perbedaannya tidak sebesar itu. Solusi apa pun yang menawarkan opsi untuk mendefinisikan pemilih sewenang -wenang atau gaya bersarang akan menggabungkannya, terlepas dari apakah mereka digunakan atau tidak di dalam komponen kami. Kami telah berhasil mengirimkan gaya SSR yang tidak digunakan dengan semua solusi yang diuji.
Penghapusan kode True & Full yang tidak digunakan sulit diimplementasikan, karena sintaks CSS tidak diperiksa tipe, atau secara statis dapat dianalisis. Juga, sifat dinamis komponen membuatnya praktis tidak mungkin dalam skenario tertentu, terutama ketika markup diterjemahkan secara dinamis:
& span : Elemen Keturunan;&:nth-child() : pemilih semu tertentu;& .bg-${color} : selektor dinamis;.parent & : Parent Selectors;Pada dasarnya, yang kita dapatkan adalah penghapusan kode ketika kita menghapus komponen, atau kita tidak mengimpornya lagi. Itu perilaku implisit, karena gaya adalah ketergantungan langsung dari komponen. Saat komponen hilang, begitu pula gayanya.
Ada 2 metode untuk menyuntikkan CSS ke dalam DOM & memperbaruinya dari JavaScript:
<style> Pendekatan ini menyiratkan penambahan satu atau lebih <style> tag (s) di dom (baik di <head> atau di suatu tempat di <body> ), menggunakan .AppendChild () untuk menambahkan <style> node, selain tag <textcontent, .innerHtML untuk memperbarui tag <style> s).
<style> dan memperbarui seluruh kontennya, bisa lambat untuk memperbarui seluruh DOM ketika kami benar -benar mengubah hanya satu set kecil aturan CSS;DEVELOPMENT , karena memberikan pengalaman debugging yang lebih baik;PRODUCTION juga; CSSStyleSheet API Pertama kali digunakan oleh JSS , metode ini menggunakan CSSStyleSheet.insertRule() untuk menyuntikkan aturan CSS langsung ke CSSOM .
<style> kosong;<style> ;$0 di Chrome DevTools (atau dapatkan referensi untuk itu dengan cara lain, menggunakan DOM API);.sheet.cssRules pada tag <style> untuk melihat array aturan CSS yang dikandungnya;PRODUCTION ;DEVELOPMENT juga; Jika komponen yang sama diimpor oleh 2 rute yang berbeda, itu akan dikirim dua kali ke klien. Ini tentunya merupakan batasan sistem Bundler/Build, dalam kasus kami Next.js, dan tidak terkait dengan solusi CSS-in-Js .
Di Next.js, pemisahan kode bekerja di tingkat rute, menggabungkan semua komponen yang diperlukan untuk rute tertentu, tetapi menurut blog resmi dan web mereka. Jika komponen digunakan di lebih dari 50% halaman, itu harus dimasukkan dalam bundel commons . Namun, dalam contoh kami, kami memiliki 2 halaman, masing -masing mengimpor komponen Button , dan itu termasuk dalam setiap bundel halaman, bukan di bundel commons . Karena kode yang diperlukan untuk penataan dibundel dengan komponen, batasan ini akan berdampak pada gaya juga, jadi ada baiknya mengingat hal ini.
Ini adalah pendekatan yang mapan, matang, dan solid. Tanpa ragu, ini merupakan peningkatan besar atas BEM, SMACCS, OOCS, atau metodologi CSS yang dapat diskalakan lainnya untuk menyusun dan mengatur CSS kami, terutama dalam aplikasi berbasis komponen.
Diluncurkan pada 2015 | Kembali ke ikhtisar
✅ Penyelesaian Kode Konteks-Sehat
✅ Kerangka kerja agnostik
Tidak ada gaya co-location/komponen
Tidak ada dukungan naskah
Tidak ada CSS atom
Tidak ada dukungan tema
Metode Definisi Gaya
Gaya bersarang
Metode gaya berlaku
classNamestyledcss CSSOutput gaya
.css<style> injeksi tagIni adalah garis dasar yang akan kami pertimbangkan ketika membandingkan semua solusi CSS-in-JS berikut. Periksa motivasi untuk lebih memahami keterbatasan pendekatan ini yang kami coba isi.
| Ditransfer / gzip | Tidak terkompresi | |
|---|---|---|
| Ukuran halaman indeks | 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
Solusi yang sangat sederhana, tidak memiliki situs web khusus untuk dokumentasi, semuanya ada di GitHub. Ini tidak populer, tetapi ini adalah solusi bawaan di Next.js.
Versi: 4.0 | Dikelola oleh Vercel | Diluncurkan pada 2017 | Lihat Dokumen | ... kembali ke ikhtisar
✅ Lokasi gaya/komponen
? Konteks-Sehat Kode Penyelesaian : Untuk Mendapatkan Penyupu Sintaks & Penyelesaian Kode, diperlukan ekstensi editor
? Dukungan TypeScript : @types dapat diinstal tambahan, tetapi API terlalu minim untuk memerlukan TS
Tidak ada CSS atom
Tidak ada dukungan tema
Bukan kerangka kerja agnostik
Metode Definisi Gaya
Gaya bersarang
Metode gaya berlaku
classNamestyledcss CSSOutput gaya
.css<style> Tag Injection elements HTML juga, dan itu menghasilkan nama kelas yang unik untuk mereka (tidak yakin apakah itu praktik yang baik, meskipun) Secara keseluruhan, kami merasa ingin menulis CSS biasa, dengan manfaat tambahan untuk dapat mendefinisikan gaya bersama dengan komponen, jadi kami tidak memerlukan file .css tambahan . Memang, ini adalah filosofi perpustakaan: mendukung sintaks CSS di dalam file komponen. Kita dapat menggunakan konstanta fungsi JS/TS dengan interpolasi string. Bekerja dengan gaya dinamis cukup mudah karena pada akhirnya JavaScript pada akhirnya. Kami mendapatkan semua manfaat ini dengan harga yang sangat rendah, dengan overhead bundel yang cukup kecil .
Kelemahan adalah pengalaman keseluruhan dari menulis CSS biasa. Tanpa mendukung kelas/elemen semu dan permintaan media menjadi sangat rumit untuk dikelola.
| Ditransfer / gzip | Tidak terkompresi | |
|---|---|---|
| Ukuran halaman indeks | 79,5 kb | 245 kb |
| vs. modul 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
Pasti salah satu solusi paling populer dan dewasa, dengan dokumentasi yang baik. Ini menggunakan templat yang ditandai untuk mendefinisikan gaya secara default, tetapi dapat menggunakan objek juga. Ini juga mempopulerkan pendekatan komponen styled , yang menciptakan komponen baru bersama dengan gaya yang ditentukan.
Versi: 5.3 | Dipelihara oleh Max Stoiber & Lainnya | Diluncurkan pada 2016 | Lihat Dokumen | ... kembali ke ikhtisar
✅ Lokasi gaya/komponen
✅ dukungan naskah : @types harus diinstal tambahan, melalui pasti
✅ Dukungan tema bawaan
✅ Kerangka kerja agnostik
? Penyelesaian Kode Konteks-Awari : Membutuhkan Ekstensi/Plugin Editor
Tidak ada CSS atom
Metode Definisi Gaya
Gaya bersarang
Metode gaya berlaku
classNamestyledcss CSSOutput gaya
.css<style> Tag Injection Props , dll) Styled Components menawarkan pendekatan baru untuk komponen gaya menggunakan metode styled yang menciptakan komponen baru termasuk gaya yang ditentukan. Kami tidak merasa ingin menulis CSS, jadi berasal dari modul CSS kami harus belajar cara baru yang lebih program, untuk mendefinisikan gaya. Karena memungkinkan sintaks string dan object , ini adalah solusi yang cukup fleksibil baik untuk memigrasi gaya kami yang ada, dan untuk memulai proyek dari awal. Juga, pengelola melakukan pekerjaan yang cukup baik untuk mengikuti sebagian besar inovasi di bidang ini.
Namun sebelum mengadopsinya, kita harus sadar bahwa itu datang dengan biaya tertentu untuk ukuran bundel kita.
| Ditransfer / gzip | Tidak terkompresi | |
|---|---|---|
| Ukuran halaman indeks | 90.1 kb | 272 kb |
| vs. modul 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
Mungkin solusi yang paling komprehensif, lengkap dan sofis. Dokumentasi terperinci, sepenuhnya dibangun dengan naskah, terlihat sangat matang, kaya akan fitur dan dipelihara dengan baik.
Versi: 11.4 | Dipelihara oleh Mitchell Hamilton & Lainnya | Diluncurkan pada 2017 | Lihat Dokumen | ... kembali ke ikhtisar
✅ Lokasi gaya/komponen
✅ Dukungan naskah
✅ Dukungan tema bawaan
✅ Penyelesaian Kode Konteks-Awari : Untuk Menggunakan Pendekatan Komponen styled , Plugin Editor Tambahan Diperlukan
✅ Kerangka kerja agnostik
Tidak ada CSS atom
Metode Definisi Gaya
Gaya bersarang
Metode gaya berlaku
className (menggunakan @emosi/CSS)styledcss CSSOutput gaya
.css<style> Tag Injection css menawarkan ergonomi yang hebat selama pengembangan, namun tampaknya merupakan pendekatan yang lebih baru, berdasarkan reaksi 17 transformasi jsx baru, dan mengkonfigurasinya tidak sepele, berbeda pada pengaturan Anda, dan menyiratkan beberapa boilerplate (yang seharusnya segera berubah dan menjadi lebih mudah)) styled akan menambahkan 3 kB ke bundel kami, karena diimpor dari paket terpisahstyled css ) Emosi secara keseluruhan terlihat menjadi pendekatan yang sangat solid dan fleksibel. Pendekatan novel css Prop menawarkan ergonomi yang hebat bagi pengembang. Bekerja dengan gaya dan naskah dinamis cukup mudah dan intuitif. Mendukung kedua strings dan objects saat mendefinisikan gaya, itu dapat dengan mudah digunakan baik saat bermigrasi dari CSS biasa, atau mulai dari awal. The bundle overhead is not negligible, but definitely much smaller than other solutions, especially if you consider the rich set of features that it offers.
It seems it doesn't have a dedicated focus on performance, but more on Developer eXperience. It looks like a perfect "well-rounded" solution.
| Transferred / gzipped | Uncompressed | |
|---|---|---|
| Index page size | 83.2 kB | 253 kB |
| vs. CSS Modules | +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
Minimal library, focused only on type-checking. It is framework agnostic, that's why it doesn't have a special API for handling dynamic styles. 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: