CSS a SCSS moduly 📦
V této části se podíváme na různé způsoby organizace CSS stylů v React aplikacích pomocí CSS modulů a SCSS preprocesoru.
🎯 Proč CSS moduly?
Problémy s globálními CSS styly:
- Konflikty názvů - různé komponenty mohou používat stejné třídy
- Těžká údržba - změna v jednom CSS souboru může ovlivnit celou aplikaci
- Nedostatečná izolace - styly se mohou navzájem ovlivňovat
Výhody CSS modulů:
✅ Izolované styly - každá komponenta má své vlastní styly
✅ Automatické přejmenování - třídy se automaticky přejmenují a nedojde ke konfliktu názvů
✅ TypeScript podpora - typování CSS tříd (IDE nám pomůže s typováním className)
✅ Lepší organizace - styly jsou blízko komponentám, což zjednodušuje jejich hledání a údržbu
📁 Struktura souborů
src/
├── components/
│ ├── EmployeeCard/
│ │ ├── EmployeeCard.jsx
│ │ ├── EmployeeCard.module.(css|scss)
└── styles/
├── globals.(css|scss)
└── variables.(css|scss)
🎨 CSS moduly
Základní použití:
CSS Moduly jsou vlastně CSS třídy, které potom importujeme a použijeme v kódu.
V případě, že máme 2 třídy s tímže názvem, tak CSS moduly nám pomohou vyřešit tento problém tím, že každá použitá třída bude přejmenována na vlastní unikátní název.
/* EmployeeCard.module.css */
.employeeCard {
background: white;
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: transform 0.2s ease;
}
.employeeCard:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.employeeAvatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: #007bff;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 18px;
}
.employeeInfo {
margin-left: 12px;
}
.employeeName {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
}
.employeePosition {
margin: 0 0 8px 0;
color: #666;
font-size: 14px;
}
.employeeDepartment {
background: #e9ecef;
color: #495057;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
Použití v komponentě:
// EmployeeCard.jsx
import React from 'react';
import styles from './EmployeeCard.module.css';
const EmployeeCard = ({ employee, onClick }) => {
return (
<div className={styles.employeeCard} onClick={onClick}>
<div className={styles.employeeAvatar}>
{employee.name.charAt(0)}
</div>
<div className={styles.employeeInfo}>
<h3 className={styles.employeeName}>{employee.name}</h3>
<p className={styles.employeePosition}>{employee.position}</p>
<span className={styles.employeeDepartment}>{employee.department}</span>
</div>
</div>
);
};
export default EmployeeCard;
🎨 SCSS moduly
Výhody SCSS:
- Proměnné - definice barev, velikostí, breakpointů
- Mixiny - znovupoužitelné styly
- Vnořování - lepší organizace CSS
- Funkce - matematické operace s hodnotami
SCSS soubor:
// EmployeeCard.module.scss
// Proměnné
$primary-color: #007bff;
$secondary-color: #6c757d;
$border-radius: 8px;
$box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
$transition: all 0.2s ease;
// Mixiny
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin card-hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
// Styly
.employeeCard {
background: white;
border-radius: $border-radius;
padding: 16px;
box-shadow: $box-shadow;
cursor: pointer;
transition: $transition;
&:hover {
@include card-hover;
}
}
.employeeAvatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: $primary-color;
color: white;
@include flex-center;
font-weight: bold;
font-size: 18px;
}
.employeeInfo {
margin-left: 12px;
}
.employeeName {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
}
.employeePosition {
margin: 0 0 8px 0;
color: $secondary-color;
font-size: 14px;
}
.employeeDepartment {
background: lighten($secondary-color, 40%);
color: darken($secondary-color, 20%);
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
🌐 Globální styly
Globální CSS soubor:
/* globals.css */
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.app {
min-height: 100vh;
background-color: #f8f9fa;
}
.main-content {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
Import v hlavním souboru:
// App.jsx
import React from 'react';
import './styles/globals.css';
// ... další importy
🔧 Konfigurace Vite
vite.config.js:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
css: {
modules: {
localsConvention: 'camelCase',
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
}
});
📋 Praktické cvičení
- Převeďte styly z předchozí lekce na CSS moduly
- Vytvořte SCSS verzi s proměnnými a mixiny
- Nastavte globální styly pro celou aplikaci
- Otestujte izolaci stylů mezi komponentami
🚀 Tipy a triky
Kombinování tříd:
import styles from './Component.module.css';
import classNames from 'classnames';
const Component = ({ isActive }) => {
return (
<div className={classNames(styles.base, {
[styles.active]: isActive
})}>
Content
</div>
);
};
Podmíněné styly:
const Component = ({ variant }) => {
return (
<div className={`${styles.base} ${styles[variant]}`}>
Content
</div>
);
};