логотип PurpleSchool
логотип PurpleSchool

Инструкция по работе с grid на Vue

Автор

Олег Марков

Введение

Работая с современными приложениями на Vue, вы часто сталкиваетесь с необходимостью создавать гибкие, адаптивные и масштабируемые интерфейсы. Одним из самых удобных инструментов для этого является CSS Grid — модуль для построения сеток прямо в браузере. Vue, как компонентно-ориентированный фреймворк, прекрасно сочетается с Grid-подходом для организации контента, построения галерей, таблиц и админок.

В этой инструкции я покажу вам, как максимально эффективно использовать возможности CSS Grid внутри компонентов Vue, как связывать сетку с реактивными данными и динамически управлять ее параметрами. Вы увидите, как объединить силу декларативного подхода Vue и лаконичность CSS Grid, чтобы делать интерфейсы одновременно красивыми и удобными для поддержки.

Основные концепции CSS Grid, применимые к Vue

Краткий обзор CSS Grid

CSS Grid Layout — это система двумерной верстки, которая позволяет размещать элементы на странице по строкам и столбцам с помощью простых правил. Grid отлично подходит для сложных интерфейсов, где контроль над положением элементов важнее "потока документа", как при Flexbox.

Для базовой работы с Grid вам нужно:

  • Определить элемент-контейнер (он становится grid-контейнером).
  • Описать сетку через grid-template-columns, grid-template-rows.
  • Управлять размещением дочерних элементов с помощью свойств grid.

В Vue вы объявляете сетку обычно с помощью стилей (CSS, SCSS, CSS-in-JS) в шаблоне компонента, применяя их к корневому или вложенному элементу.

Как связать CSS Grid и Vue

Главный принцип: CSS Grid работает на уровне DOM, а Vue — на уровне реактивных данных. В компонентах Vue вы можете:

  • Применять grid через scoped или глобальные стили.
  • Генерировать элементы сетки через директиву v-for.
  • Динамически изменять параметры сетки с помощью биндинга inline-стилей (:style) или классов (:class).

Такой подход позволяет динамически реагировать на изменения данных: например, увеличивать число колонок или менять структуру сетки по клику пользователя.

Создаем простую сетку на Vue

Пример базового grid-контейнера

Давайте начнем с самого простого — разместим элементы в виде сетки:

<template>
  <div class="grid-container">
    <div v-for="n in 6" :key="n" class="grid-item">
      Элемент {{ n }}
    </div>
  </div>
</template>

<style scoped>
/* Объявляем контейнер grid */
.grid-container {
  display: grid; /* Активируем grid */
  grid-template-columns: repeat(3, 1fr); /* 3 колонки одинаковой ширины */
  gap: 16px; /* Отступы между ячейками */
}

.grid-item {
  background: #f1f3f4;
  padding: 20px;
  border-radius: 8px;
  text-align: center;
}
</style>

В этом примере вы видите, как с помощью Vue мы создаем 6 элементов через v-for, а с помощью CSS задаем сетку с тремя колонками.

Динамическое изменение колонок

Теперь представим задачу: вы хотите, чтобы количество колонок сетки изменялось динамически, например, по клику или при изменении параметра. Это реализуется через связывание с inline-стилями:

<template>
  <div>
    <label>
      Кол-во колонок:
      <input v-model.number="columns" min="1" max="6" type="number">
    </label>
    <div class="grid-container" :style="gridStyle">
      <div v-for="n in 12" :key="n" class="grid-item">Элемент {{ n }}</div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      columns: 3 // начальное количество колонок
    };
  },
  computed: {
    gridStyle() {
      // Формируем строку для grid-template-columns
      return {
        display: 'grid',
        gridTemplateColumns: `repeat(${this.columns}, 1fr)`,
        gap: '16px'
      };
    }
  }
};
</script>

<style scoped>
.grid-item {
  background: #e6ecf0;
  padding: 16px;
  border-radius: 6px;
}
</style>

Как видите, теперь число колонок сетки зависит от значения поля columns, а пользователь может менять его через input. Это типичный пример реактивности Vue + CSS Grid.

Сложные случаи: вложенные Grid, адаптивность и работа с динамическими элементами

Вложенные сетки (nested grids)

Если ваш интерфейс сложнее, то можно внутри одной grid-ячейки разместить еще одну сетку. Такой подход часто используется для карточек со сложным содержимым.

<template>
  <div class="outer-grid">
    <div v-for="n in 4" :key="n" class="card">
      <div class="inner-grid">
        <div class="img"></div>
        <div class="text">Описание {{ n }}</div>
        <div class="button">Подробнее</div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.outer-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}

