Escrever CSS é realmente simples e direto; por que motivo são necessários princípios e práticas recomendadas ao escrever CSS?
À medida que o escopo do projeto aumenta e à medida que o número de pessoas trabalhando no projeto aumenta, os problemas se tornam cada vez mais aparentes e podem causar problemas sérios no futuro. Os problemas de correção podem se tornar mais difíceis, código duplicado, cadeias de substituição complexas e uso de !important
código restante / não utilizado (elementos ou recursos removidos), código difícil de ler etc.
Escrever CSS em nível profissional tornará o código CSS mais sustentável, extensível, compreensível e mais limpo. Vamos examinar os cinco princípios simples e muito eficazes que levarão seu CSS ao próximo nível.
Princípio de nomeação
“Existem apenas duas coisas difíceis na Ciência da Computação: invalidação de cache e nomeação de coisas.” – Phil Karlton
Nomear e estruturar adequadamente seus seletores de CSS é o primeiro passo para tornar seu CSS mais legível, estruturado e mais limpo. Estabelecer regras e restrições em sua convenção de nomenclatura torna seu código padronizado, robusto e fácil de entender.
É por isso que conceitos como BEM (Modificador de Elemento de Bloco) , SMACSS (Arquitetura Escalável e Modular para CSS) e OOCSS (CSS Orientado a Objetos) são populares entre muitos desenvolvedores de front-end.
Princípio de baixa especificidade
Substituir propriedades CSS é muito útil, mas as coisas podem sair de controle rapidamente em projetos mais complexos. A substituição de cadeias pode ficar muito longa e complexa, você pode ser forçado a usar !important
para resolver o problema de especificidade e pode se perder com muita facilidade ao depurar ou adicionar novos recursos.
/* Low-specificity selector */
.card {}
/* High-specificity selectors */
.card .title {}
.blog-list .card img {}
.blog-list .card.featured .title {}
#js-blog-list .blog-list .card img {}
Navegador e especificidade
Um dos benefícios de seguir o princípio de baixa especificidade é o desempenho. Os navegadores analisam o CSS da direita para a esquerda .
Vamos dar uma olhada no seguinte exemplo:
.blog-list .card img {}
Os navegadores analisam o seletor da seguinte maneira:
- Encontre todos os
img
elementos na página - Mantenha os elementos selecionados que são descendentes da
.card
classe - Mantenha os elementos selecionados que são descendentes da
.blog-list
classe
Você pode ver como seletores de alta especificidade afetar o desempenho, especialmente quando precisamos globalmente selecionar elementos genéricos como div
, img
, li
, etc.
Usando o mesmo nível de especificidade
Ao usar seletores de classe CSS de baixa especificidade em combinação com o BEM ou um dos outros princípios de nomeação mencionados na seção anterior, podemos criar um código de desempenho, flexível e compreensível.
Por que usar classes CSS? Queremos manter o mesmo nível de especificidade, manter a flexibilidade e poder direcionar vários elementos. Os seletores de elemento e de identificação não oferecem a flexibilidade de que precisamos.
Vamos reescrever nosso exemplo anterior usando o BEM e mantendo a especificidade baixa.
/* Low-specificity selector */
.card {}
/* Fixed high-specificity selectors */
.card__title {}
.blogList__image {}
.blogList__title--featured {}
.blogList__img--special {}
Você pode ver como esses seletores são simples, compreensíveis e podem ser facilmente substituídos e estendidos, se necessário. E, mantendo-os de baixo nível (uma única classe), garantimos desempenho e flexibilidade ideais.
Princípio DRY
O princípio DRY (não se repita) também pode ser aplicado ao CSS. O código duplicado no CSS pode causar inchaço no código, substituições desnecessárias, reduzir a manutenção, etc. Esse problema pode ser corrigido estruturando o código adequadamente e possuindo documentação de alta qualidade.
O Storybook é uma ótima ferramenta gratuita que permite criar uma visão geral dos componentes de front-end disponíveis e escrever documentação de alta qualidade.
/* Without DRY Princple */
.warningStatus {
padding: 0.5rem;
font-weight: bold;
color: #eba834;
}
.errorStatus {
padding: 0.5rem;
font-weight: bold;
color: #eb3d34;
}
.form-errorStatus {
padding: 0.5rem 0 0 0;
font-weight: bold;
color: #eb3d34;
}
Vamos refatorar o código para que ele siga o princípio DRY.
/* With DRY Principle */
.status {
padding: 0.5rem;
font-weight: bold;
}
.status--warning {
color: #eba834;
}
.status--error {
color: #eb3d34;
}
.form__status {
padding: 0.5rem 0 0 0;
}
Princípio da responsabilidade única
Usando o princípio de responsabilidade única em nosso CSS, podemos garantir que nossas classes CSS sejam facilmente estendidas e substituídas. Vamos dar uma olhada no exemplo a seguir.
.button {
padding: 1rem 2rem;
font-size: 2rem;
border-radius: 0.2rem;
background-color: #eb4934;
color: #fff;
font-weight: bold;
}
.button--secondary {
border-radius: 0;
font-size: 1rem;
background-color: #888;
}
Podemos ver que, se queremos estender a .button
classe .button--secondary
, estamos fazendo muitas substituições para alcançar o que precisamos, quando queremos aplicar apenas uma cor de plano de fundo diferente e manter os estilos padrão.
O problema é que nossa .button
classe está tendo várias funções:
- Define o layout (
padding
) - Define tipografia (
font-size
,font-weight
) - Conjuntos de apresentação (
color
,background-color
,border-radius
)
isso torna muito difícil estender e combinar nossas classes CSS com outras classes CSS. Mantendo isso em mente, vamos usar o BEM e o OOCSS para melhorar nosso CSS.
/* Shared styles */
.button {
padding: 1rem 2rem;
font-weight: bold;
color: #fff;
}
/* Style extensions */
.button--radialBorder {
border-radius: 0.2rem;
}
.button--large {
font-size: 2rem;
}
.button--primary{
background-color: #eb4934;
}
.button--secondary {
background-color: #888;
}
Dividimos nossos button
estilos em várias classes que podem ser usadas para estender a button
classe base . Opcionalmente, podemos aplicar os modificadores e adicionar novos à medida que o design muda ou novos elementos são adicionados.
Princípio Abrir / Fechar
entidades de software (classes, módulos, funções etc.) devem estar abertas para extensão, mas fechadas para modificação.
Já usamos o princípio de abrir / fechar nos exemplos anteriores. Todos os novos recursos e opções precisam ser adicionados por extensão. Vamos dar uma olhada neste exemplo.
.card {
padding: 1rem;
}
.blog-list .card {
padding: 0.5em 1rem;
}
O .blog-list .card
seletor tem alguns problemas em potencial:
- Alguns estilos podem ser aplicados apenas se o
.card
elemento for filho do.blog-list
elemento. - Os estilos são aplicados à força ao
.card
elemento se colocados dentro do.blog-list
elemento, o que pode produzir resultados inesperados e substituições desnecessárias.
Vamos reescrever o exemplo anterior:
.card {
padding: 1rem;
}
.blogList__card {
padding: 0.5em 1rem;
}
Corrigimos o problema com um seletor de classe única. Com esse seletor, podemos evitar efeitos inesperados e não há estilos aninhados condicionais.