Перейти к содержанию

Особенности CSS в однофайловых компонентах

CSS с ограниченной областью действия

Когда тег <style> имеет атрибут scoped, его CSS будет применяться только к элементам текущего компонента. Это похоже на инкапсуляцию стилей в Shadow DOM. Он имеет некоторые оговорки, но не требует полифиллов. Это достигается с помощью PostCSS для преобразования следующих элементов:

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

<template>
  <div class="example">привет</div>
</template>

В следующие:

vue
<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style>

<template>
  <div class="example" data-v-f3f3eg9>привет</div>
</template>

Корневые элементы дочерних компонентов

При использовании scoped стили родительского компонента не будут просачиваться в дочерние компоненты. Однако корневой узел дочернего компонента будет подвержен влиянию как родительского, так и дочернего CSS. Это сделано специально для того, чтобы родитель мог придать стиль дочернему корневому элементу в целях верстки.

Глубокие селекторы

Если вы хотите, чтобы селектор в scoped стилях был «глубоким», для воздействия на дочерние компоненты, можно использовать псевдокласс :deep():

vue
<style scoped>
.a :deep(.b) {
  /* ... */
}
</style>

Все вышеперечисленное будет собрано воедино:

css
.a[data-v-f3f3eg9] .b {
  /* ... */
}

Совет

DOM-контент, созданный с помощью v-html, не подвержен влиянию скопированных стилей, но вы всё равно можете стилизовать его с помощью глубоких селекторов.

Селекторы slotted

По умолчанию стили с ограниченной областью действия не влияют на содержимое, отображаемое с помощью <slot/>, поскольку считается, что они принадлежат родительскому компоненту, передающему их. Чтобы явно указать содержимое слота, используйте псевдокласс :slotted:

vue
<style scoped>
:slotted(div) {
  color: red;
}
</style>

Глобальные селекторы

Если вы хотите, чтобы только одно правило применялось глобально, вы можете использовать псевдокласс :global вместо создания другого <style> (см. ниже):

vue
<style scoped>
:global(.red) {
  color: red;
}
</style>

Смешение локальных и глобальных стилей

Вы также можете включить в один и тот же компонент стили как с областью действия, так и без области действия:

vue
<style>
/* глобальные стили */
</style>

<style scoped>
/* локальные стили */
</style>

Советы по стилям с ограниченной областью действия

  • Стили с ограниченной областью действия не устраняют необходимость в классах. Из-за того, как браузеры отображают различные селекторы CSS, p {color: red } будет во много раз медленнее при ограничении области действия (т. е. в сочетании с селектором атрибутов). Если вместо этого вы используете классы или идентификаторы, например, .example {color: red }, вы практически исключаете снижение производительности.

  • Будьте осторожны с селекторами потомков в рекурсивных компонентах! Для правила CSS с селектором .a .b, если элемент, соответствующий .a, содержит рекурсивный дочерний компонент, то все .b в этом дочернем компоненте будут соответствовать правилу.

CSS-модули

Тег <style module> компилируется как CSS-модули и предоставляет результирующие классы CSS компоненту в качестве объекта под ключом $style:

vue
<template>
  <p :class="$style.red">Это должно быть красным</p>
</template>

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

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

Обратитесь к спецификации CSS-модулей для получения более подробной информации, такой как глобальные исключения и композиция.

Пользовательское имя инъекции

Можно настроить ключ свойства объекта инжектируемых классов, задав значение атрибуту module:

vue
<template>
  <p :class="classes.red">красный</p>
</template>

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

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

Доступ к инжектированным классам можно получить в setup() и <script setup> через API useCssModule. Для блоков <style module> с пользовательскими именами инъекций, useCssModule принимает в качестве первого аргумента соответствующее значение атрибута module:

js
import { useCssModule } from 'vue'

// внутри области видимости setup()...
// по умолчанию, возвращает классы для <style module>
useCssModule()

// возвращает классы для именованного модуля <style module="classes">
useCssModule('classes')
  • Пример
vue
<script setup lang="ts">
import { useCssModule } from 'vue'

const classes = useCssModule()
</script>

<template>
  <p :class="classes.red">red</p>
</template>

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

v-bind() в CSS

Теги <style> в однофайловых компонентах поддерживают привязку значений CSS к динамическому состоянию компонента с помощью CSS-функции v-bind:

vue
<template>
  <div class="text">привет</div>
</template>

<script>
export default {
  data() {
    return {
      color: 'red'
    }
  }
}
</script>

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

Синтаксис работает с <script setup>, а также поддерживает выражения JavaScript (должны быть заключены в кавычки):

vue
<script setup>
import { ref } from 'vue'
const theme = ref({
  color: 'red'
})
</script>

<template>
  <p>привет</p>
</template>

<style scoped>
p {
  color: v-bind('theme.color');
}
</style>

Фактическое значение будет скомпилировано в хэшированное пользовательское свойство CSS, поэтому CSS остаётся статичным. Пользовательское свойство будет применяться к корневому элементу компонента с помощью встроенных стилей и реактивно обновляться при изменении исходного значения.

Особенности CSS в однофайловых компонентах