Quem conversa comigo sobre o assunto, sabe que sou totalmente favorável ao uso de classes e quase obcecado em defendê-las. Existem algumas razões para isso.
Depois do último artigo, algumas pessoas ficaram com dúvidas ou pediram para explicar essa frase:
[..] Como qualquer propriedade, as roles podem ser alteradas via CSS. Você sempre devia usar classes, mas caso você tenha algum problema quanto a isso [..]
Como é um assunto complexo, nada melhor do que um artigo explicando meu ponto de vista.
Performance
Essa é a ordem dos seletores mais rápidos para o mais lentos:
- ID, #header
- Classe, .header
- Tipo, header
- Irmão adjacente, nav + header
- Filho, header > h1
- Descendente, header p
- Universal, *
- Atributo, [type=”text”]
- Pseudo-class / Pseudo-elemento, a:hover .header:before
Sim! Acreditem se quiser. O #ID é o seletor mais rápido. Mas antes de sair substituindo todas as classes dos seus projetos por IDs, saiba que a diferença entre eles é mínima, praticamente imperceptível.
Quer comprovar? Nesse site você pode passar um bom tempo brincando de testar performance CSS.
Porém, estamos falando de seletores únicos. Você não criaria algo como #header-title usando IDs. É mais provável que faça algo como #header h1
Ou mesmo:
Ou se você for maluco:
Sendo que usando uma class, o resultado seria:
Mas quer saber? Só performance não importa
É isso mesmo, não estou louco. Performance por si só, não importa tanto quanto parece. Primeiro porque o impacto do uso indevido de propriedades e transições é muito maior do que seletores. Segundo porque é impossível prever o impacto exato. Temos milhões de dispositivos, navegadores e situações.
O que precisamos nos preocupar é em desenvolver o código mais escalável possível, e a performance se torna uma consequência.
Uso Atomic CSS, então, aproveito da cascata do CSS para reaproveitar ao máximo e modificar componentes quando necessário.
Por performance, essa não é a melhor escolha, já que alguns elementos são aninhados (dica: respeite sempre o limite de três níveis!)
Mas por escalabilidade, considero essa a melhor forma do projeto crescer sem gambiarras e consequentemente não ter perda na qualidade do código e…. Na performance.
Referências
- CSS performance revisited: selectors, bloat and expensive styles
- Writing efficient CSS selectors
- MDN – Writing efficient CSS
Evitando conflito na estilização de elementos
Essa é uma vantagem sensacional de usar classes.
Disclaimer
Quero deixar claro que vou utilizar uma nomenclatura que estou usando nos meus projetos. Me baseei no BEM e em outros modelos. Adotem a nomenclatura que mais gostarem e foquem no contexto dos exemplos.
Observem esse componente retirado do site do Airbnb:
Seguindo a lógica do Atomic CSS, os elementos 1 e 2 seriam títulos pertencentes a um organismo, enquanto os elementos 3, 4 e 5 pertenceriam a uma molécula reaproveitável em diversos organismos.
Vamos imaginar que o nome do organismo é .place e o nome da molécula é .card na seguinte estrutura HTML:
<section class="place"> <div class="place__container"> <h1>Lugares vistos recentemente</h1> <p>Continue de onde parou</p> <a class="card" href="#"> <div class="card__main"> <img src="" alt=""> <h2>Hospedado por Luciana</h2> <p>Rio de Janeiro</p> </div> <p class="price">R$395</p> </a> <a class="card" href="#"> <div class="card__main"> <img src="" alt=""> <h2>Hospedado por Igor</h2> <p>Florianópolis</p> </div> <p class="price">R$200</p> </a> <a class="card" href="#"> <div class="card__main"> <img src="" alt=""> <h2>Hospedado por Loise</h2> <p>Florianópolis</p> </div> <p class="price">R$551</p> </a> </div> </section>
Como eu fazia e dava errado
// A molécula .card h2 ... p ... .price ... img ... // O organismo .place h1 ... p ...
Por que dava errado?
Observem que tanto o .place, quanto o .card têm o elemento <p>. Sendo assim, o elemento <p> do .card, que estava dentro do organismo .place, tinha propriedades que eu não queria que fossem herdadas. Muitas vezes era necessário dar reset nessas propriedades. Ou seja, gambiarra!
Nesse contexto, o .place tem um <h1> e o .card tem um <h2>, mas contextos mudam, e a semântica muda. Ao atrelar o visual em um elemento, jamais poderíamos trocar por outro elemento mais semântico em outra situação.
O .card tem dois <p>, o .price tem um estilo completamente diferente, mas herdaria o estilo do irmão.
O que tentei fazer para evitar que as moléculas herdassem o estilo dos organismos, foi dar estilos apenas para os filhos diretos:
// A mólecula .card > h2 ... > p ... > img ... > .price ... // O organismo .place > h1 ... > p ...
Por que dava errado?
Observem que o .place tem um .place__container e o .card tem um .card__main. Automáticamente, os elementos já não são filhos diretos. Poderíamos fazer com que eles fossem filhos dessas classes intermediarias, mas vocês percebem o quanto o código fica engessado?
Dependemos de que os elementos sejam filhos diretos de outros para que funcionem.
Como eu faço agora?
Lembrando que uso Stylus…
// A molécula .card // Textos &--title ... &--text ... &--price ... &--media ... // Etc &__main ... // O organismo .place // Textos &--title ... &--text ... // Etc &__container ...
E no HTML fica assim:
<section class="place"> <div class="place__container"> <h1 class="place--title">Lugares vistos recentemente</h1> <p class="place--text">Continue de onde parou</p> <a class="card" href="#"> <div class="card__main"> <img class="card--media" src="" alt=""> <h2 class="card--title">Hospedado por Luciana</h2> <p class="card-text">Rio de Janeiro</p> </div> <p class="card--price">R$395</p> </a> <a class="card" href="#"> <div class="card__main"> <img class="card--media" src="" alt=""> <h2 class="card--title">Hospedado por Igor</h2> <p class="card-text">Florianópolis</p> </div> <p class="card--price">R$200</p> </a> <a class="card" href="#"> <div class="card__main"> <img class="card--media" src="" alt=""> <h2 class="card--title">Hospedado por Loise</h2> <p class="card-text">Florianópolis</p> </div> <p class="card--price">R$551</p> </a> </div> </section>
Porque isso da certo!
Nenhuma classe ou elemento vai sobrescrever outro. Nunca.
Se o <h2> virar um <h3> em outro contexto, tudo bem; poderíamos usar <h3 class=”card–title”> e assim por diante…
Não importa dentro de qual elemento as classes estão, elas sempre vão funcionar. Ajuda a manter a sanidade do código, evita precisar apelar para gambiarras e o código fica mais escalável.
Mas e a redundância?
Um dos argumentos usados para customizar os elementos e não as classes são possíveis redundâncias do código, já que que as classes de alguns elementos acabam ficando exatamente igual ao nome da tag.
<header class="header"></header> <footer class="footer"></footer> <main class="main"></main>
Não sei porque isso seria um problema, já que o HTML resolve semântica e o CSS resolve estilo. Mas caso isso incomode, nada te impede de utilizar outros nomes para as classes.
Mas caso você realmente bata o pé e resolva estilizar diretamente os elementos, com certeza vão acontecer alguns problemas quando o projeto crescer. Pode ser que no inicio, você realmente tenha apenas um <header> previsto, mas todos sabemos que essa tag pode ser utilizada mais vezes. Então, todos os estilos adicionados no primeiro elemento seriam herdados pelo segundo, e seria necessário aplicar resets, sujando o código e causando diversos problemas de escalabilidade.
Sinceramente, não tem nenhuma razão para estilizar diretamente um elemento ao invés de estilizar uma classe adicionada nele.
Mas sempre existem as exceções
Usar classes para estilizar os elementos funciona muito bem para componentes, mas claro que não funciona para tudo.
Textos de conteúdo ou de blogs, gerados por um CMS, por exemplo, de maneira nenhuma devem ser customizado com classes (a não ser estilos muito específicos).
Nesse caso, seguindo a lógica do Atomic CSS, teríamos uma molécula chamada .content, com as configurações de tipografia.
.content > h1 ... > h2 ... > h3 ... > h4 ... > h5 ... > p ...
Dessa forma, é possível escrever o texto livremente, adicionar em qualquer lugar do projeto e as configurações vão funcionar.
Plus: não se esqueça dos data-attributes
Mesmo não sendo os campeões de performance, os data-attributes podem ser importantes aliados na construção de um código mais escalável.
Em 2014, escrevi um artigo chamado Sobre Data Atributes e JavaScript em que mostrava as vantagens de usar data-atributes e não classes ou IDs para manipulações no JavaScript.
E esse conceito está cada vez mais consolidado.
Conclusão
As classes são nossas amigas! E são essenciais para a construção de um código mais escalável. Não tenha medo de usá-las, nem de “sujar” o código, isso não vai acontecer se seguir regras de nomenclaturas.
Existem diversas arquiteturas famosas para ajudar nas suas escolhas, como:
O Jean Carlo Emer escreveu o artigo OOCSS, SMACSS, BEM, DRY CSS: afinal, como escrever CSS? em meados de 2014 e continua sendo uma ótima introdução desses conceitos.
É uma sopa de letrinhas e cada uma delas trazem vantagens e desvantagens. O ideal é estudá-las e abstrair os conceitos que mais se adequam ao seu workflow.
Boa sorte nessa jornada!