← Назад к вопросам
Как реализовать изоляцию CSS в компонентах Vue?
2.0 Middle🔥 111 комментариев
#HTML и CSS
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое CSS изоляция?
CSS изоляция — это концепция ограничения области действия CSS стилей только компонентом, в котором они определены. Без изоляции стили компонента могут случайно затронуть другие компоненты. Vue предоставляет несколько способов достичь CSS изоляции.
Способ 1: Scoped CSS (встроенный в Vue)
// Component.vue
<template>
<div class="container">
<h1>{{ title }}</h1>
<p class="description">{{ description }}</p>
<button class="btn">Click me</button>
</div>
</template>
<script setup>
defineProps({
title: String,
description: String
});
</script>
<style scoped>
.container {
padding: 20px;
background-color: #f5f5f5;
border-radius: 8px;
}
h1 {
color: #333;
font-size: 24px;
}
.description {
color: #666;
margin: 10px 0;
}
.btn {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.btn:hover {
background-color: #0056b3;
}
</style>
<!-- Vue добавляет data-атрибут каждому элементу:
<div class="container" data-v-f3f3eg9c>
И модифицирует CSS селекторы:
.container[data-v-f3f3eg9c] { ... }
-->
Способ 2: CSS Modules
// Component.vue
<template>
<div :class="styles.container">
<h1 :class="styles.title">{{ title }}</h1>
<p :class="styles.description">{{ description }}</p>
<button :class="[styles.btn, isActive && styles.btnActive]">
Click me
</button>
</div>
</template>
<script setup>
import { ref } from "vue";
import styles from "./Component.module.css";
defineProps({
title: String,
description: String
});
const isActive = ref(false);
</script>
<style module="styles">
.container {
padding: 20px;
background-color: #f5f5f5;
border-radius: 8px;
}
.title {
color: #333;
font-size: 24px;
}
.description {
color: #666;
margin: 10px 0;
}
.btn {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.btnActive {
background-color: #0056b3;
}
</style>
Способ 3: BEM (Block Element Modifier)
// UserCard.vue
<template>
<div class="user-card">
<div class="user-card__header">
<img :src="avatar" :alt="name" class="user-card__avatar" />
<h2 class="user-card__name">{{ name }}</h2>
</div>
<div class="user-card__body">
<p class="user-card__bio">{{ bio }}</p>
<div class="user-card__tags">
<span
v-for="tag in tags"
:key="tag"
class="user-card__tag"
>
{{ tag }}
</span>
</div>
</div>
<div class="user-card__footer">
<button
class="user-card__btn user-card__btn--primary"
@click="handleFollow"
>
Follow
</button>
<button
class="user-card__btn user-card__btn--secondary"
@click="handleMessage"
>
Message
</button>
</div>
</div>
</template>
<script setup>
defineProps({
name: String,
avatar: String,
bio: String,
tags: Array
});
const emit = defineEmits(["follow", "message"]);
const handleFollow = () => emit("follow");
const handleMessage = () => emit("message");
</script>
<style scoped>
.user-card {
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.user-card__header {
display: flex;
gap: 12px;
margin-bottom: 16px;
}
.user-card__avatar {
width: 60px;
height: 60px;
border-radius: 50%;
object-fit: cover;
}
.user-card__name {
font-size: 18px;
font-weight: bold;
}
.user-card__body {
margin-bottom: 16px;
}
.user-card__bio {
color: #666;
font-size: 14px;
}
.user-card__tag {
display: inline-block;
padding: 4px 12px;
background-color: #e0e0e0;
border-radius: 20px;
font-size: 12px;
}
.user-card__btn {
padding: 8px 12px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.user-card__btn--primary {
background-color: #007bff;
color: white;
}
.user-card__btn--primary:hover {
background-color: #0056b3;
}
.user-card__btn--secondary {
background-color: #f0f0f0;
color: #333;
}
</style>
Способ 4: CSS-in-JS с Tailwind CSS
// UserCard.vue
<template>
<div class="p-5 border border-gray-300 rounded-lg max-w-sm">
<div class="flex gap-3 mb-4">
<img
:src="avatar"
:alt="name"
class="w-15 h-15 rounded-full object-cover"
/>
<h2 class="text-lg font-bold text-gray-900 self-center">{{ name }}</h2>
</div>
<div class="mb-4">
<p class="text-sm text-gray-600 mb-3">{{ bio }}</p>
<div class="flex flex-wrap gap-2">
<span
v-for="tag in tags"
:key="tag"
class="px-3 py-1 bg-gray-200 rounded-full text-xs"
>
{{ tag }}
</span>
</div>
</div>
<div class="flex gap-2">
<button
class="flex-1 px-3 py-2 bg-blue-500 text-white rounded hover:bg-blue-700"
@click="handleFollow"
>
Follow
</button>
<button
class="flex-1 px-3 py-2 bg-gray-200 rounded hover:bg-gray-300"
@click="handleMessage"
>
Message
</button>
</div>
</div>
</template>
Способ 5: Комбинированный подход
// Используем scoped для простых стилей
// Используем CSS Modules для сложных стилей
<style scoped>
.wrapper {
padding: 20px;
background-color: #f9f9f9;
}
.header {
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
margin-bottom: 20px;
}
</style>
<style module="styles">
.content {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.cardWrapper {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
</style>
Сравнение методов
- Scoped CSS: Просто, встроено в Vue
- CSS Modules: Явная изоляция, уникальные имена
- BEM: Читаемо, масштабируемо
- Tailwind: Быстро, много утилит
- Комбинированный: Гибкость и лучшее из всех