Alura > Cursos de Front-end > Cursos de React > Conteúdos de React > Primeiras aulas do curso React: utilizando CSS Modules e Tailwind para estilização de componentes

React: utilizando CSS Modules e Tailwind para estilização de componentes

Conhecendo estilos CSS no React - Apresentação

Apresentando o curso e o instrutor

Sejam bem-vindos a mais este curso de React na Alura. Eu sou Vinicios Neves, e estou aqui para ajudar nesta jornada de estilização de aplicativos React. Se já possuímos conhecimento prévio de React, compreendemos o funcionamento dos componentes e temos familiaridade com JSX, vamos prosseguir nesta jornada.

Explorando a estilização em aplicativos React

A primeira etapa será entender o estado da arte e o panorama de estilização de aplicativos React. Vamos explorar a principal diferença ao pensar e organizar os estilos de um site tradicional em comparação com componentes React.

Conhecendo as opções de estilização

Vamos primeiro entender com o que precisamos nos preocupar e conhecer as possíveis opções. Vamos explorar as diversas maneiras de estilizar aplicativos React, mas nos aprofundaremos em duas delas: CSS Modules e Tailwind CSS. Vamos construir o Poupaapp utilizando essas duas tecnologias, o que nos permitirá compará-las. No final, poderemos decidir qual delas preferimos.

Encorajando a prática e o aprendizado

O curso está repleto de desafios, então, se desejarmos não apenas aprender, mas também praticar, nos arriscar e nos desafiar, estamos no lugar certo. Esperamos que todos estejam tão animados quanto nós para começar a criar o Poupaapp. Estaremos aguardando no próximo vídeo e prometemos que não sairemos daqui. Vamos criar o Poupaapp e aprender sobre CSS Modules e Tailwind CSS. Vamos começar?

Conhecendo estilos CSS no React - Estlizando apps React

Iniciando a discussão sobre estilização no React

Vamos iniciar nossa discussão sobre a estilização no React. Precisamos entender que, ao criar componentes, o paradigma de estilização é diferente. O que isso significa? Não devemos mais pensar em páginas globais ou em blocos de páginas, mas sim em componentes reutilizáveis. Para que um componente seja 100% reutilizável, devemos ter cuidado com elementos externos ou outros componentes que possam afetá-lo, como ocorre no CSS tradicional.

Quando estilizamos um site para a web, geralmente temos um arquivo global, como styles.css. Às vezes, conseguimos dividir isso em arquivos menores, separados por contexto, mas, ainda assim, todo CSS é, por padrão, global. Isso nos obriga a ter cuidado com seletores amplos. Por exemplo, se selecionarmos uma tag, todas as tags selecionadas terão aquele estilo aplicado. Assim, a estilização e os elementos que podem afetar uma parte da aplicação, ou seja, o componente, ficam espalhados pelo código.

Analisando exemplos de conflitos de estilo

Se analisarmos um exemplo na tela, como o que trouxemos, temos uma classe, um seletor .card, .card-title e .card-description, e o HTML correspondente do lado esquerdo. Imagine que estamos criando um card, algo genérico, mas se outra pessoa criar um seletor .card sem cuidado, ou se a base de código for grande demais para ser lida, haverá conflitos. Teremos estilos conflitantes, o que dificultará a depuração. Portanto, o paradigma de CSS global não funciona bem com aplicações React.

Aqui está um exemplo de como isso pode ser implementado em HTML e CSS:

<div class="card">
    <h2 class="card-title">Título</h2>
    <p class="card-description">Descrição...</p>
</div>

<div class="card">
    <h2 class="card-title">Título</h2>
    <p class="card-description">Descrição...</p>
</div>

<div class="card">
    <h2 class="card-title">Título</h2>
    <p class="card-description">Descrição...</p>
</div>
.card {
    background: white;
    padding: 20px;
}

.card-title {
    font-size: 18px;
}

.card-description {
    font-size: 14px;
}

Explorando a estilização de componentes React

Podemos ter estilos globais, como definir uma fonte padrão ou aplicar uma fonte específica em toda a aplicação, definir o tamanho de fonte base ou cores que serão usadas globalmente. Isso é tranquilo. No entanto, quando falamos de estilização de componentes, o caminho é diferente. E é sobre esses caminhos diferentes que vamos falar agora.

No caso de componentes React, devemos pensar em quais cuidados tomar ao estilizar componentes, e não uma página inteira. Um componente deve ser autocontido, ou seja, ele mesmo gerencia seu estilo. Ele pode reagir ao estado e ter estilos diferentes baseados em uma prop (propriedade) passada, mas, via de regra, a não ser que haja uma boa exceção, o próprio componente cuida do seu estilo.