.inner-grid {
  display: grid;
  grid-template-columns: 60px 1fr;
  grid-template-rows: auto auto;
  gap: 8px;
  align-items: center;
}

.img {
  grid-row: span 2;
  background: #bcd;
  width: 60px;
  height: 60px;
  border-radius: 50%;
}
.text {
  font-size: 16px;
}
.button {
  grid-column: span 2;
  background: #f9a825;
  color: #fff;
  text-align: center;
  padding: 4px;
  border-radius: 4px;
  cursor: pointer;
}
</style>

В этом примере — карточка внутри сетки из двух колонок, у самой карточки поведение задает вложенная grid.

Адаптивные сетки

Vue и Grid дают очень простой способ сделать адаптивные сетки, которые меняются вместе с шириной экрана. Один из самых распространенных вариантов — использование функции auto-fit или auto-fill и значения minmax:

<template>
  <div class="auto-grid">
    <div v-for="item in 10" :key="item" class="auto-item">
      {{ item }}
    </div>
  </div>
</template>

<style scoped>
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 18px;
}
.auto-item {
  background: #ffeb3b;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
}
</style>

Теперь при сужении экрана количество колонок будет уменьшаться до тех пор, пока ячейка не станет уже 180px.

Для продвинутой адаптивности используют медиазапросы:

@media (max-width: 600px) {
  .auto-grid {
    grid-template-columns: 1fr; /* только одна колонка */
  }
}

Динамическое управление положением элементов

Иногда требуется, чтобы элементы занимали несколько ячеек или меняли положение в зависимости от данных. Здесь на помощь приходит биндинг стилей или классов:

<template>
  <div class="grid-layout">
    <div
      v-for="item in items"
      :key="item.id"
      class="grid-block"
      :style="{
        gridColumn: item.isWide ? 'span 2' : 'span 1'
      }"
    >
      {{ item.text }}
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, text: 'Блок 1', isWide: false },
        { id: 2, text: 'Блок 2', isWide: true }, // занимает две колонки
        { id: 3, text: 'Блок 3', isWide: false }
      ]
    };
  }
};
</script>

