В вёрстке часто возникает ситуация: DOM-обёртка есть, а в layout’е она мешает.
Особенно это заметно в приложениях на Nuxt, где почти всегда есть корневой контейнер #__nuxt.
CSS-свойство display: contents — редкий, но мощный инструмент, который позволяет визуально «убрать» элемент, не удаляя его из DOM.
Разберёмся, как он работает, какие у него ограничения и почему в Nuxt его можно безопасно применять прямо в app.vue.
Что делает display: contents
.wrapper {
display: contents;
}
👉 Элемент перестаёт участвовать в layout-е,
👉 но его дочерние элементы остаются и ведут себя так, будто были подняты на уровень выше.
Проще говоря
DOM:
<div class="wrapper">
<button>OK</button>
<button>Cancel</button>
</div>
CSS:
.wrapper {
display: contents;
}
Результат для layout’а:
<button>OK</button>
<button>Cancel</button>
⚠️ Важно:
- элемент не исчезает из DOM
- JS, Vue refs, события — работают
- исчезает только сам box
Зачем это вообще нужно
1. Когда обёртка ломает Grid или Flex
<div class="grid">
<div class="wrapper">
<div class="item" />
<div class="item" />
</div>
</div>
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
Без display: contents:
- grid видит один элемент (
wrapper)
С display: contents:
- grid видит два
.item
2. Когда компонент — логический, а не визуальный
Во Vue / Nuxt это особенно актуально:
<MyProvider>
<PageContent />
</MyProvider>
Компонент нужен:
- для логики
- для provide/inject
- для side-effects
Но не нужен как DOM-элемент.
display: contents решает это без фрагментов и костылей.
display: contents и доступность (важно)
Есть нюанс ⚠️
- элемент пропадает из accessibility tree
role,aria-*на нём не работаютlabel→inputможет сломаться
❌ Не используйте для:
buttonalabelform- элементов с
role
✅ Хорошо подходит для:
div- layout-обёрток
- контейнеров компонентов
Применение в Nuxt: #__nuxt
В Nuxt есть обязательный корневой элемент:
<div id="__nuxt">
<div id="__layout">
...
</div>
</div>
Часто он:
- ломает
height: 100% - мешает flex / grid
- добавляет лишний уровень вложенности
Решение
В app.vue можно безопасно написать:
<style>
#__nuxt {
display: contents;
}
</style>
Почему это работает
#__nuxt— чистая техническая обёртка- у него нет:
- роли
- семантики
- интерактивности
- Nuxt и Vue продолжают нормально работать
📌 Визуально:
- layout упрощается
- grid / flex начинают работать «как ожидалось»
- пропадает лишний контейнер
Это лучше, чем fragment?
| Подход | Когда использовать |
|---|---|
<template> / Fragment | когда ты контролируешь компонент |
display: contents | когда DOM уже есть (Nuxt, сторонние компоненты) |
teleport | когда нужно вынести из дерева |
Для #__nuxt — display: contents идеален.
Ограничения и подводные камни
- нельзя применять анимации к самому элементу
z-indexна нём не работает::before / ::after— не работаютposition— не имеет смысла
Итог
display: contents — это:
- 🧠 способ отделить DOM от layout
- 🧱 убрать лишние контейнеры без рефакторинга
- ⚡ особенно полезен в Nuxt / Vue
Используй его:
- для layout-обёрток
- для
#__nuxt - для логических компонентов
И не используй для семантических и интерактивных элементов.


Добавить комментарий