As lindas pseudo-class
Fui desenvolvedor em uma época terrível. Tempos em que era necessário usar PNGs transparentes para emular box-shadow e border-radius; tempos em que precisávamos usar hacks para IE6 e IE7 e em que tudo era lento e de difícil manutenção.
Felizmente o CSS evoluiu, e uma das novidades que mais gostei nos últimos anos foram as pseudo-class. Provavelmente, as pseudo-class mais conhecidas sejam as :nth-child(), :last-child e :first-child.
Só para contextualizar, no passado para fazer uma tabela com cores alternadas era preciso fazer isso aqui:
<table> <tr class="even"> </tr> <tr class="odd"> </tr> </table>
E agora basta fazer isso:
tr { background: #fff; } tr:nth-child(odd) { background: #eee; }
Sem classe extra, sem nada. Limpo e bonito!
Mas tenho certeza que vocês já viram um milhão de artigos falando dessas pseudo-class mais conhecidas. E mesmo que muita gente também conheça e use o :not(), achei que ele merecia um artigo falando só dele.
O fodástico :not() [2]
Poucas coisas me deixam tão agoniado no CSS do que propriedades sendo resetadas. É tão frustrante que bolei um jeito de usar as Media Queries evitando que isso acontecesse, muito antes dessa técnica ficar famosa.
Sério, não faz sentido nenhum resetar propriedades. Se você precisou resetar, ela simplesmente não deveria existir dentro daquele escopo (mas claro, sempre há as exceções).
E o :not() se torna um aliado sensacional para nos ajudar nessa missão.
Exemplos
Sabe aquela li cheia de bordas e margens que deixa o layout feio no último elemento?
Muita gente faz algo assim:
li border-bottom 1px solid #eee margin-bottom 2rem padding-bottom 2rem &:last-child border-bottom 0 margin-bottom 0 padding-bottom 0
Olhem essas três propriedades sendo resetadas. Muuito feio, né?
Agora observem a elegância com que o :not() resolve isso:
li &:not(:last-child) border-bottom 1px solid #eee margin-bottom 1rem padding-bottom 1rem
Quer que determinado estilo seja adicionado em todos os elementos, mas não em uma classe especifica?
p:not(.foo) font-size 2rem
Ou o inverso disso: que o estilo seja adicionado em uma classe, mas não em um elemento especifico.
.title:not(h2) color $brand-primary
E tem mais…
Também é possível usar o :not() combinado com outras pseud-class.
Quer que o elemento tenha um comportamento caso ele seja o último filho, mas não se ele for ao mesmo tempo o primeiro?
.btn:last-child:not(:first-child) align-self flex-end
Quer negar dois elementos?
.title:not(h2):not(h3) color $brand-primary
Quer que o :hover e o :focus só funcionem se o elemento não tiver a classe .active?
.btn:hover:not(.active), .btn:focus:not(.active) ...
Quer que o elemento tenha determinadas propriedades apenas se não estiver vazio?
.foo:not(:empty) ...
Quer combinar com pseudo-selectors?
Pegue a classe .title apenas se ela não for um h2 e o .header não estiver ativo?
.header:not(.active) + .main .title:not(h2) ...
O céu é o limite.