Pilotze, wyobraz sobie dwa typy silnikow statku kosmicznego. Pierwszy oblicza trase lotu w locie -- zuzywa paliwo na biezaco (runtime CSS-in-JS jak styled-components). Drugi oblicza trase przed startem i zapisuje ja w komputerze pokladowym -- podczas lotu nie zuzywa dodatkowej energii (zero-runtime CSS-in-JS). W swiecie frontendu to roznica miedzy podejsciami runtime i zero-runtime do stylowania.
Styled-components i Emotion dzialaja tak: za kazdym razem gdy React renderuje komponent, biblioteka w runtime parsuje template literal, generuje unikalny hash klasy i wstrzykuje
<style> tag do DOM. To oznacza:1// Styled-components -- runtime
2const Card = styled.div`
3 background: ${({ theme }) => theme.colors.surface};
4 padding: ${({ theme }) => theme.spacing.lg};
5 border-radius: 12px;
6`;
7// Za kazdym renderem: parsuj template -> generuj hash -> wstrzyknij <style>Problemy:
Zero-runtime CSS-in-JS to podejscie, gdzie style sa generowane w czasie kompilacji (build time) -- wynikowy kod nie zawiera zadnego JavaScript do obslugi stylow. Piszesz style w TypeScript, a bundler zamienia je na zwykly plik CSS.
Vanilla-extract to najpopularniejsza biblioteka zero-runtime. Style definiujesz w plikach
.css.ts:1// styles.css.ts -- plik ze stylami
2import { style } from '@vanilla-extract/css';
3
4export const card = style({
5 background: '#1a1a4e',
6 border: '2px solid #3949ab',
7 borderRadius: '12px',
8 padding: '20px',
9 transition: 'all 0.3s ease',
10 ':hover': {
11 borderColor: '#7c4dff',
12 transform: 'translateY(-2px)',
13 },
14});
15
16export const heading = style({
17 color: '#7c4dff',
18 fontSize: '20px',
19 marginBottom: '16px',
20});W komponencie React importujesz klasy jak zwykly string:
1// Component.tsx
2import { card, heading } from './styles.css.ts';
3
4function MissionCard({ title, children }) {
5 return (
6 <div className={card}>
7 <h3 className={heading}>{title}</h3>
8 {children}
9 </div>
10 );
11}Po kompilacji
card i heading to zwykle stringi z nazwami klas CSS -- zero JavaScript w runtime.Vanilla-extract oferuje
sprinkles -- typowany odpowiednik klas uzytkowych (jak Tailwind, ale z pelnym typowaniem TypeScript):1// sprinkles.css.ts
2import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
3
4const responsiveProperties = defineProperties({
5 conditions: {
6 mobile: {},
7 tablet: { '@media': 'screen and (min-width: 768px)' },
8 desktop: { '@media': 'screen and (min-width: 1024px)' },
9 },
10 defaultCondition: 'mobile',
11 properties: {
12 display: ['none', 'flex', 'block', 'grid'],
13 padding: { sm: '8px', md: '16px', lg: '24px' },
14 gap: { sm: '8px', md: '16px', lg: '24px' },
15 },
16});
17
18export const sprinkles = createSprinkles(responsiveProperties);Uzycie:
1<div className={sprinkles({
2 display: { mobile: 'block', tablet: 'grid' },
3 padding: { mobile: 'sm', desktop: 'lg' },
4 gap: 'md',
5})}>Wszystko jest typowane -- TypeScript podpowie dostepne wartosci i zlapie literowki.
Linaria oferuje skladnie identyczna jak styled-components, ale kompiluje style w build time:
1import { styled } from '@linaria/react';
2
3const Card = styled.div`
4 background: #1a1a4e;
5 border: 2px solid #3949ab;
6 border-radius: 12px;
7 padding: 20px;
8 &:hover {
9 border-color: #7c4dff;
10 }
11`;Wyglada identycznie jak styled-components, ale po kompilacji
Card renderuje <div className="hash123"> -- bez runtime JS.Panda CSS to najnowszy gracz -- laczy podejscie utility-first (jak Tailwind) z typowaniem i zero-runtime:
1import { css } from '../styled-system/css';
2
3function MissionPanel() {
4 return (
5 <div className={css({
6 bg: 'surface',
7 p: '6',
8 borderRadius: 'lg',
9 border: '2px solid',
10 borderColor: 'border',
11 _hover: { borderColor: 'primary' },
12 })}>
13 Panel misji
14 </div>
15 );
16}Panda generuje CSS atomowe (jak Tailwind) w build time -- kazda wlasciwosc to osobna klasa, co minimalizuje duplikacje.
| Cecha | styled-components | Vanilla-extract | Linaria | Panda CSS | |-------|------------------|-----------------|---------|-----------| | Runtime JS | Tak (~12 KB) | Nie | Nie | Nie | | Dynamiczne style | Pelne (props) | Ograniczone (recipes) | Ograniczone | Ograniczone | | TypeScript | Dobre | Natywne | Dobre | Natywne | | SSR | Konfiguracja | Bezproblemowy | Bezproblemowy | Bezproblemowy | | DX (doswiadczenie) | Swietne | Dobre | Swietne | Swietne |