Read it in English

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?

Guy with style


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>

RouterLink apresentando a cor da classe txt-tomato definida no css global

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>

RouterLink apresentando a cor da classe  raw `example` endraw  declarada em CSS escopado e h1 em outro componente ignorando a cor da mesma classe por estar fora do escopo

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>

o RouterLink e h1 em outro componente recebendo a cor da mesma classe com o uso do seletor :deep

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:

RouterLink e h1 em componentes diferentes com mesma classe e resultados distintos

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>

RouterLink recebendo a cor amarela do CSS Module externo em vez do interno

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:

Código Vue compilado no devtools do navegador

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!