Вёрстка сайта с использованием Material UI
Material UI (MUI) — React-компонентная библиотека, реализующая Material Design от Google. В версии v5+ библиотека перешла с JSS на emotion как styling engine и предоставляет систему тем через ThemeProvider. Набор компонентов охватывает практически весь спектр UI: от кнопок до сложных data grid.
Установка и базовая тема
npm install @mui/material @mui/icons-material @emotion/react @emotion/styled
// src/theme/index.ts
import { createTheme, responsiveFontSizes } from '@mui/material/styles';
declare module '@mui/material/styles' {
interface Palette {
neutral: Palette['primary'];
}
interface PaletteOptions {
neutral?: PaletteOptions['primary'];
}
}
let theme = createTheme({
palette: {
primary: {
light: '#60a5fa',
main: '#2563eb',
dark: '#1d4ed8',
contrastText: '#ffffff',
},
secondary: {
main: '#7c3aed',
contrastText: '#ffffff',
},
neutral: {
main: '#6b7280',
light: '#9ca3af',
dark: '#374151',
contrastText: '#ffffff',
},
background: {
default: '#f9fafb',
paper: '#ffffff',
},
text: {
primary: '#111827',
secondary: '#6b7280',
disabled: '#9ca3af',
},
},
typography: {
fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
h1: { fontWeight: 700, fontSize: '3rem' },
h2: { fontWeight: 700, fontSize: '2.25rem' },
h3: { fontWeight: 600, fontSize: '1.5rem' },
h4: { fontWeight: 600, fontSize: '1.25rem' },
body1: { fontSize: '1rem', lineHeight: 1.6 },
body2: { fontSize: '0.875rem', lineHeight: 1.57 },
},
shape: {
borderRadius: 8,
},
components: {
MuiButton: {
defaultProps: {
disableElevation: true,
},
styleOverrides: {
root: {
textTransform: 'none',
fontWeight: 500,
borderRadius: 8,
},
sizeLarge: {
padding: '12px 28px',
fontSize: '1rem',
},
},
},
MuiCard: {
defaultProps: {
elevation: 0,
},
styleOverrides: {
root: {
border: '1px solid #f3f4f6',
borderRadius: 12,
},
},
},
MuiTextField: {
defaultProps: {
variant: 'outlined',
size: 'small',
},
},
},
});
theme = responsiveFontSizes(theme);
export default theme;
// src/main.tsx
import { ThemeProvider, CssBaseline } from '@mui/material';
import theme from './theme';
function App() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Router>...</Router>
</ThemeProvider>
);
}
Примеры компонентов
Hero-секция
import { Box, Container, Typography, Button, Stack } from '@mui/material';
const HeroSection = () => (
<Box
component="section"
sx={{
py: { xs: 8, md: 14 },
background: 'linear-gradient(135deg, #eff6ff 0%, #f5f3ff 100%)',
}}
>
<Container maxWidth="lg">
<Stack
direction={{ xs: 'column', md: 'row' }}
spacing={6}
alignItems="center"
>
<Box flex={1}>
<Typography
variant="h1"
sx={{ mb: 3, fontSize: { xs: '2rem', md: '3rem' } }}
>
Заголовок вашего продукта
</Typography>
<Typography
variant="body1"
color="text.secondary"
sx={{ mb: 4, fontSize: '1.125rem', maxWidth: 480 }}
>
Описание ценностного предложения в двух-трёх предложениях.
</Typography>
<Stack direction="row" spacing={2} flexWrap="wrap">
<Button variant="contained" size="large" href="/start">
Начать бесплатно
</Button>
<Button variant="outlined" size="large" href="/demo">
Посмотреть демо
</Button>
</Stack>
</Box>
<Box flex={1}>
<Box
component="img"
src="/img/hero.webp"
alt="Product preview"
sx={{ width: '100%', borderRadius: 3, boxShadow: 6 }}
/>
</Box>
</Stack>
</Container>
</Box>
);
Карточки услуг
import { Grid, Card, CardContent, Typography } from '@mui/material';
import { Code, Cloud, Security } from '@mui/icons-material';
const services = [
{ icon: <Code />, title: 'Разработка', description: '...' },
{ icon: <Cloud />, title: 'Облако', description: '...' },
{ icon: <Security />, title: 'Безопасность', description: '...' },
];
const ServicesGrid = () => (
<Grid container spacing={3}>
{services.map((service) => (
<Grid item xs={12} sm={6} lg={4} key={service.title}>
<Card
sx={{
height: '100%',
transition: 'box-shadow 250ms ease',
'&:hover': { boxShadow: 4 },
}}
>
<CardContent sx={{ p: 4 }}>
<Box
sx={{
mb: 2,
color: 'primary.main',
'& svg': { fontSize: 40 },
}}
>
{service.icon}
</Box>
<Typography variant="h4" gutterBottom>
{service.title}
</Typography>
<Typography variant="body2" color="text.secondary">
{service.description}
</Typography>
</CardContent>
</Card>
</Grid>
))}
</Grid>
);
styled() для кастомных компонентов
import { styled } from '@mui/material/styles';
import { Box } from '@mui/material';
// MUI styled — доступ к теме через props
const GradientBox = styled(Box)(({ theme }) => ({
background: `linear-gradient(135deg, ${theme.palette.primary.main}, ${theme.palette.secondary.main})`,
borderRadius: theme.shape.borderRadius * 2,
padding: theme.spacing(6),
color: '#fff',
[theme.breakpoints.down('md')]: {
padding: theme.spacing(4),
},
}));
Тёмная тема
import { createTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
const App = () => {
const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
const theme = createTheme({
palette: {
mode: prefersDark ? 'dark' : 'light',
// Остальные переопределения...
},
});
return <ThemeProvider theme={theme}>...</ThemeProvider>;
};
Оптимизация bundle
MUI импортирует компоненты по-компонентно автоматически через babel-plugin или через tree-shaking:
// Правильно — tree-shaking работает
import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
// Или через деструктуризацию (tree-shaking в Vite тоже работает)
import { Button, Card, Typography } from '@mui/material';
Иконки — только нужные:
import CodeIcon from '@mui/icons-material/Code'; // Правильно
// import { Code } from '@mui/icons-material'; // Медленнее при сборке
Сроки
Настройка темы и ThemeProvider: 3–4 часа (тщательная проработка с дизайнером). Посадочная страница: 1.5–2 дня. Полный сайт с формами, модалками, таблицами данных: 4–8 дней в зависимости от функционала.







