Imagem mostra um grupo de artistas em posando para a foto em frente a uma casa de shows em uma época antiga

Contando elementos com nth-last-child

Acredito que não há dúvidas de que o Design Responsivo veio pra ficar e que não está mais apenas na moda. Mais do que ficar pensando em tamanhos específicos de telas ou em mobile e tablet, minha opinião é que esqueçamos isso. Com a variedade de smartphones diferentes que existem hoje, acho difícil separarmos o que é mobile do que é tablet ou desktop. Um exemplo disso é o Viewport sizes que traz uma lista completa com os tamanhos dos viewports de vários dispositivos diferentes. Mas isso é só a minha opinião.

Acredito que o principal é fazer com que o seu conteúdo, independente de resolução ou tela, seja acessível pro usuário; afinal, e muitas vezes esquecemos disso, é exatamente isso que importa: que o usuário encontre a informação que procura. Quem aqui nunca entrou em algum site pra procurar algo, e por um motivo xis não conseguiu acessar aquela informação, seja por ela não estar disposta de forma correta, ou por algum problema cross-browser e por aí vai.

Adaptando seu conteúdo

Pra mim, uma das principais vertentes que o design responsivo trouxe foi a priorização de volta no conteúdo. Mais que qualquer coisa, devemos focar na informação que deve ser passada e garantir que ela seja acessada independente de dispositivo ou resolução.

E, nesse caminho das pedras, uma hora ou outra teremos que trabalhar com um tipo de conteúdo que pode variar. Eaí Bino, como fazer? Nesses dias cai numa situação desse tipo e vi que há diversos caminhos para resolver esse problema.

O problema do conteúdo variável

Jogo rápido: imaginem uma lista disposta horizontalmente com 5 itens. Podemos pensar então que em uma determinada resolução cada item teria 20% de largura da lista e em um determinado breakpoint cada item ficaria com a largura total da lista (ou se formos pelo lado do mobile first, cada item teria por padrão a largura inteira da lista e, só a partir de um determinado breakpoint que ele ficaria com a nova largura de 20%).

.list li {
  width: 20%;
  float: left;
}

@media screen and (max-width: 768px) {
  width: 100%;
  float: none;
}

Ou, se pensarmos numa abordagem mobile first (apenas a encargo de exemplo):

@media screen and (min-width: 768px) {
  width: 20%;
  float: left;
}

Beleza, matou! Mas, e se a quantidade de itens variar? Por exemplo entre 3 e 5? Me deparei com uma situação semelhante alguns dias atrás e meu primeiro pensamento foi: antes da renderização dos elementos na página eu vejo quantos itens tem ali e, dependendo do resultado, coloco uma classe na lista. Algo mais ou menos assim:

.list li {
  float: left;
}

.list-3 li { width: 33.3%; }
.list-4 li { width: 25%; }
.list-5 li { width: 20%; }

Resolve o problema? Resolve. Mas nem sempre temos essa opção, de contar por exemplo com o lado do servidor para nos retornar o número de itens. Aí nesse caso, uma outra solução seria via JavaScript, seguindo o mesmo pensamento: contar os elementos e de acordo com o resultado, aplicar uma classe na lista.

E tem ainda uma outra coisa: nesse caso nem estamos pensando ainda em breakpoints e variações de resolução. Paramos ainda no primeiro ponto que é simplesmente que o seu conteúdo esteja bem disposto numa resolução qualquer; pra depois disso, podermos pensar na estratégia a se seguir.

Dando uma pesquisada na Barsa da internet vi que daria pra resolver esse problema apenas com o velho e bom CSS.

Contando os elementos

A idéia básica é através do CSS, descobrirmos quantos itens estão presentes na lista e a partir daí aplicarmos a largura correta para cada item. Mas, eaí? Como contar, certo? Podemos usar a magia negra dos pseudo seletores pra nos ajudar com isso.

O cara nth-last-child

Esse brother aí nada mais faz do que contar o elemento partindo do seu último item. Então se quiséssemos, por exemplo selecionar o segundo item da lista, mas iniciando a contagem do fim, faríamos algo assim:

.list li:nth-last-child(2) {
  border: solid 1px red;
}

Uma representação bem simples do item selecionado:

  • item 1
  • item 2
  • item 3
  • item 4 (selecionado)
  • item 5

Tendo idéia de como selecionar um elemento, podemos estabelecer a seguinte linha de raciocínio:

  • temos que saber exatamente quantos itens temos, chegando no primeiro elemento da lista.
  • selecionar todos os elementos irmãos.

Vamos por partes. Conseguimos matar o primeiro item utilizando o que vimos no exemplo anterior. Então, partindo de uma lista de 5 itens, poderíamos fazer algo assim:

.list li:nth-last-child(5),
.list li:nth-last-child(5) ~ li {
  width: 20%;
  // \o/
}

E shaaazam! Conseguimos teoricamente contar quantos elementos temos na lista. Agora é só aplicarmos as demais variações.

.list li:nth-last-child(3),
.list li:nth-last-child(3) ~ li { width: 33.3%; }

.list li:nth-last-child(4),
.list li:nth-last-child(4) ~ li { width: 25%; }

.list li:nth-last-child(5),
.list li:nth-last-child(5) ~ li { width: 20%; }

Fiz um exemplo rápido no CodePen com o que falamos aqui.

See the Pen Quantity queries by Raphael Fabeni (@raphaelfabeni) on CodePen.

Algumas referências e links legais:

Gostou? Escrevi alguma groselha? Quer melhorar? Abra uma issue mencionando o post e vamos conversar.

See all posts...