display: contents и React: когда переиспользование контейнера ломает семантику, разметк...
display: contents и React: когда переиспользование контейнера ломает семантику, разметку и анимации — и как чинить Универсальные компоненты-обертки вроде Box или Card — стандарт production-кода. Но они часто нарушают семантику HTML, ломают flex/grid layout и делают DOM-дерево невалидным. Решение — display: contents, но оно не так безобидно, как кажется. Семантика и роль контейнера Проблема: <ul> внутри <div> рендерит <li> не прямым потомком, что нарушает спецификацию. display: contents делает контейнер невидимым для браузера, а children «встраиваются» в родителя. Пример на TypeScript: function Container({ as: Tag = 'div', children }: { as?: string; children: ReactNode }) { return <Tag style={{ display: 'contents' }}>{children}</Tag> } Но если у контейнера есть aria-label или role, они теряются для скринридеров — это частая ошибка в production. Анимации и неожиданное поведение display: contents удаляет элемент из визуального дерева. Анимации на нем (opacity, transform) перестают работать. Дети отрисовываются мгновенно, без плавности. Чинить так: // Плохо: анимация на контейнере с contents <div style={{ display: 'contents', opacity: 0 }}> // Не сработает // Хорошо: обертка отдельно <div style={{ display: 'contents' }}> <div style={{ opacity: 0, transition: 'opacity 0.3s' }}>...</div> </div> Где не работает и trade-offs * Табличные элементы (<tr>, <td>) не поддерживают contents — верстка ломается. * Корневые элементы (<html>, <body>) — не пытайтесь. * ARIA-атрибуты на контейнере пропадают для доступности: если нужен aria-label для скринридера, выноси его на детей или используй role="presentation" отдельно. Практический совет В production используй display: contents только для контейнеров без собственных стилей и анимаций. Например, в layout-компоненте: function FlexItem({ children }: { children: ReactNode }) { return <div style={{ display: 'contents' }}>{children}</div> } Это уменьшает дублирование стилей и сохраняет семантику. Но анимированные элементы всегда оборачивай дополнительно. Вывод: display: contents — мощный инструмент для чистого DOM и семантики, но требует явного разделения стилей и анимаций, иначе ломает визуальное поведение и доступность.