Стили

Как стилизовать приложение Nuxt.

Nuxt даёт большую свободу в стилизации: свои стили, локальные и внешние таблицы, препроцессоры, CSS-фреймворки, UI-библиотеки и модули Nuxt.

Локальные стили

Для локальных стилей естественное место — директория app/assets/.

Импорт в компонентах

Стили можно импортировать в страницах, макетах и компонентах — через JavaScript-импорт или CSS-@import.

app/pages/index.vue
<script>
// Статический импорт для совместимости с SSR
import '~/assets/css/first.css'

// Внимание: динамический импорт не совместим с SSR
import('~/assets/css/first.css')
</script>

<style>
@import url("~/assets/css/second.css");
</style>
Стили будут встроены в HTML, отдаваемый Nuxt.

Свойство css в конфиге

Стили можно подключить через свойство css в конфигурации Nuxt. Удобное место для файлов — директория app/assets/; укажите путь, и Nuxt подключит его ко всем страницам.

nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
})
Стили будут встроены в HTML, подключены глобально и будут на всех страницах.

Работа со шрифтами

Разместите файлы шрифтов в public/, например в public/fonts. В стилях подключайте их через url().

assets/css/main.css
@font-face {
  font-family: 'FarAwayGalaxy';
  src: url('/fonts/FarAwayGalaxy.woff') format('woff');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

Далее используйте имя шрифта в стилях, страницах или компонентах:

<style>
h1 {
  font-family: 'FarAwayGalaxy', sans-serif;
}
</style>

Стили из npm

Можно подключать стили из npm-пакетов. Пример — библиотека animate.css:

npm install animate.css

Подключение в страницах, макетах и компонентах:

app/app.vue
<script>
import 'animate.css'
</script>

<style>
@import url("animate.css");
</style>

Пакет можно указать строкой в свойстве css в конфиге Nuxt:

nuxt.config.ts
export default defineNuxtConfig({
  css: ['animate.css'],
})

Внешние стили

Внешние таблицы стилей подключаются через элемент link в head — например, через свойство app.head в конфиге Nuxt. Так же можно подключать и локальные стили.

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }],
    },
  },
})

Динамическое добавление стилей

Композабл useHead позволяет задавать теги в head из кода.

Узнать больше Docs > 4 X > API > Composables > Use Head.
useHead({
  link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }],
})

Под капотом Nuxt использует unhead — см. документацию.

Изменение head через Nitro-плагин

Для более тонкого контроля можно перехватить отрендеренный HTML хуком и изменить head в коде.

Создайте плагин в ~~/server/plugins/my-plugin.ts:

server/plugins/my-plugin.ts
export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('render:html', (html) => {
    html.head.push('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">')
  })
})

Внешние стили блокируют рендеринг: браузер должен загрузить и обработать их до отрисовки страницы. Подробнее: web.dev.

Препроцессоры

Для использования SCSS, Sass, Less или Stylus сначала установите нужный пакет:

npm install -D sass

Писать стили удобно в директории app/assets. Импортируйте их в app.vue (или в макетах) синтаксисом выбранного препроцессора:

app/pages/app.vue
<style lang="scss">
@use "~/assets/scss/main.scss";
</style>

Либо укажите файл в свойстве css конфига Nuxt:

nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/scss/main.scss'],
})
В обоих случаях скомпилированные стили будут встроены в HTML, отдаваемый Nuxt.

Чтобы внедрить код в обрабатываемые файлы (например, Sass-партиал с переменными цветов), используйте опции препроцессоров Vite.

Создайте партиалы в app/assets:

$primary: #49240F;
$secondary: #E4A79D;

В nuxt.config:

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@use "~/assets/_colors.scss" as *;',
        },
      },
    },
  },
})

По умолчанию Nuxt использует Vite. При использовании webpack см. документацию лоадеров для каждого препроцессора.

Preprocessor Workers (экспериментально)

В Vite есть экспериментальная опция для ускорения препроцессоров.

Включение в nuxt.config:

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorMaxWorkers: true, // число CPU минус 1
    },
  },
})
Опция экспериментальная; см. документацию Vite и обсуждение.

Стили в SFC (Single File Components)

В Vue и SFC стили задаются прямо в блоке <style> компонента — без обязательного CSS-in-JS. При желании можно использовать сторонние библиотеки вроде pinceau.

Подробнее: документация Vue по стилям в SFC.

Привязки class и style

Используйте возможности Vue SFC для привязки атрибутов class и style:

<script setup lang="ts">
const isActive = ref(true)
const hasError = ref(false)
const classObject = reactive({
  'active': true,
  'text-danger': false,
})
</script>

