display: contents — как он работает и зачем нужен в Nuxt

от автора

в ,
Время чтения: 2 мин.

В вёрстке часто возникает ситуация: 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-* на нём не работают
  • labelinput может сломаться

❌ Не используйте для:

  • button
  • a
  • label
  • form
  • элементов с 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когда нужно вынести из дерева

Для #__nuxtdisplay: contents идеален.


Ограничения и подводные камни

  • нельзя применять анимации к самому элементу
  • z-index на нём не работает
  • ::before / ::after — не работают
  • position — не имеет смысла

Итог

display: contents — это:

  • 🧠 способ отделить DOM от layout
  • 🧱 убрать лишние контейнеры без рефакторинга
  • ⚡ особенно полезен в Nuxt / Vue

Используй его:

  • для layout-обёрток
  • для #__nuxt
  • для логических компонентов

И не используй для семантических и интерактивных элементов.


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Сколько будет 4 + 7?