반응형
9장: 스타일링 - 컴포넌트에 옷 입히기
Vue 컴포넌트의 스타일을 꾸미는 다양한 방법을 배웁니다. 컴포넌트 스코프를 보장하는 <style scoped>, 동적 스타일링을 위한 v-bind, 그리고 전역 스타일 관리까지 알아봅니다.
1. 핵심 개념
<style scoped>:- 싱글 파일 컴포넌트(SFC)의 가장 큰 장점 중 하나입니다.
<style>태그에scoped속성을 추가하면, 해당 스타일은 현재 컴포넌트의 엘리먼트에만 적용됩니다. - Vue는 빌드 시점에 각 엘리먼트에 고유한 데이터 속성(예:
data-v-f3f3eg9)을 추가하고, CSS 셀렉터를h1[data-v-f3f3eg9]와 같이 변환하여 스타일 충돌을 방지합니다.
- 싱글 파일 컴포넌트(SFC)의 가장 큰 장점 중 하나입니다.
전역 스타일:
scoped를 사용하지 않은<style>블록은 전역 스타일로 적용됩니다. 애플리케이션 전체에 일관된 스타일(예: 기본 폰트, 레이아웃 리셋)을 정의할 때 유용합니다. 보통App.vue나 별도의 CSS 파일에서 관리합니다.
CSS Modules:
<style module>을 사용하여 CSS 파일을 모듈로 가져올 수 있습니다. 클래스 이름이 고유한 해시값으로 변환되어 객체 형태로 주입됩니다. JavaScript 내에서 클래스 이름을 동적으로 다룰 때 유용합니다.
State-Driven Dynamic Styles (v-bind in CSS):
- Vue 3.2+ 부터
<style>블록 안에서v-bind()함수를 사용하여 JavaScript 상태(ref, reactive, props 등)를 CSS 값에 직접 바인딩할 수 있습니다. 매우 직관적이고 강력한 동적 스타일링 기법입니다.
- Vue 3.2+ 부터
2. 예제 코드
예제 1: <style scoped>와 전역 스타일
Button.vue는 자신만의 스코프 스타일을 가지고, App.vue는 전역 스타일을 정의합니다.
<!-- src/components/Button.vue -->
<template>
<button class="button">나는 스코프 버튼</button>
</template>
<style scoped>
/* 이 스타일은 Button.vue 컴포넌트 내의 .button 클래스에만 적용됩니다. */
.button {
background-color: #42b883; /* Vue 색상 */
color: white;
border: none;
padding: 10px;
}
</style>
<!-- src/App.vue -->
<script setup>
import MyButton from './components/Button.vue';
</script>
<template>
<div>
<p class="global-text">이 텍스트는 전역 스타일의 영향을 받습니다.</p>
<MyButton />
<button class="button">나는 일반 버튼</button>
</div>
</template>
<style>
/* scoped가 없으므로 전역 스타일로 적용됩니다. */
/* App.vue의 .button과 MyButton의 .button 모두에 영향을 주려 하지만,
scoped로 인해 MyButton에는 적용되지 않습니다. */
.button {
background-color: #ccc;
padding: 5px;
}
.global-text {
font-style: italic;
}
</style>
예제 2: v-bind를 사용한 동적 스타일링
JavaScript 상태를 CSS에 직접 바인딩하여 동적으로 색상을 변경합니다.
<script setup>
import { ref } from 'vue';
const textColor = ref('red');
</script>
<template>
<p>이 텍스트의 색상은 아래 버튼으로 바꿀 수 있습니다.</p>
<button @click="textColor = 'green'">Green</button>
<button @click="textColor = 'blue'">Blue</button>
</template>
<style scoped>
p {
/* <script setup>의 textColor 상태를 CSS color 속성에 바인딩 */
color: v-bind(textColor);
font-weight: bold;
transition: color 0.3s;
}
</style>
3. 연습 문제
문제 1: 클래스 바인딩으로 경고 메시지 만들기
- 요구사항:
Alert.vue컴포넌트를 만들어,typeprop에 따라 다른 스타일의 경고 메시지를 보여주세요. - 세부사항:
type('success' 또는 'error')과message를 props로 받습니다.<style scoped>안에.alert,.success,.error세 개의 클래스를 정의합니다.type이 'success'이면 배경은 연한 녹색, 글자는 진한 녹색으로 설정합니다.type이 'error'이면 배경은 연한 빨간색, 글자는 진한 빨간색으로 설정합니다.:class바인딩을 사용하여typeprop 값에 따라.success또는.error클래스를 동적으로 적용합니다.
문제 1 정답 예시
<!-- src/components/Alert.vue -->
<script setup>
defineProps({
type: String,
message: String
});
</script>
<template>
<!--
:class에 객체를 전달하여 조건부로 클래스를 적용합니다.
'alert' 클래스는 항상 적용되고,
type이 'success'이면 'success' 클래스가, 'error'이면 'error' 클래스가 추가됩니다.
-->
<div :class="{ alert: true, success: type === 'success', error: type === 'error' }">
{{ message }}
</div>
</template>
<style scoped>
.alert {
padding: 15px;
margin: 10px 0;
border-radius: 5px;
border: 1px solid;
}
.success {
background-color: #d4edda;
color: #155724;
border-color: #c3e6cb;
}
.error {
background-color: #f8d7da;
color: #721c24;
border-color: #f5c6cb;
}
</style>
문제 2: v-bind로 프로그레스 바 만들기
- 요구사항:
ProgressBar.vue컴포넌트를 만들어,progressprop(0~100)에 따라 너비가 변하는 프로그레스 바를 구현하세요. - 세부사항:
progress라는 숫자 타입의 prop을 받습니다.v-bind를 사용하여progressprop 값을 내부 바(bar)의width스타일에 연결합니다.progressprop 값에 '%' 단위를 붙여서width를 설정해야 합니다. (힌트: 템플릿 리터럴을 사용)
문제 2 정답 예시
<!-- src/components/ProgressBar.vue -->
<script setup>
import { computed } from 'vue';
const props = defineProps({
progress: {
type: Number,
default: 0,
validator: (value) => value >= 0 && value <= 100,
}
});
// v-bind에 복잡한 표현식을 사용하기 위해 computed 속성을 활용할 수 있습니다.
const barWidth = computed(() => `${props.progress}%`);
</script>
<template>
<div class="progress-container">
<div class="progress-bar"></div>
</div>
</template>
<style scoped>
.progress-container {
width: 100%;
height: 20px;
background-color: #eee;
border-radius: 10px;
}
.progress-bar {
height: 100%;
background-color: #42b883;
border-radius: 10px;
/* computed 속성인 barWidth를 width에 바인딩합니다. */
width: v-bind(barWidth);
transition: width 0.5s ease;
}
</style>
반응형
'프론트엔드 > 뷰' 카테고리의 다른 글
| [Vue] 12장: 최종 프로젝트 - 미니 블로그 만들기 (0) | 2025.09.24 |
|---|---|
| [Vue] 11장: 전역 상태 관리 (Pinia) - 컴포넌트의 벽 허물기 (0) | 2025.09.23 |
| [Vue] 10장: Vue Router - 페이지 이동과 목차 만들기 (0) | 2025.09.23 |
| [Vue] 8장: 컴포저블과 반응성 심화 - Vue 능력 끌어올리기 (0) | 2025.09.23 |
| [Vue] 7장: 폼과 `v-model` - 사용자의 입력 받기 (0) | 2025.09.23 |
| [Vue] 6장: 리스트 렌더링 - 동적인 목록 만들기 (0) | 2025.09.23 |
| [Vue] 5장: 조건부 렌더링 - 상황에 맞는 UI 보여주기 (0) | 2025.09.23 |
| [Vue] 4장: 이벤트 핸들링 - 사용자와의 상호작용 (0) | 2025.09.23 |