<template>
  <div
    class="static"
    :class="{ 'active': isActive, 'text-danger': hasError }"
  />
  <div :class="classObject" />
</template>

Подробнее: Vue — классы и стили.

Динамические стили с v-bind

В блоках <style> можно использовать переменные и выражения JavaScript через v-bind. Значения реактивны: при изменении переменной обновится и стиль.

<script setup lang="ts">
const color = ref('red')
</script>

<template>
  <div class="text">
    hello
  </div>
</template>

<style>
.text {
  color: v-bind(color);
}
</style>

Scoped-стили

Атрибут scoped ограничивает стили текущим компонентом.

<template>
  <div class="example">
    hi
  </div>
</template>

<style scoped>
.example {
  color: red;
}
</style>

CSS Modules

CSS Modules подключаются атрибутом module. Доступ через переменную $style:

<template>
  <p :class="$style.red">
    This should be red
  </p>
</template>

<style module>
.red {
  color: red;
}
</style>

Препроцессоры в SFC

В блоках <style> поддерживается синтаксис препроцессоров. Vite из коробки поддерживает .scss, .sass, .less, .styl и .stylus — достаточно установить пакет и указать lang:

<style lang="scss">
  /* Пишите scss здесь */
</style>

См. Vite CSS и @vitejs/plugin-vue. Для webpack — vue-loader.

PostCSS

В Nuxt PostCSS встроен. Настройка в nuxt.config:

nuxt.config.ts
export default defineNuxtConfig({
  postcss: {
    plugins: {
      'postcss-nested': {},
      'postcss-custom-media': {},
    },
  },
})

Для подсветки синтаксиса в SFC можно указать lang="postcss":

<style lang="postcss">
  /* Пишите postcss здесь */
</style>

По умолчанию в Nuxt уже подключены:

Разные стили для макетов

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

<template>
  <div class="default-layout">
    <h1>Default Layout</h1>
    <slot />
  </div>
</template>

<style>
.default-layout {
  color: red;
}
</style>
Узнать больше Docs > 4 X > Directory Structure > App > Layouts.

Сторонние библиотеки и модули

Nuxt не навязывает подход к стилям: можно использовать UnoCSS, Tailwind CSS и другие инструменты.

Сообщество и команда Nuxt разработали множество модулей для удобной интеграции. Ищите их в разделе модулей сайта. Несколько примеров:

  • UnoCSS: атомарный CSS по требованию
  • Tailwind CSS: utility-first CSS фреймворк
  • Fontaine: метрики шрифтов и fallback
  • Pinceau: адаптивная система стилей
  • Nuxt UI: UI-библиотека для современных приложений
  • Panda CSS: CSS-in-JS с генерацией атомарного CSS при сборке

Модули дают удобный опыт из коробки, но если у вашего инструмента нет модуля — его всё равно можно подключить вручную (плагин и/или собственный модуль). Имеет смысл поделиться решением в сообществе.

Подключение веб-шрифтов

Для Google Fonts можно использовать модуль Nuxt Google Fonts.

При использовании UnoCSS доступен пресет web fonts для подключения шрифтов от популярных провайдеров, включая Google Fonts.

Продвинутое

Переходы

В Nuxt доступен тот же элемент <Transition>, что и во Vue, плюс экспериментальная View Transitions API.

Узнать больше Docs > 4 X > Getting Started > Transitions.

Оптимизация шрифтов

Рекомендуется Fontaine для снижения CLS. Для более сложных сценариев можно написать модуль Nuxt, расширяющий сборку или рантайм.

Используйте доступные в веб-экосистеме инструменты: нативный CSS, препроцессор, PostCSS, UI-библиотеку или модуль — Nuxt позволяет комбинировать их как удобно.

Оптимизация LCP

Чтобы ускорить загрузку глобального CSS:

  • Используйте CDN для приближения файлов к пользователям
  • Сжимайте ресурсы (предпочтительно Brotli)
  • Используйте HTTP/2 или HTTP/3
  • Размещайте ресурсы на том же домене (без отдельного поддомена)

На современных платформах (Cloudflare, Netlify, Vercel) многое из этого делается автоматически. Подробнее: web.dev — оптимизация LCP.

Если весь CSS инлайнится Nuxt, можно (экспериментально) убрать ссылки на внешние CSS из HTML. Для этого подойдёт хук в модуле или в конфиге Nuxt:

nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'build:manifest': (manifest) => {
      const css = Object.values(manifest).find(options => options.isEntry)?.css
      if (css) {
        for (let i = css.length - 1; i >= 0; i--) {
          if (css[i].startsWith('entry')) {
            css.splice(i, 1)
          }
        }
      }
    },
  },
})