<style scoped>
.grid-layout {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.grid-block {
  background: #bbdefb;
  padding: 20px;
  border-radius: 5px;
  text-align: center;
}
</style>

В этом примере вы видите, что второй блок растягивается на две колонки благодаря свойству gridColumn: 'span 2', и это задается прямо из данных.

Grid-подход для больших компонентов и шаблонов

Создание сложных лэйаутов

Vue и Grid прекрасно подходят для сложных дэшбордов (админок) с множеством областей. Для них часто используют именованные grid-области (grid areas):

<template>
  <div class="dashboard">
    <header class="header">Шапка</header>
    <nav class="sidebar">Меню</nav>
    <main class="main">Контент</main>
    <aside class="ads">Боковой блок</aside>
    <footer class="footer">Футер</footer>
  </div>
</template>

<style scoped>
.dashboard {
  display: grid;
  grid-template-columns: 200px 1fr 150px;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    "header header header"
    "sidebar main ads"
    "footer footer footer";
  min-height: 100vh;
}

.header   { grid-area: header; background: #ececec; }
.sidebar  { grid-area: sidebar; background: #d0f0c0; }
.main     { grid-area: main; background: #fffde7; }
.ads      { grid-area: ads; background: #ffcdd2; }
.footer   { grid-area: footer; background: #bdbdbd; }
</style>

Grid areas позволяют задавать макет гораздо проще и декларативнее, чем с помощью float, flex и прочих устаревших подходов.

Работа с библиотеками Vue-компонентов

Некоторые популярные UI-библиотеки (Vuetify, Element Plus) предоставляют свои компоненты-сетки. Например, в Vuetify это <v-row> и <v-col>, но вы можете всегда строить кастомный grid только с помощью CSS.

Пример с использованием Vuetify:

<template>
  <v-container>
    <v-row>
      <v-col cols="12" md="6">Левый столбец</v-col>
      <v-col cols="12" md="6">Правый столбец</v-col>
    </v-row>
  </v-container>
</template>

Такой вариант хорош для стандартных layuot-ов, но если требуется максимальная гибкость и производительность — разумно использовать CSS Grid напрямую.

Взаимодействие grid с переходами и анимацией во Vue

Вы можете совмещать grid с переходами Vue для создания плавных анимаций при добавлении и удалении элементов:

<template>
  <div>
    <button @click="addItem">Добавить элемент</button>
    <transition-group name="fade-grid" tag="div" class="grid-list">
      <div
        v-for="item in items"
        :key="item.id"
        class="grid-cell"
      >
        {{ item.text }}
      </div>
    </transition-group>
  </div>
</template>

<script>
let counter = 4;
export default {
  data() {
    return {
      items: [
        { id: 1, text: 'Ячейка 1' },
        { id: 2, text: 'Ячейка 2' },
        { id: 3, text: 'Ячейка 3' }
      ]
    };
  },
  methods: {
    addItem() {
      this.items.push({ id: counter++, text: `Ячейка ${counter}` });
    }
  }
};
</script>

<style scoped>
.grid-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
}
.grid-cell {
  background: #c8e6c9;
  padding: 18px;
  border-radius: 6px;
}

.fade-grid-enter-active, .fade-grid-leave-active {
  transition: all 0.4s;
}
.fade-grid-enter, .fade-grid-leave-to {
  opacity: 0;
  transform: scale(0.95);
}
</style>

<transition-group> работает с grid аналогично, как и с flex или обычным списком, аккуратно анимируя появление/удаление элементов.

Практические советы и лучшие практики

  • Используйте Grid для любых сложных лэйаутов, где важно сохранить строгую структуру.
  • Старайтесь минимизировать вложенность, чтобы не усложнять поддержку — используйте вложенную сетку только там, где это действительно необходимо.
  • Для адаптивных макетов предпочитайте auto-fit/auto-fill и minmax: это уменьшает количество медиазапросов в коде.
  • Помните, что grid-ячейки по умолчанию растягиваются на всю ширину/высоту своей области.
  • Динамически меняйте параметры сетки (число колонок, размеры, положение) через биндинг Vue.
  • Для анимаций используйте <transition-group>, а для больших таблиц — виртуализацию или пагинацию.

Заключение

Работа с grid в компонентах Vue — мощный инструмент, который избавляет от множества типичных проблем верстки. С его помощью вы можете организовать адаптивные, динамические и масштабируемые интерфейсы, которые легко интегрируются с реактивностью Vue. Управляйте структурой сетки через данные, комбинируйте с анимациями, и ваш front-end станет заметно проще как для поддержки, так и для быстрого прототипирования новых фич.


Частозадаваемые технические вопросы по теме статьи и ответы на них

  1. Как сделать высоту grid-строк динамической, чтобы все ячейки сетки имели одинаковую высоту по высочайшему содержимому?

    Используйте свойство align-items: stretch на контейнере grid — по умолчанию оно растягивает все ячейки по высоте друг друга. Если в одной строке есть блок с большей высотой, все остальные в этой строке вытянутся до этого размера.

  2. Можно ли сделать Drag&Drop между элементами grid внутри Vue-компонента?

    Да, для этого используйте сторонние библиотеки, например vue-draggable, которые поддерживают работу с grid. Либо реализуйте drag&drop через объединение событий drag, v-for и манипуляцию массивом данных.

  3. Почему при скрытии блока (v-if="false") в grid появляются дырки?

    Если вы скрываете grid-элемент через v-if — он полностью убирается из разметки, и последующие элементы сдвигаются. Если же используется v-show, элемент становится display: none, но место он не занимает. Для избежания "провалов" рекомендуется работать только с v-if и корректной структурой массива данных.

  4. Как объединить несколько grid-ячееек по вертикали в одной колонке?

    Задайте дочернему элементу свойство grid-row: span N, где N — количество строк, которое необходимо занять. Пример: <div style="grid-row: span 2">Stretch</div> объединит две строки.

  5. Можно ли использовать v-for не только для контента ячеек, но и для задания структуры сетки (например, строить grid-template-columns)?

    Да, вычислите строку для grid-template-columns динамически (например, через массив с ширинами колонок), а затем пробиндите ее через :style или :class на grid-контейнере. Пример: vue :style="{ gridTemplateColumns: columnsArray.join(' ') }" Если columnsArray = ['1fr', '2fr', '1fr'], то результатом будет 3 колонки с разными ширинами.

Стрелочка влевоРабота с модулями и пакетами в VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLIРабота с Canvas во Vue3 способа интеграции Chart.js с Vue для создания графиковИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Работа с обновлениями компонента и жизненным циклом updateОбзор и использование утилит Vue для удобной разработкиРазрешение конфликтов и ошибок с помощью Vue resolveЗагрузка и управление состоянием загрузки в VueИспользование query-параметров и их обработка в маршрутах VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовКак обрабатывать async операции с Promise во VueИнтеграция Vue с серверной частью и HTTPS настройкамиИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Понимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueОбработка запросов и асинхронных операций в VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний