# Возможности стилей SFC

# <style scoped>

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

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

<template>
  <div class="example">привет</div>
</template>
1
2
3
4
5
6
7
8
9

В следующее:

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

<template>
  <div class="example" data-v-f3f3eg9>привет</div>
</template>
1
2
3
4
5
6
7
8
9

# Корневые элементы дочернего компонента

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

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

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

<style scoped>
.a :deep(.b) {
  /* ... */
}
</style>
1
2
3
4
5

Указанное выше будет скомпилировано в:

.a[data-v-f3f3eg9] .b {
  /* ... */
}
1
2
3

Совет

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

# Селекторы слотов

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

<style scoped>
:slotted(div) {
  color: red;
}
</style>
1
2
3
4
5

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

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

<style scoped>
:global(.red) {
  color: red;
}
</style>
1
2
3
4
5

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

В одном компоненте можно вместе использовать как scoped, так и обычные секции style:

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

<style scoped>
/* локальные стили */
</style>
1
2
3
4
5
6
7

# Советы по использованию scoped-стилей

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

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

# <style module>

Секция <style module> компилируется как CSS модуль (opens new window) и объявляет результирующие CSS-классы компоненту объектом под ключом $style:

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

<style module>
.red {
  color: red;
}
</style>
1
2
3
4
5
6
7
8
9
10
11

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

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

# Внедрение пользовательского имени

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

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

<style module="classes">
.red {
  color: red;
}
</style>
1
2
3
4
5
6
7
8
9

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

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

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

// при указании имени, возвращает классы для <style module="classes">
useCssModule('classes')
1
2
3
4
5

# Динамический CSS с учётом состояния

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

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

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

<style>
.text {
  color: v-bind(color);
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

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

<script setup>
const theme = {
  color: 'red'
}
</script>

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

<style scoped>
p {
  color: v-bind('theme.color');
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

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