Planejando e codificando componentes autossuficientes

Por exemplo, um botão pode ter um fundo colorido normal, ser um botão outline (com fundo transparente e apenas uma borda), ou ser um botão com ícone. Podemos controlar esses estilos através de props, sem reestilizá-lo a cada uso. A ideia é que ele seja autossuficiente. Se, ao planejar e codificar um componente, percebemos que as props são muitas ou complexas, talvez seja melhor dividir o componente em partes menores. Isso facilita a manutenção e a vida útil do componente, reduzindo o risco de causar um bug.

Ao analisar um componente, como o exemplo do card, podemos planejar um CSS específico para ele, aplicando o className no estilo tradicional que já vimos em cursos anteriores. Quais cuidados devemos ter? Ao importar estilos.card.css, mesmo que esteja separado em uma pasta relacionada a um componente específico, ele ainda é global. Esses estilos podem vazar para outras partes da aplicação se não tivermos cuidado. Devemos evitar seletores muito genéricos, como title, header, footer, card. Quanto menos genéricos formos, mais difícil será conflitar o estilo sem querer.

Estruturando um componente Card em React

Aqui está um exemplo de como podemos estruturar um componente Card em React:

// Card.jsx
import './estilos.card.css';

function Card({ title, children }) {
    return (
        <div className="card">
            <h2 className="card-title">{title}</h2>
            <div className="card-body">{children}</div>
        </div>
    );
}

Explorando técnicas de estilização no React

Falamos bastante sobre CSS tradicional e global, mas o React oferece várias ferramentas para escolhermos como aplicar estilo na aplicação. Vamos explorar essas técnicas. Primeiro, o CSS tradicional, que já mencionamos. O CSS é global, e fazemos um import para utilizá-lo. O cuidado necessário é que o estilo é global e pode vazar para outros componentes. Devemos usar convenções de nomenclatura e técnicas para evitar colisões e vazamentos indesejados.

Por exemplo, temos um style.css, importamos e está feito. O próprio Vite já sabe lidar com isso. Outra opção é o estilo inline. Isso significa abrir uma propriedade style no HTML e aplicar o estilo como se fosse JavaScript. Isso funciona bem quando queremos variar muito o estilo baseado em uma prop e outras condições.

Aplicando estilos inline em componentes

Com isso, o que ganhamos? O estilo não vaza, mas precisamos tomar cuidado, pois isso pode crescer de forma desorganizada. Vamos evitar colisões por um lado, mas isso pode gerar outros tipos de problemas. Trouxemos um exemplo para analisarmos. Nesse cenário, temos o componente botão, que possui definido o background-color, a cor, o padding, entre outros. Note que, apesar de os nomes das propriedades serem muito parecidos com o que temos no CSS, eles serão ligeiramente diferentes. Por exemplo, background-color se torna backgroundColor, com "C" maiúsculo. O VS Code possui um autocomplete muito bom para esse tipo de situação, facilitando a alteração sem medo de errar o nome de uma propriedade.

Aqui está um exemplo de como podemos aplicar estilos inline em um componente Button:

function Button() {
    return (
        <button style={{
            backgroundColor: 'blue',
            color: 'white',
            padding: '10px' }}>
            Clique aqui
        </button>
    );
}

Utilizando CSS Modules para escopo local

O que mais temos aqui? CSS Modules. Ele é muito parecido com o estilo e o paradigma do CSS tradicional, porém, resolve um dos nossos grandes problemas: o escopo local. O que significa escopo local? Significa que o CSS de um componente não vai vazar para os outros, permanecendo bem definido. Escolhemos quais classes vamos usar, mas o próprio CSS Modules faz um trabalho para evitar colisões de nome. Ele aplica alguns ajustes, e o que será compilado no final não é a classe que colocamos, mas algo gerado pelo módulo. Isso gera nomes únicos, e começamos a importar os estilos como se fossem um objeto JavaScript. No exemplo que trouxemos, do lado esquerdo, temos o CSS normal, com um ponto botão e os estilos dentro, e um ponto botão hover, um pseudo-seletor. Quando olhamos para o componente, estamos importando styles de Botao.module.css, como se fosse um módulo CSS. Na hora de aplicar, chamamos o className e usamos styles.botao. Em vez de passar uma string, estamos passando uma propriedade de um objeto JavaScript. Isso resolve problemas de conflitos de estilos, vazamento de estilos, colisão de nomes, entre outros.

Aqui está um exemplo de como podemos usar CSS Modules em um componente Botão:

.botao {
    background-color: #0070f3;
    color: white;
    padding: 10px 16px;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-weight: bold;
}

.botao:hover {
    background-color: #0059c1;
}
import styles from './Botao.module.css'

