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 <style>
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 <style>
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.
<!-- Exemplo no App.vue -->
<template>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about" class="txt-tomato">About</RouterLink>
<!-- A classe "txt-tomato" está no CSS global e pode ser utilizada -->
<!-- diretamente no componente -->
</nav>
</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 <style scoped>
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
<style>
sem o atributoscoped
aplica os estilos de forma global, então cuidado aí com esse detalhe!
<!-- App.vue -->
<template>
<div>
<HelloWorld />
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about" class="example">About</RouterLink>
</nav>
</div>
</template>
<style scoped>
.example {
color: darkorchid;
}
</style>
<!-- HelloWorld.vue -->
<template>
<h1 class="example">You did it!</h1>
</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
<!-- App.vue -->
<template>
<!-- Colocamos a classe "example" no elemento-pai -->
<!-- de HelloWorld.vue, no caso, a div -->
<div class="example">
<HelloWorld />
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about" class="example">About</RouterLink>
</nav>
</div>
</template>
<style scoped>
/* E aqui usamos o seletor :deep() para herança do componente-filho */
.example :deep(.example) {
color: darkorchid;
}
</style>
<!-- HelloWorld.vue -->
<template>
<h1 class="example">You did it!</h1>
</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 <style>
em um componente, deixando um com estilos globais e outro com estilos escopados (mas aí também já é demais 😅).
<!-- Em um mesmo arquivo... -->
<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
<style module>
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 <style module>
. A partir disso, todo CSS criado dentro desse escopo será acessado no <template>
através do objeto $style
. Bora pro exemplo:
<!-- HelloWorld.vue -->
<template>
<!-- Acessando a classe com $style -->
<h1 :class="$style.example">You did it!</h1>
</template>
<!-- Declarando o CSS Module -->
<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
:
<!-- HelloWorld.vue -->
<script setup lang="ts">
// Importando o CSS Module como styles -->
import styles from '@/assets/example.module.css'
</script>
<template>
<!-- Acessando a classe com styles -->
<h1 :class="styles.example">You did it!</h1>
</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 <style>
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!
Top comments (6)
Incrível como sempre. Parabéns Angela!!! Caiu como uma luva agora que estou num projeto com Vue hehe XD.
Olha sóóó, vai entrar no Vue World, que massa! Depois me conta como tá sendo a experiência.
Muito obrigada pela visita e pelo comentário, xuxu <3
E eu aqui preso no scoped! Refatoramento vai rolar solto. Obrigado.
Boa, Cledilson! Bora diminuir o tamanho desses componentes, hehe! Obrigada pela visita 💚
Parabéns Angela!!!
Brigadão, Thais! <3