CSS-in-JS i Zero-Runtime Styling
Od styled-components i Emotion (runtime) do vanilla-extract, StyleX i Linaria (zero-runtime) — ewolucja CSS w React i Next.js.
6 podejść do stylowania w React
Tailwind, vanilla-extract, StyleX, CSS Modules, Linaria i Emotion — runtime overhead, TypeScript i React Server Components compatibility.
| Biblioteka | Typ | Runtime | TypeScript | RSC | Kiedy |
|---|---|---|---|---|---|
| Tailwind CSS v4 | Utility-first | Zero (build) | Dobry | Tak | Default 2024, utility classes, fast dev |
| vanilla-extract | Zero-runtime CSS-in-JS | Zero (build) | Natywny (strict) | Tak | Type-safe design system, TypeScript |
| StyleX | Zero-runtime CSS-in-JS | Zero (build) | Natywny | Tak | React+RN unified, Meta scale |
| CSS Modules | Scoped CSS | Zero | Plugin | Tak | Prostota, full CSS, zero deps |
| Linaria | Zero-runtime styled | Zero (babel extract) | Dobry | Tak | Migracja z styled-components |
| Emotion / styled-components | Runtime CSS-in-JS | Runtime (JS parse) | Dobry | Ograniczone | Legacy, nie nowe projekty |
Często zadawane pytania
Co to jest CSS-in-JS i jaka jest jego historia w React?
CSS-in-JS: pisanie CSS wewnątrz JavaScript. Rozwiązuje: global scope CSS. Dead code elimination. Colocated styles z komponentem. Dynamiczne style oparte na props. História: 2014 — Christopher Chedeau (Facebook) popularyzuje koncepcję. JSS — pierwsza biblioteka. 2016 — styled-components (Glen Maddern, Max Stoiber). 2017 — Emotion. 2018-2021 — dominacja styled-components i Emotion. 2022-2024 — zwrot ku zero-runtime. Styled-components: tagged template literals. const Button = styled.button styled.button - background: ${props => props.primary ? 'blue' : 'white'}; color: ${props => props.primary ? 'white' : 'blue'}; - (backtick notation). Button primary -> niebieski. ThemeProvider: motyw w kontekście. Dynmic styles przez props. Automatyczne CSS vendor prefixes. Emotion: podobne do styled-components, ale bardziej elastyczne. @emotion/styled — styled API. @emotion/css — klasowy API. css prop: div css={css-background: red-}. Wbudowany w wielu komponentach UI (Chakra, MUI). Performance: runtime CSS generation. Przy każdym renderze parses styles. Wstrzykuje style tags. Problem: Server-Side Rendering może być skomplikowany. Hydration mismatch. Bundle size: styled-components ~22KB, Emotion ~11KB. React 18 Concurrent Mode: styled-components i Emotion mają problemy. Dlaczego odchodzą od runtime CSS-in-JS: performance concerns. Server Components incompatibility. Zero-runtime era nastała.
vanilla-extract — zero-runtime CSS-in-JS dla TypeScript?
vanilla-extract: CSS-in-JS bez runtime overhead (Mark Dalgleish, Seek, 2021). Generuje statyczne CSS w czasie buildu. TypeScript-first. Zero runtime. Scoped styles. Theming. Instalacja: npm install @vanilla-extract/css. Vite plugin: @vanilla-extract/vite-plugin. Next.js: @vanilla-extract/next-plugin. Podstawy: style.css.ts (specjalny plik). import {style, createTheme, createVar} from '@vanilla-extract/css'. const button = style({backgroundColor: 'blue', padding: '8px 16px', borderRadius: '4px', ':hover': {backgroundColor: 'darkblue'}, '@media': {'(min-width: 768px)': {padding: '12px 24px'}}}). Eksportuj klasę, użyj w JSX: button className={button}. Theming: createThemeContract({color: {brand: null, text: null}}). createTheme(contract, {color: {brand: '#0070f3', text: '#333'}}). CSS Variables: createVar(). assignVars(). Recipes (warianty): import {recipe} from '@vanilla-extract/recipes'. const buttonRecipe = recipe({base: {...}, variants: {color: {primary: {...}, secondary: {...}}, size: {small: {...}, large: {...}}}}). buttonRecipe({color: 'primary', size: 'large'}). Sprinkles (@vanilla-extract/sprinkles): utility-first API na vanilla-extract. Definiuj atomic CSS. const sprinkles = createSprinkles(defineProperties({...})). Jak Tailwind ale type-safe. Dessert Stack: vanilla-extract + sprinkles — pełny design system. Wady: tylko build-time styles (nie dynamic props bezpośrednio). Obejście: CSS variables.
StyleX — Meta CSS-in-JS dla React i React Native?
StyleX: CSS-in-JS od Meta (Facebook, 2023). Używany w Facebook, Instagram, WhatsApp. Zero-runtime. TypeScript-first. Atomic CSS generation. Instalacja: @stylexjs/stylex + Babel plugin lub webpack plugin. import * as stylex from '@stylexjs/stylex'. Podstawy: const styles = stylex.create({root: {color: 'blue', padding: '8px'}, primary: {backgroundColor: vars.brandColor}}). stylex.props(styles.root, condition && styles.primary) -> {className, style}. Spread do JSX: div {...stylex.props(styles.root)}. Zmienne: const vars = stylex.defineVars({brandColor: {default: '#0070f3', '@media (prefers-color-scheme: dark)': '#60a5fa'}}). Theme tokens: const theme = stylex.createTheme(vars, {brandColor: '#ff0000'}). Wrap komponent z ThemeProvider (ale przez className). Atomic: każda property -> osobna klasa. background-color: blue -> dedykowana klasa. Deduplication — jedna klasa per property. Klasy mogą być mergowane bez konfliktów. Overrides: ostatnia property wins (bez specificity wars). StyleX vs Tailwind: StyleX — TypeScript, type-safe, colocation ze stylem. Tailwind — utility-first, shorter learning, HTML-based. StyleX vs vanilla-extract: StyleX — lepszy dla komponentów React Native (unified). vanilla-extract — lepsze theming, sprinkles. Dla React Native: StyleSheet.create() native. React Native StyleSheet jest bardzo podobny do StyleX. Unified API potencjalnie.
Linaria i Panda CSS — inne podejścia zero-runtime?
Linaria: zero-runtime CSS-in-JS (2017, Callstack). styled API jak styled-components. Babel plugin: ekstraktuje CSS w czasie buildu. const Button = styled.button styled.button - color: ${({primary}) => primary ? 'white' : 'black'}; - (backtick). Statyczne wartości -> CSS. Dynamiczne -> CSS variables. Linaria vs vanilla-extract: Linaria — styled-components migration łatwiejsza. vanilla-extract — TypeScript strict. Kaliber: @callstack/linaria, @linaria/react. Panda CSS: utility-first, type-safe, build-time (Segun Adebayo, 2023). Twórca Chakra UI. Jak Tailwind ale type-safe i theme-aware. css({display: 'flex', color: 'blue.500'}). Panda generuje utility classes. Design tokens: tokens.config.ts. Recipes: cva() (Class Variance Authority-inspired). Patterns: stack(), grid(), center(). Instalacja: npm install @pandacss/dev. panda init -> panda.config.ts. PostCSS plugin albo Vite plugin. Output: wygenerowane CSS utility classes. Stitches: type-safe, zero-runtime (podobne do styled-system). Zamrożony development (brak aktywnego maintenance). Mówi się o migracji do vanilla-extract. Linaria vs Emotion migration: API kompatybilny. Zmień import. Zbudowane zostaną statyczne klasy. Performance improvement. Która biblioteka w 2024: Tailwind — dominuje. vanilla-extract — utility (sprinkles) + componenty. StyleX — Facebook apps. Panda — Chakra ecosystem. Emotion/styled-components — legacy, nie nowe projekty.
CSS Modules i Tailwind CSS — czy potrzebujesz CSS-in-JS?
CSS Modules: lokalne scope CSS per component. Button.module.css: .button {background: blue}. import styles from './Button.module.css'. button className={styles.button}. Automatyczna unikalna nazwa klasy (hash). Obsługiwane natively w Next.js, Vite, CRA. TypeScript: typescript-plugin-css-modules. Zalety: zero runtime. Full CSS power. Łatwa migracja. Colocated z komponentem. Wady: brak type-safe props. CSS Variables dla dynamiki. Tailwind CSS v4 (2024): Oxide engine (Rust). CSS-first config (@theme directive). Input CSS: @import 'tailwindcss'. @theme {--color-brand: #0070f3}. Brak tailwind.config.js (opcjonalny). Szybszy build. CSS Modules + Tailwind: styles.button + className='mr-4 text-sm' — można łączyć. Jak wybrać w 2024: Tylko Tailwind — szybkie projekty, utility-first devs. CSS Modules — pełna kontrola CSS, zero runtime, prosty. Tailwind + CSS Modules — kombinacja dla złożonych projektów. vanilla-extract — TypeScript strict, design system. StyleX — React Native unification, FB-scale. Emotion/styled-components — legacy, maintenance mode. Tematyzacja: CSS Custom Properties (variables) — uniwersalne. Tailwind: var(--color-brand) w klasie lub @theme. CSS Modules: :root --color. vanilla-extract: createThemeContract(). Design System tips: tokens -> CSS variables. semantic naming (color-primary vs blue-500). dark mode: prefers-color-scheme + CSS variables. ThemeProvider (minimal Context) dla runtime switching.
Powiązane artykuły
Skontaktuj się z nami
Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.
Wyślij zapytanie
Telefon
+48 790 814 814
Pon-Pt: 9:00 - 18:00
adam@fotz.pl
Odpowiadamy w ciągu 24h
Adres
Plac Wolności 16
61-739 Poznań
Godziny pracy
Wolisz porozmawiać?
Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.
Zadzwoń teraz