export default function Botao({ texto }) {
    return <button className={styles.botao}>{texto}</button>
}

Explorando CSS em JS e Utility First

O que mais temos? CSS em JS. É muito parecido com o conceito de usar JavaScript para compilar. Qual é o paradigma, a ideia desse CSS em JS? O próprio JSX conterá o estilo, eliminando a separação do arquivo CSS. O JSX será autossuficiente, preparado para ser dinâmico e reativo ao estado. Quando o estado muda, o estilo reflete essa alteração, evitando problemas de vazamento de CSS e colisão de nomes. O exemplo que trouxemos é o styled-components. Note que ele possui uma sintaxe específica, onde fazemos styled.button, usando um template string. O styled.button é uma função, e passamos para essa função essa string. O próprio styled-components sabe como lidar com isso. Detalhe: o styled-components está depreciado. A pessoa que mantinha o styled-components identificou que o uso estava caindo e optou por não manter mais. Porém, isso não muda a quantidade de aplicações que já utilizam essa abordagem. Vale a pena conhecer e entender como funciona. Em regra, parece muito com CSS tradicional, mas tudo está dentro do JSX.

Aqui está um exemplo de como podemos usar styled-components:

import styled from 'styled-components';

const Button = styled.button`
    background: ${props => props.primary ? 'blue' : 'gray'};
    color: white;
`;

<Button primary>Clique aqui</Button>

O que mais temos aqui? Utility First. O que queremos dizer com Utility First? Em vez de escrevermos arquivos CSS, usamos classes predefinidas por uma biblioteca, aplicando qualquer estilo CSS que aplicaríamos normalmente. A ideia é que isso vai direto no componente, evitando a necessidade de criar arquivos CSS em excesso, aumentando a produtividade. No entanto, há uma curva inicial alta. Isso significa que, para pegarmos o ritmo e entendermos como funciona, leva tempo. Com tudo isso, é importante cuidar da organização do nosso código, pois quando começamos a ter estados que variam com base em props, a situação pode se complicar. No exemplo que trouxemos, estamos usando classes do Tailwind. Note que temos classes como bg-blue-500, que define o background, text-white, que define a cor do texto como branca, px-4, que define o padding horizontal como 4, e py-2, que define o padding vertical como 2. Estamos usando pequenas classes, seguindo as convenções da biblioteca escolhida, como o Tailwind. O próprio Tailwind traduz e lida com isso, preparando a aplicação para produção.

Aqui está um exemplo de como podemos usar classes do Tailwind:

<button className="bg-blue-500 text-white px-4 py-2">
    Salvar
</button>

Concluindo a discussão sobre estilização no React

Era isso que queríamos discutir, oferecendo um panorama. Neste curso, vamos nos especializar em duas dessas alternativas. Vamos falar mais sobre CSS Modules e praticar, e depois, na sequência, abordaremos o Tailwind e, obviamente, praticaremos também. Esse era o objetivo da conversa: mostrar o estado da arte dos estilos CSS dentro de um aplicativo React. Agora, estamos prontos, com a bagagem bem definida, para continuar nossos estudos e aplicar os estilos na nossa aplicação. Vamos lá? Estamos esperando na sequência.

Utilizando o CSS Modules - Entendendo o CSS Modules

Introduzindo o conceito de CSS Modules

Vamos prosseguir com nossos estudos e falar um pouco mais sobre CSS e módulos. Agora é o momento de respirarmos profundamente para fazermos um mergulho mais aprofundado. Antes de aprendermos como implementar, é importante entender por que essa técnica existe e qual foi o contexto que levou ao seu desenvolvimento. Vamos segurar a ansiedade para colocar a mão no código, pois já já faremos isso. Primeiro, vamos falar sobre CSS Modules.

Observando nossos slides, vemos que o CSS tradicional é global por padrão. Quando temos uma classe, como .botao, qualquer elemento em qualquer lugar da página que possua essa classe terá o estilo aplicado. Isso pode levar a conflitos de estilos ou colisões de nomes, onde aplicamos um estilo sem querer, resultando em bugs de tamanho ou cor que não desejamos. Precisamos então depurar, entender de onde vem o problema e ajustá-lo para que tudo fique correto. Esse é o problema que enfrentamos no dia a dia.

Exemplificando problemas do CSS tradicional

Para ilustrar, vamos ver um exemplo de como o CSS tradicional pode ser aplicado:

/* botao.estilos.css */
.botao {
  background: red;
}

E como isso seria utilizado em um componente React:

import './botao.estilos.css'

const Botao = ({ children }) => {
  return (
    <button className="botao">
      {children}
    </button>
  )
}

