Bài 15: Scoped CSS trong VueJS và các kĩ thuật liên quan
Mình đã cập nhật lại tất cả các bài với các thay đổi ở hiện tại ở năm 2024: Vue 3, Vite, Laravel 11x,...
Cập nhật gần nhất: 09/06/2024
Hello các bạn lại là mình đây 👋
Tiếp tục với series học VueJS với Laravel của mình, ở bài trước mình đã hướng dẫn các bạn cách xử lý các sự kiện khi người dùng tương tác bằng chuột hoặc bàn phím với VueJS, các bạn có thể xem lại ở đây. Ở bài này chúng ta sẽ tìm hiểu về một trợ thủ rất đắc lực trong quá trình phát triển các ứng dụng Vue nữa đó là thiết lập phạm vi cho CSS (scoped CSS) trong Vue nhé 🚀🚀
Scoped CSS là gì?
Tưởng tượng cảnh các bạn làm việc ở một project lớn, nhiều module, nhiều người cùng làm một lúc, và CSS cứ bị override liên tục bởi người này người khác, và ta cứ phải mất công nghĩ tên CSS class sao cho độc nhất, và thậm chí là phải dùng tới !important
để tăng độ ưu tiên, việc nay làm cho code của ta rất rối rắm và dẫn tới performance có thể kém hơn. Đó là lúc ta cần tới Scoped CSS
Scoped CSS trong Vue 3 cho phép bạn áp dụng các style chỉ cho component hiện tại mà không ảnh hưởng đến các component khác. Điều này giúp tránh xung đột style và làm cho code của bạn dễ bảo trì hơn.
Cú pháp cơ bản
Để sử dụng Scoped CSS, bạn chỉ cần thêm thuộc tính scoped
vào thẻ <style>
:
<template>
<div class="scoped-style">
Scoped CSS Example
</div>
</template>
<script setup>
</script>
<style scoped>
.scoped-style {
color: blue;
}
</style>
Khi chạy lên các bạn sẽ thấy rằng mỗi một component Vue sẽ generate cho ta một cái id độc nhất và được gắn vào các thẻ trong component của ta:
Ở trên ta thấy rằng Vue đã thêm vào data-v-424539e3
vào trong các thẻ HTML mà ta có, từ đó tận dụng CSS attribute selector để tránh việc đụng độ CSS xảy ra
Lợi ích của Scoped CSS
Dưới đây mình tổng hợp những lợi ích của Scoped CSS:
- Tránh xung đột style: Scoped CSS giúp tránh xung đột style giữa các component khác nhau, làm cho style của bạn an toàn và độc lập.
- Dễ dàng bảo trì: với Scoped CSS, bạn có thể dễ dàng tìm thấy và cập nhật các style liên quan đến một component cụ thể mà không ảnh hưởng đến các component khác.
- Tính Modular hóa cao: Scoped CSS giúp tăng tính modular hóa cho ứng dụng của bạn, làm cho các component trở nên tự quản lý và dễ dàng tái sử dụng.
Vọc vạch
Scoped CSS cơ bản
Trong ví dụ này, style chỉ áp dụng cho component hiện tại.
<template>
<div class="scoped-basic">
Đây là ví dụ về Scoped CSS cơ bản.
</div>
</template>
<script setup>
</script>
<style scoped>
.scoped-basic {
background-color: lightblue;
padding: 10px;
border-radius: 5px;
}
</style>
Scoped CSS với child components
Scoped CSS cũng áp dụng cho các component con, nhưng bạn có thể ghi đè nó nếu cần.
<template>
<div class="parent">
<TestComponent />
</div>
</template>
<script setup>
import TestComponent from './TestComponent.vue';
</script>
<style scoped>
.parent {
color: red;
}
</style>
<template>
<div class="child">
Đây là component con.
</div>
</template>
<script setup>
</script>
<style scoped>
.child {
font-weight: bold;
}
</style>
Ở trên ta thấy rằng color
của component con đã ghi đè cha, và các thẻ của component con có ID của cha + thêm ID của riêng nó
Scoped CSS với deep selector
Từ cha mà ta muốn áp dụng (ghi đè) style cho các phần tử sâu hơn trong component con, bạn có thể sử dụng deep selector >>>
hoặc :deep
:
<template>
<div class="parent">
<TestComponent />
</div>
</template>
<script setup>
import TestComponent from './TestComponent.vue';
</script>
<style scoped>
.parent :deep(.child) {
color: green;
}
/* .parent >>> .child {
color: green;
} */
</style>
SCSS,SASS,...
Ta cũng có thể dùng SCSS nếu muốn nhé, Vue support hết (quá được 🤩🤩):
<template>
<div>
<div class="scss-style">
Đây là ví dụ về v-bind() trong SCSS.
<div class="test">Test</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const textColor = ref('blue');
</script>
<style scoped lang="scss">
.scss-style {
color: v-bind(textColor);
border-radius: 5px;
transition: color 0.5s;
.test {
color: red
}
}
</style>
CSS Modules
CSS Modules là một giải pháp khác để quản lý style trong Vue 3. Với CSS Modules, mỗi class name được định danh duy nhất, giúp tránh xung đột style và duy trì tính modular hóa.
Cách sử dụng CSS Modules
Để sử dụng CSS Modules, bạn chỉ cần thêm thuộc tính module
vào thẻ <style>
:
<template>
<div :class="$style.moduleStyle">
Đây là ví dụ về CSS Modules.
</div>
</template>
<script setup>
</script>
<style module>
.moduleStyle {
background-color: lightcoral;
padding: 10px;
border-radius: 5px;
}
</style>
Khi chạy lên ta sẽ thấy rằng Vue đã generate cho ta 1 class name là duy nhất, không dựa vào HTML data attribute
như scoped CSS nữa, kiểu này thì giống như 1 class bình thường mà ta vẫn hay dùng, chỉ là tên của nó là duy nhất
Và ta để ý rằng ở phần <template>
ta phải dùng 1 biến đặc biệt là $style
và truyền đúng tên class ở thẻ <style>
mà ta mong muốn
chú ý rằng nếu tên class của bạn mà như sau
.module-style
, thì phía template để truy cập tới ta dùng$style['module-style']
Import CSS Modules Trong Script
Bạn cũng có thể import CSS Modules từ 1 file css ngoài vào trong phần <script>
:
<template>
<div :class="styles.moduleStyle">
Đây là ví dụ về CSS Modules.
</div>
</template>
<script setup>
import styles from './ExampleComponent.module.css';
</script>
.moduleStyle {
background-color: lightcoral;
padding: 10px;
border-radius: 5px;
}
chú ý rằng tên file các bạn phải có đuôi .module.css
mới được nhé
Sử dụng v-bind()
trong CSS
Vue 3 cho phép bạn sử dụng v-bind()
để bind các giá trị động vào CSS trực tiếp trong thẻ <style scoped>
. Điều này giúp bạn dễ dàng thay đổi các thuộc tính CSS dựa trên các biến trong component.
Chú ý rằng hiện tại
v-bind()
chỉ support CSS, nên nếu các bạn viếtv-bind()
vào những đoạn CSS lồng nhau khi code SCSS là sẽ lỗi đó nhé
Binding biến JS vào CSS
Bạn có thể sử dụng v-bind()
để bind các biến từ script vào CSS:
<template>
<div class="dynamic-style">
Đây là ví dụ về v-bind() trong CSS.
</div>
</template>
<script setup>
import { ref } from 'vue';
const bgColor = ref('purple');
</script>
<style scoped>
.dynamic-style {
background-color: v-bind(bgColor);
color: white;
}
</style>
Như ta thấy Vue đã tạo inline CSS variable cho ta và tham chiếu tới nó ở class dynamic-style
, giá trị của CSS variable cũng là duy nhất để tránh trùng lặp
Sử dụng v-bind()
với các biểu thức phức tạp
Bạn cũng có thể sử dụng v-bind()
với các biểu thức phức tạp hơn:
<template>
<div class="complex-style">
Đây là ví dụ về v-bind() với biểu thức phức tạp.
</div>
</template>
<script setup>
import { ref } from 'vue';
const bgColor = ref('orange');
const baseFontSize = ref(16);
</script>
<style scoped>
.complex-style {
background-color: v-bind(bgColor);
color: white;
font-size: v-bind(`calc(${baseFontSize}px + 2vmin)`);
}
</style>
Khi chạy lên ta sẽ thấy như sau:
Ở đây ta thấy Vue tạo ra CSS var nom khá là kì, nhưng hợp lệ đó nha 🤣. Ta có thể lia chuột vào tên biến sẽ thấy giá trị thực:
Cập nhật giá trị của v-bind()
Trong ví dụ này, khi giá trị của biến reactive state thay đổi, CSS sẽ thay đổi theo.
<template>
<div>
<div class="reactive-style">
Đây là ví dụ về v-bind() với reactive state.
</div>
<button @click="toggleColor">Thay đổi màu</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const bgColor = ref('blue');
function toggleColor() {
bgColor.value = bgColor.value === 'blue' ? 'red' : 'blue';
}
</script>
<style scoped>
.reactive-style {
background-color: v-bind(bgColor);
color: white;
transition: background-color 0.5s;
}
</style>
Ở đây ta thấy khi bấm nút, thì biến CSS thay đổi theo giá trị của bgColor
là 1 reactive state:
Nếu ta để ý sẽ thấy rằng tất cả các biến CSS được tạo ra sẽ inline vào thẻ cha của chúng, và các class mà tham chiếu tới biến đó sẽ inherit
cái biến đó:
Ở trên ta thấy rằng 2 thẻ
<div>
cha mà chứa classtest
vàreactive-style
đều được Vue tạo chung các CSS variable giống như nhau
Sử dụng v-bind()
trong CSS Modules
Bạn cũng có thể sử dụng v-bind()
trong CSS Modules để bind các giá trị động vào các lớp CSS:
<template>
<div :class="$style.moduleStyle">
Đây là ví dụ về CSS Modules với v-bind().
</div>
</template>
<script setup>
import { ref } from 'vue';
const textColor = ref('coral');
</script>
<style module>
.moduleStyle {
color: v-bind(textColor);
padding: 10px;
border-radius: 5px;
}
</style>
Khi nào nên dùng Scoped CSS Và CSS Modules?
Scoped CSS | CSS Modules |
---|---|
- Khi bạn cần cách ly style của một component khỏi các component khác. - Khi bạn làm việc trong một dự án lớn với nhiều component độc lập. |
- Khi bạn muốn tránh xung đột tên lớp hoàn toàn. - Khi bạn cần chia sẻ các style giữa các component mà không sợ bị ghi đè. |
Các vấn đề liên quan và giải pháp
Performance | Global Styles |
---|---|
Scoped CSS có thể tạo ra nhiều selectors hơn trong DOM, điều này có thể ảnh hưởng đến hiệu suất. Để giải quyết, ta có thể sử dụng CSS Modules hoặc TailwindCSS để tối ưu hóa style của mình. | Nếu cần áp dụng style toàn cục, bạn có thể sử dụng các file CSS global hoặc các thư viện CSS như Bootstrap. |
Thực tế thì 2 vấn đề này mình cũng khá ít gặp trong thực tế, và vẫn dùng scoped CSS cho hầu hết mọi dự án
Kết bài
Scoped CSS và CSS Modules trong Vue 3 là các công cụ mạnh mẽ giúp bạn quản lý style một cách hiệu quả và độc lập. Từ việc tránh xung đột style, tăng tính modular hóa, đến việc dễ dàng bảo trì, Scoped CSS và CSS Modules mang lại nhiều lợi ích cho quá trình phát triển ứng dụng của bạn.
Cám ơn các bạn đã theo dõi, ở bài sau mình sẽ hướng dẫn các bạn cách chúng ta gọi API từ backend Laravel nhé (oh finally, tên series là học ..... với Laravel
mà đến tận bài này mới ra đc 1 bài ). Nếu có gì thắc mắc các bạn để lại dưới phần comment nhé ^^!
All rights reserved