Как изменить количество колонок через Props в CSS-in-JS?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Изменение количества колонок через Props в CSS-in-JS
Это классическая задача, когда нужно сделать компонент гибким, позволяя родителю контролировать количество колонок в Grid или многоколонном макете. Рассмотрим несколько подходов для разных CSS-in-JS решений.
1. Tailwind CSS с условными классами (рекомендуется)
В современной разработке часто используют Tailwind CSS, который может генерировать динамические классы.
// components/Grid.tsx
interface GridProps {
children: React.ReactNode;
columns?: 1 | 2 | 3 | 4 | 6;
}
export function Grid({ children, columns = 2 }: GridProps) {
const colsClass = {
1: grid-cols-1,
2: grid-cols-2,
3: grid-cols-3,
4: grid-cols-4,
6: grid-cols-6
}[columns];
return (
<div className={`grid gap-4 ${colsClass}`}>
{children}
</div>
);
}
// Использование
<Grid columns={3}>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</Grid>
Проблема: нельзя просто вставить grid-cols-${columns}, потому что Tailwind требует статических класс-имен для оптимизации.
2. CSS Variables (самый современный способ)
Используем CSS переменные (custom properties) для динамического контроля.
// components/Grid.tsx
interface GridProps {
children: React.ReactNode;
columns?: number;
}
export function Grid({ children, columns = 2 }: GridProps) {
return (
<div
style={{
display: grid,
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: 1rem
}}
>
{children}
</div>
);
}
// Или через CSS переменную
export function Grid({ children, columns = 2 }: GridProps) {
return (
<div
style={{
--cols: columns
} as React.CSSProperties}
className="grid"
>
{children}
</div>
);
}
// В CSS файле или <style>
// .grid {
// display: grid;
// grid-template-columns: repeat(var(--cols), 1fr);
// gap: 1rem;
// }
3. Emotion (CSS-in-JS библиотека)
Эмоция позволяет писать CSS прямо в JavaScript с поддержкой переменных.
import { css } from @emotion/react;
import styled from @emotion/styled;
const GridWrapper = styled.div<{ columns: number }>`
display: grid;
grid-template-columns: repeat(${props => props.columns}, 1fr);
gap: 1rem;
`;
interface GridProps {
children: React.ReactNode;
columns?: number;
}
export function Grid({ children, columns = 2 }: GridProps) {
return (
<GridWrapper columns={columns}>
{children}
</GridWrapper>
);
}
// Использование
<Grid columns={4}>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</Grid>
4. Styled Components
Популярная библиотека для CSS-in-JS в React.
import styled from styled-components;
const GridWrapper = styled.div<{ columns: number }>`
display: grid;
grid-template-columns: repeat(${props => props.columns}, 1fr);
gap: 1rem;
width: 100%;
`;
interface GridProps {
children: React.ReactNode;
columns?: number;
}
export function Grid({ children, columns = 2 }: GridProps) {
return (
<GridWrapper columns={columns}>
{children}
</GridWrapper>
);
}
5. Vanilla CSS с CSS-in-JS объектом
Прямое применение стилей через style prop в React.
interface GridProps {
children: React.ReactNode;
columns?: number;
gap?: number;
}
export function Grid({ children, columns = 2, gap = 16 }: GridProps) {
const gridStyle: React.CSSProperties = {
display: grid,
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: `${gap}px`,
width: 100%
};
return <div style={gridStyle}>{children}</div>;
}
// Использование
<Grid columns={3} gap={20}>
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
</Grid>
6. Responsive Grid (разное количество колонок на разных экранах)
Очень часто нужно менять количество колонок в зависимости от размера экрана.
interface ResponsiveGridProps {
children: React.ReactNode;
columns?: {
mobile: number;
tablet: number;
desktop: number;
};
}
export function ResponsiveGrid({
children,
columns = { mobile: 1, tablet: 2, desktop: 3 }
}: ResponsiveGridProps) {
return (
<div
style={{
display: grid,
gridTemplateColumns: `repeat(${columns.mobile}, 1fr)`
}}
className="
grid gap-4
sm:grid-cols-2 tablet:grid-cols-2
lg:grid-cols-3 desktop:grid-cols-3
"
>
{children}
</div>
);
}
// Или с CSS переменными
const styles = `
@media (max-width: 640px) {
.responsive-grid {
grid-template-columns: repeat(var(--cols-mobile), 1fr);
}
}
@media (min-width: 641px) and (max-width: 1024px) {
.responsive-grid {
grid-template-columns: repeat(var(--cols-tablet), 1fr);
}
}
@media (min-width: 1025px) {
.responsive-grid {
grid-template-columns: repeat(var(--cols-desktop), 1fr);
}
}
`;
interface ResponsiveGridProps {
children: React.ReactNode;
mobileColumns?: number;
tabletColumns?: number;
desktopColumns?: number;
}
export function ResponsiveGrid({
children,
mobileColumns = 1,
tabletColumns = 2,
desktopColumns = 3
}: ResponsiveGridProps) {
return (
<div
style={{
--cols-mobile: mobileColumns,
--cols-tablet: tabletColumns,
--cols-desktop: desktopColumns
} as React.CSSProperties}
className="responsive-grid gap-4"
>
{children}
</div>
);
}
7. Практический пример с обработкой edge cases
interface GridProps {
children: React.ReactNode;
columns?: number;
minWidth?: number; // Минимальная ширина колонки
gap?: number;
}
export function Grid({
children,
columns = 2,
minWidth = 200,
gap = 16
}: GridProps) {
// Валидация
const validColumns = Math.max(1, Math.floor(columns));
const validGap = Math.max(0, gap);
const gridStyle: React.CSSProperties = {
display: grid,
gridTemplateColumns: `repeat(auto-fit, minmax(${minWidth}px, 1fr))`,
gap: `${validGap}px`,
width: 100%
};
return (
<div style={gridStyle} role="grid">
{children}
</div>
);
}
Сравнение подходов
| Подход | Плюсы | Минусы |
|---|---|---|
| Tailwind + Map | Простой, предсказуемый | Много кода для каждого значения |
| CSS Variables | Динамичный, гибкий | Нужна поддержка CSS переменных |
| Inline styles | Быстро, нет зависимостей | Сложнее с мобильностью |
| Emotion/Styled | Мощный, типизированный | Дополнительная библиотека |
| CSS Grid auto-fit | Адаптивный без медиа-запросов | Меньше контроля над макетом |
Лучшая практика
Для современной разработки рекомендуется:
- Используй CSS Variables для простоты и гибкости
- Твой стиль должен быть типизирован в TypeScript
- Валидируй props перед использованием
- Используй auto-fit для адаптивности когда возможно
- Документируй допустимые значения в интерфейсе
Самый универсальный и современный способ — это комбинация CSS Variables и inline styles, которая работает везде и не требует дополнительных библиотек.