Sticky заголовки

В библиотеке MUI (Material-UI) управление позиционированием элементов выполняется с помощью системной пропсы sx, а также стандартных компонентов, таких как AppBar, Toolbar, Box и Typography. Sticky заголовки — это заголовки, которые остаются видимыми при прокрутке страницы или контейнера, но только до тех пор, пока их родительский блок не выйдет из области видимости.


Использование CSS-свойства position: sticky

Основная логика sticky заголовков строится вокруг CSS-свойства position: sticky. MUI полностью поддерживает это через пропсу sx:

import { Box, Typography } from '@mui/material';

<Box sx={{ overflow: 'auto', maxHeight: 400 }}>
  <Typography sx={{ position: 'sticky', top: 0, backgroundColor: '#fff', zIndex: 1 }}>
    Заголовок
  </Typography>
  <Box>
    {Array.from({ length: 50 }).map((_, i) => (
      <Typography key={i}>Элемент {i + 1}</Typography>
    ))}
  </Box>
</Box>

Ключевые моменты:

  • position: sticky фиксирует элемент относительно ближайшего родителя с прокруткой.
  • top: 0 указывает точку, от которой элемент будет «прилипать».
  • zIndex гарантирует, что заголовок будет отображаться поверх других элементов.
  • backgroundColor предотвращает наложение текста при прокрутке.

Sticky в компоненте AppBar

Компонент AppBar поддерживает sticky режим через пропсу position:

import { AppBar, Toolbar, Typography } from '@mui/material';

<AppBar position="sticky">
  <Toolbar>
    <Typography variant="h6">Главный заголовок</Typography>
  </Toolbar>
</AppBar>

Отличия от стандартного CSS:

  • position="sticky" в AppBar автоматически задаёт top: 0 и правильный zIndex для Material Design.
  • При использовании нескольких AppBar необходимо учитывать порядок zIndex для корректного перекрытия.

Sticky заголовки в списках и таблицах

Для больших таблиц или списков часто требуется, чтобы заголовки колонок оставались видимыми:

import { Table, TableHead, TableBody, TableRow, TableCell } from '@mui/material';

<Table>
  <TableHead sx={{ position: 'sticky', top: 0, backgroundColor: '#f5f5f5', zIndex: 2 }}>
    <TableRow>
      <TableCell>Имя</TableCell>
      <TableCell>Возраст</TableCell>
      <TableCell>Город</TableCell>
    </TableRow>
  </TableHead>
  <TableBody>
    {Array.from({ length: 100 }).map((_, i) => (
      <TableRow key={i}>
        <TableCell>Пользователь {i + 1}</TableCell>
        <TableCell>{20 + (i % 30)}</TableCell>
        <TableCell>Город {i % 10}</TableCell>
      </TableRow>
    ))}
  </TableBody>
</Table>

Особенности:

  • Sticky работает только в пределах родителя с заданной высотой и overflow.
  • backgroundColor обязателен, иначе текст таблицы может просвечивать.
  • zIndex помогает заголовку оставаться поверх строк таблицы.

Sticky с динамическим контентом

Когда заголовки изменяются динамически или добавляются новые секции, важно использовать уникальные ключи и контролировать top для каждого заголовка:

import { Box, Typography } from '@mui/material';

const sections = [
  { title: 'Секция 1', items: 20 },
  { title: 'Секция 2', items: 15 },
  { title: 'Секция 3', items: 30 },
];

<Box sx={{ overflowY: 'auto', maxHeight: 500 }}>
  {sections.map((section, idx) => (
    <Box key={idx}>
      <Typography
        sx={{
          position: 'sticky',
          top: 0,
          backgroundColor: '#fff',
          zIndex: 1,
          padding: 1,
          borderBottom: '1px solid #ddd',
        }}
      >
        {section.title}
      </Typography>
      {Array.from({ length: section.items }).map((_, i) => (
        <Typography key={i} sx={{ padding: 1 }}>
          Элемент {i + 1}
        </Typography>
      ))}
    </Box>
  ))}
</Box>

Рекомендации:

  • Для нескольких sticky заголовков в одном контейнере top может корректироваться суммой высот предыдущих заголовков.
  • Использование borderBottom или boxShadow повышает визуальную читаемость.

Адаптация к темной и светлой теме

Чтобы заголовки оставались заметными в разных темах, MUI позволяет использовать theme.palette в sx:

import { useTheme, Typography } from '@mui/material';

const theme = useTheme();

<Typography
  sx={{
    position: 'sticky',
    top: 0,
    backgroundColor: theme.palette.background.paper,
    zIndex: 1,
    padding: 1,
  }}
>
  Заголовок
</Typography>

Преимущества:

  • Цвет автоматически адаптируется под светлую и тёмную тему.
  • Обеспечивает согласованность с остальными компонентами MUI.

Производительность и оптимизация

  • Sticky заголовки лучше применять в контейнерах с ограниченной высотой и вертикальной прокруткой.
  • Для очень длинных списков рекомендуется использовать react-window или react-virtualized вместе с sticky заголовками, чтобы уменьшить нагрузку на DOM.
  • Избегать анимаций на position: sticky, так как это может вызывать подтормаживания на мобильных устройствах.

Sticky заголовки в MUI позволяют создавать аккуратные интерфейсы с фиксированными элементами, остающимися видимыми при прокрутке. Правильная комбинация position: sticky, top, zIndex и backgroundColor обеспечивает стабильное и визуально чистое отображение заголовков в любых компонентах.