Boas práticas em classname no CSS
Introdução
Se você é um desenvolvedor, seja especializado em back-end ou front-end, é provável que já tenha sentido aquele "receio" ao mexer com o CSS. Afinal, quem nunca estilizou uma parte específica da aplicação e acabou vendo os estilos adicionados "vazarem" para outros elementos inesperadamente?
Esse problema é mais comum do que se imagina, mas a boa notícia é que há uma solução prática e eficiente para evitá-lo. A chave está na utilização das classnames em CSS. Elas são ferramentas poderosas que permitem separar a estilização de elementos, além de servirem como seletor para aplicar estilos específicos.
O grande desafio está em escolher nomes adequados e semânticos para essas classnames. Muitas vezes, ao criar nossas classes, não damos a devida atenção à semântica dos nomes utilizados. Como resultado, acabamos com conflitos e, consequentemente, esse "vazamento" indesejado de estilos ocorre.
Mas não se preocupe! Com algumas boas práticas e um pouco de cuidado ao nomear suas classes, é possível evitar esses problemas e tornar a estilização mais confiável.
O modelo BEM
Quando falamos sobre estilização e organização de código CSS, o modelo BEM (Block Element Modifier) se mostra uma ferramenta incrivelmente importante e útil. Ele nos permite separar pequenas partes da aplicação em componentes distintos, proporcionando uma abordagem mais estruturada e fácil de dar manutenção. Vamos entender melhor como esse modelo funciona na prática.
Ao pensarmos em componentes, visualizamos elementos que fazem parte de um contexto específico e que podem ser dinâmicos, ou seja, capazes de se adaptar e modificar seu estilo conforme necessário. O modelo BEM é especialmente eficiente para lidar com essa dinamicidade.
A sigla BEM é composta pelas iniciais de três conceitos fundamentais:
- B - Block (Bloco): Representa o componente em si, uma parte maior e independente da aplicação que pode conter vários elementos internos.
- E - Element (Elemento): São as partes menores e individuais que compõem o bloco. Eles estão sempre associados ao bloco ao qual pertencem e não têm significado ou funcionalidade quando usados isoladamente.
- M - Modifier (Modificador): São as variações dos blocos ou elementos, responsáveis por alterar seu estilo ou comportamento. Eles nos permitem reutilizar estilos básicos em diferentes contextos.
Aplicação demo
A aplicação que será utilizada contém apenas um textfield para simplificar. As tecnologias utilizadas são: React, Typescript e node-sass. Temos um simples componente de TextField. Analisando este componente, podemos perceber que ele já é um bloco, ou seja, já contém alguns elementos internos (label e o input). Dessa forma, um possível nome de classe que represente esse bloco está no código abaixo.
Link da aplicação: https://codesandbox.io/s/name-conventions-class-css-0yc985
1.textfield-container {
2}
1// src/components/TextField/index.tsx
2import { InputHTMLAttributes } from "react";
3import "./styles.scss";
4
5interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
6 errorMessage?: string;
7 label?: string;
8}
9
10export function TextField({ name, label, errorMessage, ...props }: InputProps) {
11 return (
12 <div className="textfield-container">
13 ...
14 </div>
15 );
16}
17No código acima temos uma div com classeName textfield-container. Como podemos identificar o modelo BEM neste caso? O nosso bloco está identificado como textfield-container. Neste caso não foi necessário utilizar um elemento e nem modificador(Modifiers). Se você escreve muito código JavaScript ou Typescript, escrever variáveis em camelCase é uma prática comum. O problema é que essa forma de nomenclatura não é adequada para CSS. Uma forma adequada seria usar strings delimitadas por hífen. Esta é uma convenção de nomenclatura CSS bastante padrão. É sem dúvida mais legível. Além disso, é consistente com os nomes das propriedades CSS.
1/* Adequado */
2.textfield-container {}
3
4/* Não adequado */
5.textfieldContainer {}1/* src/components/TextField/styles.scss */
2.textfield-container {
3 display: flex;
4 flex-direction: column;
5}
6
7.textfield-item__name {
8 margin-top: 8px;
9 padding: 5px 10px;
10 border-radius: 8px;
11
12 &.--error {
13 border: 1px solid red;
14 }
15}
16
17.textfield-message__error {
18 color: red;
19}Observe que temos uma nova classename chamada textfield-item__name apresenta um bloco textfield-item e um elemento, que neste caso é o __name que se refere ao input para capturar o nome do usuário. Além disso, possuí também um modifier --error caso esse componente de TextInput tenha alguma mensagem de erro a ser mostrada.
1import { InputHTMLAttributes } from "react";
2import "./styles.scss";
3
4interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
5 errorMessage?: string;
6 label?: string;
7}
8
9export function TextField({ name, label, errorMessage, ...props }: InputProps) {
10 return (
11 <div className="textfield-container">
12 {!!label && (
13 <label className="textfield-label" htmlFor={name}>
14 {label}
15 </label>
16 )}
17 <input
18 {...(label ? { id: name } : {})}
19 className={`textfield-item__name ${errorMessage && "--error"}`}
20 type="text"
21 {...props}
22 />
23 {!!errorMessage && (
24 <span className="textfield-message__error">{errorMessage}</span>
25 )}
26 </div>
27 );
28}
29Alguns comentários
Perceba que os nomes escolhidos para as classnames estão de acordo com o contexto em que estão inseridas. Dessa forma, até certo ponto, conseguiremos evitar o vazamento de estilos para outras partes da aplicação. Além disso, conseguimos também tornar nosso componente mais dinâmico com os modifiers. Os modifiers contém um prefixo com dois hifens seguidos, por exemplo, --error.
Temos algumas ferramentas que valem muito a pena serem utilizada desde o início do projeto. O styled-components é uma dessa ferramentas e também o css-modules que permitem um isolamento melhor de seletores com classenames.
Um detalhe muito importante é que a escolha de nomes para classenames vai de acordo com a sua equipe. Quando entramos em um projeto em andamento devemos seguir o padrão que já está sendo implementado.