Nesses últimos anos usando Vue como meu framework favorito, acabei esbarrando em várias pessoas que acreditavam que a única forma de se estilizar um componente seria utilizando CSS dentro da tag do próprio arquivo
.vue
. Algumas pessoas até relataram não gostar de Vue unicamente por esse motivo!
Então, pra esclarecer um pouco mais esse assunto "nebuloso", vem comigo ver as diferentes abordagens de estilização de componentes Vue.
Sumário
Estilos globais
Estilos escopados com scoped
Estilos escopados com CSS Modules
Quando usar cada um?
Estilos globais
Como o próprio nome diz, os estilos globais ficam disponíveis pra toda a aplicação e normalmente são importados no arquivo main.ts
na pasta /src
do seu projeto.
Quando você inicia uma aplicação Vue, um arquivo global já vem configurado e importado:
import './assets/main.css'
Você pode criar quantos arquivos globais quiser e importá-los diretamente no seu main.ts
. Ou você pode importar seus arquivos globais em um único arquivo .css
(ou .scss
, .less
, etc.) e importar esse único arquivo no seu main.ts
:
// assets/styles.scss
@import "base/reset";
@import "base/variables";
@import "base/typography";
@import "components/buttons";
@import "components/table";
@import "pages/home";
// main.ts
import './assets/styles.scss'
❓ "Mas eu não preciso ter uma tag no meu arquivo
.vue
?
👉🏽 Não! O modelo SFC do Vue apenas exige que você tenha o template
que será renderizado, sendo o script
e o style
opcionais.
<template>
to="/">Home
to="/about" class="txt-tomato">About
template>
Se seu projeto é pequeno e/ou se você usa estratégias como Atomic Design ou BEM, utilizar estilos globais vai te atender muito bem. No entanto, é necessário ter cuidado, pois um CSS global mal gerenciado pode "vazar" estilos entre componentes e páginas.
Voltar ao Sumário
Estilos escopados com scoped
Um projeto Vue já vem por padrão com uma tag no arquivo
App.vue
. O uso do atributo scoped
significa que o CSS é escopado, ou seja, todo o CSS declarado dentro da tag será exclusivo do componente.
⚠️ O uso da tag
sem o atributo
scoped
aplica os estilos de forma global, então cuidado aí com esse detalhe!
<template>
/>
to="/">Home
to="/about" class="example">About
template>
<style scoped>
.example {
color: darkorchid;
}
style>
<template>
class="example">You did it!
template>
Criamos uma classe example
apenas no arquivo App.vue
. No entanto, usamos essa mesma classe também em outro arquivo, o HelloWorld.vue
.Como resultado, a cor darkorchid
será aplicada apenas ao App.vue
, mesmo que HelloWorld.vue
seja seu componente-filho.
❓ E se eu quisesse reaproveitar essa classe no componente-filho? Preciso declará-la em um CSS global?
👉🏽 Bom, essa é uma das opções... Mas o atributo scoped
do Vue permite que possamos tornar essas classes "profundas" com o seletor :deep()
, permitindo que você consiga passar estilos...
Scoped de pai pra filho
<template>
class="example">
/>
to="/">Home
to="/about" class="example">About
template>
<style scoped>
/* E aqui usamos o seletor :deep() para herança do componente-filho */
.example :deep(.example) {
color: darkorchid;
}
style>
<template>
class="example">You did it!
template>
Mas se você quiser mesmo seguir a linha de deixar essa classe global a partir de um determinado componente, o scoped
também disponibiliza o seletor :global()
:
<style scoped>
:global(.example) {
color: darkorchid;
}
style>
Assim, disponibilizamos a classe .example
para qualquer outro componente da aplicação. Pessoalmente, evito o uso de :global()
, preferindo manter os estilos globais no main.css
pra melhor organização e legibilidade.
⚠️ Evite usar
:global()
ao máximo, pois esse seletor aumenta a especificidade do estilo, se sobrepondo a estilos escopados.
Existe também a possibilidade de usar duas tags em um componente, deixando um com estilos globais e outro com estilos escopados (mas aí também já é demais 😅).
<style>
/* estilos globais */
style>
<style scoped>
/* estilos locais */
style>
✒️ Para saber mais: CSS Isolado (Vue Docs)
Voltar ao Sumário
Estilos escopados com CSS Modules
Existem duas formas distintas de usar CSS Modules com Vue:
- usando a tag
dentro do próprio componente (SFC); ou
- criando um arquivo
.module.css
(ou.module.scss
,.module.less
, etc.) e importando-o no componente.
CSS Modules (SFC)
Usar CSS Modules dentro do próprio componente é muito simples: basta usar a tag . A partir disso, todo CSS criado dentro desse escopo será acessado no
através do objeto
$style
. Bora pro exemplo:
<template>
:class="$style.example">You did it!
template>
<style module>
.example {
color: tomato;
}
style>
Aqui estamos usando o atributo module
e acessando a classe example
no template
através do objeto $style
. Então, apesar de também termos uma classe example
em App.vue
, elas vão ter seus estilos independentes:
Essa abordagem permite ter um código mais harmônico, mantendo lógica e estilos de um componente isolados em um único arquivo. Além disso, facilita pro desenvolvedor ver a relação entre template e estilos.
No entanto, o reuso dessas classes é dificultado, além de poder tornar o seu arquivo muito extenso, um possível problema que podemos resolver com...
CSS Modules em arquivo separado
... que melhora a separação de responsabilidades, além de facilitar o reuso dos estilos em outros componentes, favorecendo também o uso de CSS mais complexo.
Pra testarmos, vamos criar um arquivo em nossa pasta /assets
chamado example.module.css
:
.example {
color: yellow;
}
Esse arquivo deverá ser importado em todos os componentes onde você quiser usar a classe example
. Vamos importá-la no nosso HelloWorld.vue
:
<script setup lang="ts">
// Importando o CSS Module como styles -->
import styles from '@/assets/example.module.css'
script>
<template>
:class="styles.example">You did it!
template>
<style module>
/* Mesmo com esse módulo declarado no arquivo, a cor "tomato" da
classe 'example' daqui não será atribuída */
.example {
color: tomato;
}
style>
Quando o CSS Module é processado, cada classe de cada módulo recebe um hash único no build final, garantindo que não haverá conflitos com outras classes, mesmo que tenham o mesmo nome em outros arquivos:
E o mais legal de usar CSS Modules com Typescript? Autocomplete! 🤩
✒️ Para saber mais: Módulos de CSS (Vue Docs)
Voltar ao Sumário
Quando usar cada um?
Estilos globais sempre vão existir em uma aplicação. Utilize-os para elementos de uso geral, como tipografia, cores e espaçamentos personalizados.
Use Scoped quando:
- Tiver componentes simples e isolados;
- Preferir uma sintaxe mais simples;
- Não precisar de acesso programático às classes.
Use CSS Modules quando:
- Precisar acessar classes via JavaScript;
- Quiser compartilhar estilos entre componentes;
- Trabalhar em projetos maiores com muitos desenvolvedores.
O que é importante entender é que não existe uma solução única quando se trata de estilização no Vue. Cada método tem um propósito e um contexto de aplicação:
Estilos globais são usados pra definir a base visual do seu projeto, enquanto o scoped
ajuda a manter a organização e evitar conflitos em componentes específicos. Já os CSS Modules são type-safe quando usados com TypeScript, o que podemos considerar um ponto a mais pra experiência do desenvolvedor em projetos maiores e mais complexos.
O Vue oferece flexibilidade total quanto à estilização. E em vez de ficar limitado a usar apenas a tag no seu arquivo
.vue
, você pode combinar diferentes abordagens de acordo com as suas necessidades e gostos.
Além disso, você pode usar libs CSS-in-JS, como Vanilla Extract e Vue Styled Components, ou libs de UI, como Vuetify e Prime Vue, ou até integrar com os famosos Tailwind e Bootstrap 💚
Agora, partiu criar apps bonitões. Um xero!