Zum Inhalt springen

CSS-in-JS

Bei CSS-in-JS schreibst du Styles direkt in JavaScript — keine separaten CSS-Dateien, keine manuellen Klassennamen. Die bekannteste Bibliothek dafür ist Emotion. Sie besteht aus zwei Paketen, die jeweils eine eigene Coding-Variante einführen:

  • @emotion/react — das Kernpaket. Ermöglicht den css-Prop, mit dem du Styles direkt auf JSX-Elemente schreibst.
  • @emotion/styled — ein Zusatzpaket, das die styled-API bereitstellt. Die Syntax ist von styled-components übernommen: Du erstellst neue Komponenten, die ihre Styles bereits eingebaut haben.
Terminal-Fenster
npm install @emotion/react @emotion/styled

Damit der css-Prop funktioniert, muss Vite wissen, wie es JSX transformieren soll. Dazu passt du die Vite-Konfiguration an:

vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
jsxImportSource: '@emotion/react',
}),
],
});

Die Einstellung jsxImportSource: '@emotion/react' sorgt dafür, dass JSX-Elemente den css-Prop unterstützen.

Der css-Prop akzeptiert Styles, die mit der css-Funktion erzeugt werden. Diese Funktion unterstützt zwei Schreibweisen:

Tagged Template Literal — CSS-Syntax wie gewohnt:

const headerCss = css`
padding: 16px 20px;
border-bottom: 1px solid #e5e7eb;
background-color: #f9fafb;
`;

Objekt-Syntax — CSS als JavaScript-Objekt (Properties in camelCase):

const headingCss = css({
margin: 0,
fontSize: '18px',
});

Beide Varianten sind gleichwertig — verwende die, die dir besser gefällt. Hier CardTitle mit beiden:

import { css } from '@emotion/react';
const headerCss = css`
padding: 16px 20px;
border-bottom: 1px solid #e5e7eb;
background-color: #f9fafb;
`;
const headingCss = css({
margin: 0,
fontSize: '18px',
});
function CardTitle({ children }) {
return (
<header css={headerCss}>
<h2 css={headingCss}>{children}</h2>
</header>
);
}
export default CardTitle;

styled erstellt eine neue Komponente mit eingebauten Styles:

import styled from '@emotion/styled';
const StyledCard = styled.article`
border: 1px solid #e5e7eb;
border-radius: 8px;
overflow: hidden;
`;
function Card({ children }) {
return <StyledCard>{children}</StyledCard>;
}
export default Card;
import styled from '@emotion/styled';
const StyledButton = styled.button`
padding: 8px 16px;
border: 1px solid #d1d5db;
border-radius: 6px;
background-color: ${({ variant }) =>
variant === 'primary' ? '#2563eb' : '#ffffff'};
color: ${({ variant }) =>
variant === 'primary' ? '#ffffff' : '#374151'};
border-color: ${({ variant }) =>
variant === 'primary' ? '#2563eb' : '#d1d5db'};
font-size: 14px;
cursor: pointer;
&:hover {
background-color: ${({ variant }) =>
variant === 'primary' ? '#1d4ed8' : '#f3f4f6'};
}
`;
function Button({ variant = "default", children }) {
return (
<StyledButton variant={variant}>{children}</StyledButton>
);
}
export default Button;

Beachte, wie der variant-Prop direkt in den Styles verwendet wird. Kein manuelles Zusammensetzen von Klassennamen — die Logik lebt dort, wo die Styles definiert sind.

import styled from '@emotion/styled';
const StyledCardContent = styled.div`
padding: 20px;
`;
function CardContent({ children }) {
return <StyledCardContent>{children}</StyledCardContent>;
}
export default CardContent;
import styled from '@emotion/styled';
import Card from "./Card";
import CardTitle from "./CardTitle";
import CardContent from "./CardContent";
import Button from "./Button";
const Layout = styled.div`
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: system-ui, sans-serif;
`;
const Header = styled.header`
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 24px;
h1 {
margin: 0;
font-size: 24px;
}
`;
const Actions = styled.div`
display: flex;
gap: 8px;
margin-top: 16px;
`;
function App() {
return (
<Layout>
<Header>
<img
src="https://react.dev/images/brand/logo_light.svg"
alt="React Logo"
width="40"
height="40"
/>
<h1>CSS mit React</h1>
</Header>
<main>
<Card>
<CardTitle>Willkommen</CardTitle>
<CardContent>
<p>
Diese kleine App zeigt, wie du React-Komponenten mit
verschiedenen CSS-Ansätzen stylen kannst. Die Struktur
bleibt immer gleich — nur das Styling ändert sich.
</p>
<Actions>
<Button>Zurück</Button>
<Button variant="primary">Weiter</Button>
</Actions>
</CardContent>
</Card>
</main>
</Layout>
);
}
export default App;
VorteileNachteile
Volle JavaScript-Power in StylesRuntime-Overhead — Styles werden zur Laufzeit berechnet
Dynamische Styles basierend auf PropsGrößeres Bundle durch die Bibliothek
Keine Klassennamen-Verwaltung nötigLernkurve — neue API zusätzlich zu CSS
Styles sind automatisch an die Komponente gebundenWeniger vertraut für reine CSS-Entwickler