Стилизация

Узнайте, как стилизовать Nuxt-приложение.

Nuxt гибок в части стилей: можно писать свои стили или подключать локальные и внешние таблицы стилей.

Доступны препроцессоры CSS, CSS-фреймворки, UI-библиотеки и модули Nuxt.

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

Если вы пишете локальные таблицы стилей, стандартным местом для их размещения является директория assets/.

Импорт внутри компонентов

Вы можете импортировать таблицы стилей напрямую в свои страницы, лейауты и компоненты. Можно подключить стили через импорт в JavaScript или директиву @import в CSS.

pages/index.vue
<script>
// Use a static import for server-side compatibility
import '~/assets/css/first.css'

// Caution: Dynamic imports are not server-side compatible
import('~/assets/css/first.css')
</script>

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

Свойство CSS

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

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

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

Поместите локальные файлы шрифтов в директорию 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;
}

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

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

Таблицы стилей, распространяемые через NPM

Вы также можете ссылаться на таблицы стилей, распространяемые через npm. Давайте в качестве примера воспользуемся популярной библиотекой animate.css.

npm install animate.css

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

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>, в том числе из nuxt.config. Локальные CSS можно добавить тем же способом.

Вы можете управлять элементом 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' }],
    },
  },
})

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

Для динамического <head> в коде используйте композабл useHead.

Узнать больше Docs > 3 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

Обычным местом для написания таблиц стилей является директория assets. Затем вы можете импортировать исходные файлы в app.vue (или файлы лейаутов), используя синтаксис препроцессора.

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.

Создайте несколько фрагментов (partials) в директории assets:

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

Затем в nuxt.config :

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

Nuxt использует Vite по умолчанию. Если вы хотите использовать вместо этого webpack, обратитесь к документации загрузчика нужного препроцессора.

Воркеры препроцессора (экспериментально)

В Vite есть экспериментальная опция, ускоряющая препроцессоры.

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

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

Стилизация однофайловых компонентов (SFC)

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

Подробную справочную информацию о стилизации компонентов в SFC можно найти в документации Vue.

Привязки классов и стилей

Вы можете использовать возможности 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

Вы можете ссылаться на 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 позволяет вам стилизовать компоненты изолированно. Стили, объявленные с этим атрибутом, будут применяться только к этому компоненту.

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

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

CSS-модули

Вы можете использовать CSS-модули с атрибутом module. Доступ к модулю осуществляется с помощью внедренной переменной $style.

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

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

Поддержка препроцессоров

Блоки стилей SFC поддерживают синтаксис препроцессора. Vite поставляется со встроенной поддержкой файлов .scss, .sass, .less, .styl и .stylus без конфигурации. Вам просто нужно установить их, и они будут доступны непосредственно в SFC с атрибутом lang.

<style lang="scss">
  /* Write scss here */
</style>

Вы можете обратиться к документации Vite CSS и документации @vitejs/plugin-vue. Для пользователей webpack обратитесь к документации по загрузчику Vue.

Использование PostCSS

Nuxt поставляется со встроенным postcss. Вы можете настроить его в файле nuxt.config.

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

Для правильной подсветки синтаксиса в SFC можно использовать атрибут lang со значением postcss.

<style lang="postcss">
  /* Write postcss here */
</style>

По умолчанию Nuxt поставляется со следующими предварительно настроенными плагинами:

  • postcss-import: Улучшает правило @import
  • postcss-url: Преобразует выражения url()
  • autoprefixer: Автоматически добавляет вендорные префиксы
  • cssnano: Минифицирует и очищает

Использование лейаутов для нескольких стилей

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

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

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

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

Nuxt не навязывает один способ стилизации — доступен широкий выбор инструментов, например UnoCSS или Tailwind CSS.

Сообщество и команда выпускают модули, упрощающие интеграцию; каталог — в разделе модули. Несколько примеров для старта:

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

Модули Nuxt дают удобный опыт разработки из коробки, но отсутствие модуля не мешает подключить инструмент вручную. Часто достаточно плагина Nuxt и/или собственного модуля. Если сделаете что-то полезное — поделитесь с сообществом.

Простая загрузка веб-шрифтов

Вы можете использовать модуль Nuxt Google Fonts для загрузки Google Fonts.

Если вы используете UnoCSS, обратите внимание, что он поставляется с предустановками веб-шрифтов для удобной загрузки шрифтов от распространенных поставщиков, включая Google Fonts и другие.

Продвинутый уровень

Переходы

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

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

Продвинутая оптимизация шрифтов

Мы рекомендуем использовать Fontaine для сокращения вашего CLS. Если вам нужно что-то более продвинутое, рассмотрите возможность создания модуля Nuxt для расширения процесса сборки или рантайма Nuxt.

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

Продвинутая оптимизация LCP

Вы можете сделать следующее, чтобы ускорить загрузку ваших глобальных CSS-файлов:

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

Большинство из этих вещей могут быть сделаны для вас автоматически, если вы используете современные платформы, такие как Cloudflare, Netlify или Vercel. Вы можете найти руководство по оптимизации LCP на web.dev.

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

nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'build:manifest': (manifest) => {
      // find the app entry, css list
      const css = Object.values(manifest).find(options => options.isEntry)?.css
      if (css) {
        // start from the end of the array and go to the beginning
        for (let i = css.length - 1; i >= 0; i--) {
          // if it starts with 'entry', remove it from the list
          if (css[i].startsWith('entry')) {
            css.splice(i, 1)
          }
        }
      }
    },
  },
})