O primeiro ponto é que, sem querer, podemos afetar um elemento. Se não tomarmos cuidado, os nomes de classe podem virar uma bagunça. Isso não significa que não há solução; existem técnicas para lidar com isso, que estão disponíveis no material de apoio para quem quiser entender mais sobre essas técnicas. No entanto, se não tomarmos cuidado, a desorganização é inevitável. Precisamos seguir uma convenção para evitar esse tipo de comportamento.

Apresentando a solução com CSS Modules

A situação se complica em projetos grandes, com equipes numerosas, tornando-se cada vez mais desafiador manter essa abordagem sem perder muito tempo corrigindo problemas que deveriam ser simples. Enquanto o CSS é global por padrão, o CSS Modules é local por padrão, evitando vazamentos. Não precisamos nos preocupar com colisões de nomes, pois podemos criar uma classe .botao várias vezes sem medo, já que o CSS Modules gerencia isso.

Vamos ver como o CSS Modules resolve esse problema. Primeiro, criamos um arquivo CSS Module:

/* Botao.module.css */
.botao {
  background-color: blue;
}

E importamos esse módulo no nosso componente:

import styles from './Botao.module.css'

export function Botao({ children }) {
  return <button className={styles.botao}>
    {children}</button>
}

Explicando o funcionamento dos CSS Modules

No exemplo de código, vemos que é muito simples usar CSS Modules. Importamos um arquivo CSS como se fosse um objeto JavaScript e passamos um styles.botao, que referencia o seletor no arquivo Botao.module.css. Nesse cenário, temos segurança, pois não alteramos a cor, tamanho ou espaçamento de um elemento sem querer. Os componentes são isolados e mais fáceis de manter, pois são autocontidos. Mesmo que cometamos um erro, afetaremos apenas o componente específico em questão.

Quando utilizamos CSS Modules, é importante dar os devidos créditos aos criadores, Glen Maddern e Mark Dalgleish. O CSS Modules surgiu em 2015 e não foi criado do nada; inicialmente, utilizava algumas funcionalidades do Webpack para alcançar o mesmo resultado. Hoje, ele é suportado por padrão por ferramentas como Webpack, Vite (que é o que vamos usar), Parcel, entre outras. Antes, era necessário realizar um trabalho adicional para fazê-lo funcionar, mas agora, ao utilizarmos o Vite, por exemplo, ele já funciona por padrão, sem a necessidade de implementações ou instalações adicionais.

Detalhando o processo de build e isolamento

O que acontece por debaixo dos panos é que, ao aplicarmos estilos em um arquivo CSS, como botao.css, o CSS Modules cria um objeto que representa esses estilos. Ele faz um mapeamento do nome do seletor que utilizamos para a classe que o CSS Module gerou. Quando compila e transforma isso, o resultado é algo como botao___abc123, onde abc123 é um exemplo de hash. Isso garante que cada seletor e classe seja único, evitando conflitos de nome. O CSS Modules utiliza um pseudo-seletor CSS, :local, para isolar o CSS, garantindo que ele não vaze.

Para ilustrar, veja como o CSS é transformado durante o processo de build:

/* Antes do build */
.botao { ... }

/* Depois da build */
.Botao_botao__abc123 { ... }

E o objeto JavaScript que representa esses estilos:

// e o objeto JS:
const estilos = {
  botao: 'Botao_botao__abc123'
}

Concluindo com a aplicabilidade dos CSS Modules

O CSS Modules não foi criado apenas para React; ele também funciona com Vue, Svelte e até mesmo em aplicações vanilla, desde que utilizemos um bundler como Webpack ou Vite para lidar com essa transformação.

Agora que entendemos o contexto, a origem e o funcionamento do CSS Modules, vamos voltar ao slide onde analisamos o processo. Temos um arquivo CSS com seletores, um objeto JavaScript que o CSS Modules monta para nós, e o resultado da compilação. Essa é a mágica que acontece por debaixo dos panos, permitindo que colhamos todos os benefícios proporcionados pelo CSS Modules.

Já discutimos bastante, e agora é hora de colocar a mão no código. Vamos iniciar uma aplicação do zero, implementar uma página inteira usando essa estratégia e, enquanto implementamos, discutiremos boas práticas de estilização dentro do ecossistema do React. Nos vemos no próximo vídeo.

Sobre o curso React: utilizando CSS Modules e Tailwind para estilização de componentes

O curso React: utilizando CSS Modules e Tailwind para estilização de componentes possui 219 minutos de vídeos, em um total de 40 atividades. Gostou? Conheça nossos outros cursos de React em Front-end, ou leia nossos artigos de Front-end.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Escolha a duração do seu plano e aproveite até 44% OFF

Conheça os Planos para Empresas