Como são calculados os pontos na especificidade do CSS

124

Pesquisando a especificidade, me deparei com este blog - http://www.htmldog.com/guides/cssadvanced/specificity/

Ele afirma que a especificidade é um sistema de pontuação para CSS. Diz-nos que os elementos valem 1 ponto, as classes valem 10 pontos e os IDs valem 100 pontos. Além disso, também diz que esses pontos são totalizados e o valor total é a especificidade do seletor.

Por exemplo:

body = 1 point
body .wrapper = 11 pontos
body .wrapper #container = 111 pontos

Portanto, usando esses pontos, espero que os seguintes CSS e HTML resultem no texto sendo azul:

#a {
    color: red;
}

.a .b .c .d .e .f .g .h .i .j .k .l .m .n .o {
  color: blue;
}
<div class="a">
  <div class="b">
    <div class="c">
      <div class="d">
        <div class="e">
          <div class="f">
            <div class="g">
              <div class="h">
                <div class="i">
                  <div class="j">
                    <div class="k">
                      <div class="l">
                        <div class="m">
                          <div class="n">
                            <div class="o" id="a">
                              This should be blue.
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Por que o texto é vermelho quando 15 classes equivalem a 150 pontos em comparação com 1 ID, que é igual a 100 pontos?

Aparentemente, os pontos não são apenas totalizados; eles são concatenados. Leia mais sobre isso aqui - http://www.stuffandnonsense.co.uk/archives/css_specificity_wars.html

Isso significa que as classes em nosso seletor = 0,0,15,0OR 0,1,5,0?

(meus instintos me dizem que é o primeiro, como sabemos aparência especificidade do seletor de ID como este: 0,1,0,0)

Sam
fonte
Aqui está algo estranho também: stackoverflow.com/questions/25565928/...
Armel Larcier

Respostas:

137

A resposta de Pekka é praticamente correta e provavelmente a melhor maneira de pensar sobre o assunto.

No entanto, como muitos já apontaram, a recomendação do CSS do W3C afirma que "concatenar os três números abc (em um sistema numérico com uma base grande) fornece a especificidade". Então, o nerd em mim só tinha que descobrir quão grande é essa base.

Acontece que a "base muito grande" empregada (pelo menos pelos 4 navegadores mais usados * ) para implementar esse algoritmo padrão é 256 ou 2 8 .

O que isto significa é que um estilo especificado com 0 ids e 256 de classe-nomes irá sobrepor-se um estilo especificado com apenas 1 id. Eu testei isso com alguns violinos:

Portanto, existe efetivamente um "sistema de pontos", mas não é a base 10. É a base 256. Eis como funciona:

(2 8 ) 2 ou 65536, vezes o número de IDs no seletor
+ (2 8 ) 1 ou 256, vezes o número de nomes de classes no seletor
+ (2 8 ) 0 ou 1, vezes o número de tags- nomes no seletor

Isso não é muito prático para exercícios de retaguarda para comunicar o conceito.
Provavelmente é por isso que os artigos sobre o assunto estão usando a base 10.

***** [Opera usa 2 16 (veja o comentário de karlcow). Alguns outros mecanismos seletores usam infinito - efetivamente, nenhum sistema de pontos (veja o comentário de Simon Sapin).]

Atualização, julho de 2014:
Como o Blazemonger apontou no início do ano, os navegadores webkit (chrome, safari) agora parecem usar uma base superior a 256. Talvez 2 16 , como o Opera? O IE e o Firefox ainda usam 256.

Faust
fonte
34
Importante: observe que o número 256 não está na especificação . Assim, esta resposta descreve um detalhe de implementação (reconhecidamente útil).
Matt Fenwick
6
Não apenas 256 não está na especificação como o @MattFenwick disse, mas também varia de acordo com a implementação. Aparentemente, é maior na Opera. No WeasyPrint e no cssselect, é "infinito": uso uma tupla de números inteiros em vez de um único inteiro.
Simon Sapin
3
@Faust ópera usa 16 bits em vez de 8
karlcow
4
Essa resposta tem uma descrição mais prática do que a resposta de Pekka, para ser sincero. Basicamente, o que o @Matt Fenwick diz: o que você está descrevendo é uma implementação prática da especificação. Uma falha nesse sentido, mas não em algo que deva ser feito, seja por autores ou implementadores.
BoltClock
7
256 parece insuficiente nas versões atuais do webkit (Chrome e Safari), reforçando ainda mais o argumento de @ MattFenwick.
Blazemonger
28

Boa pergunta.

Não sei ao certo - todos os artigos que consigo encontrar evitam o exemplo de várias classes, por exemplo, aqui -, mas presumo que, quando se trata de comparar a especificidade entre um seletor de classe e um ID , a classe é calculada com um valor de 15apenas, não importa quão detalhado seja.

Isso corresponde à minha experiência em como a especificidade se comporta.

No entanto, deve haver algum empilhamento de classes porque

.a .b .c .d .e .f .g .h .i .j .k .l .m .n .o

é mais específico que

.o

a única explicação que tenho é que a especificidade das classes empilhadas é calculada apenas entre si, mas não com os IDs.

Atualização : eu meio que peguei agora. Não é um sistema de pontos, e as informações sobre as classes com peso de 15 pontos estão incorretas. É um sistema de numeração de 4 partes muito bem explicado aqui .

O ponto de partida é de 4 figuras:

style  id   class element
0,     0,   0,    0

De acordo com a explicação do W3C sobre a especificidade , os valores de especificidade para as regras acima mencionadas são:

#a            0,1,0,0    = 100
classes       0,0,15,0   = ... see the comments

este é um sistema de numeração com uma base muito grande (indefinida?).

Meu entendimento é que, como a base é muito grande, nenhum número na coluna 4 pode superar um número> 0 na coluna 3, o mesmo para a coluna 2, coluna 1 .... Isso está correto?

Eu estaria interessado em saber se alguém com uma melhor compreensão de matemática do que eu poderia explicar o sistema de numeração e como convertê-lo em decimal quando os elementos individuais forem maiores que 9.

Pekka
fonte
Isso é porque está entre .o e .a .b etc. Portanto, eles seriam considerados coletivamente. Mas entre um ID e uma classe, por exemplo: .a e #a, o ID sempre prevalecerá. Suponho que apenas contará entre classes quando não houver um atributo mais avassalador. Por exemplo, classe passará por cima de elemento e id por cima de classe.
Sphvn
@ Ozaki é o que estou assumindo também, mas contradiz o que o OP está dizendo sobre o sistema de pontos. Deve haver mais em jogo. Eu gostaria de ver as regras por trás disso.
Pekka
Acabamos de perceber que ambos chegamos à mesma conclusão. Excelente trabalho!
Sam
5
Para o lado da matemática, podemos trabalhar na base 16 aqui (porque nenhum dos números individuais excede 15). Então 0,1,0,0 = 0100h = 256 0,0,15,0 = 00f0h = 240 256> 240 para que o seletor de ID ganhe.
Matthew Wilson
1
Sim, você pode pensar em cálculos de especificidade como sendo feitos em um sistema numérico com uma base grande. Eu acho que o termo "concatenar" (também usado nas especificações) é uma descrição muito melhor. (Vim aqui de responder a uma nova questão que acaba por ser um joguete de um presente, figura go ...)
BoltClock
9

O atual Rascunho de Trabalho dos Seletores Nível 4 faz um bom trabalho ao descrever a Especificidade no CSS:

As especificidades são comparadas comparando os três componentes em ordem: a especificidade com um valor A maior é mais específica; se os dois valores A estiverem vinculados, a especificidade com um valor B maior será mais específica; se os dois valores B também estiverem vinculados, a especificidade com um valor c maior é mais específica; se todos os valores estiverem vinculados, as duas especificações são iguais.

Isso significa que os valores A, B e C são completamente independentes um do outro.

15 classes não dão ao seu seletor uma pontuação de especificidade de 150, ele fornece um valor B de 15. Um único valor A é suficiente para superar isso.

Como metáfora, imagine uma família de 1 avô, 1 pai e 1 filho. Isso pode ser representado como 1,1,1 . Se o pai ou mãe tem 15 filhos, isso de repente não faz dele outro pai ( 1,2,0 ). Isso significa que os pais têm uma responsabilidade muito maior do que eles com apenas um filho ( 1,1,15 ). ;)

A mesma documentação também diz:

Devido a limitações de armazenamento, as implementações podem ter limitações no tamanho de A , B ou c . Nesse caso, valores maiores que o limite devem ser fixados nesse limite e não excedidos.

Isso foi adicionado para resolver o problema apresentado na resposta de Faust , em que as implementações de CSS em 2012 permitiram que os valores de especificidade transbordassem entre si.

Em 2012, a maioria dos navegadores implementava uma limitação de 255, mas essa limitação podia exceder. 255 classes tiveram uma especificidade A, B, c de 0,255,0 , mas 256 classes transbordaram e tiveram uma pontuação A, B, c de 1,0,0 . De repente, nosso valor B se tornou nosso valor A. A documentação dos seletores de nível 4 irradia completamente esse problema, afirmando que o limite nunca pode exceder. Com essa implementação, as classes 255 e 256 teriam a mesma pontuação A, B, c de 0,255,0 .

O problema dado na resposta de Faust já foi corrigido na maioria dos navegadores modernos.

James Donnelly
fonte
8

Atualmente, estou usando o livro CSS Mastery: Advanced Web Standards Solutions .

O Capítulo 1, página 16, diz:

Para calcular a especificidade de uma regra, cada tipo de seletor recebe um valor numérico. A especificidade de uma regra é calculada somando o valor de cada um de seus seletores. Infelizmente, a especificidade não é calculada na base 10, mas um número de base alto e não especificado. Isso é para garantir que um seletor altamente específico, como um seletor de ID, nunca seja substituído por muitos seletores menos específicos, como seletores de tipo.

(ênfase minha) e

A especificidade de um seletor é dividida em quatro níveis constituintes: a, b, ce ed.

  • se o estilo for um estilo embutido, a = 1
  • b = o número total de seletores de identificação
  • c = o número de seletores de classe, pseudo-classe e atributo
  • d = o número de seletores de tipo e pseudoelementos

Continua dizendo que você pode fazer o cálculo frequentemente na base 10, mas apenas se todas as colunas tiverem valores menores que 10.


Nos seus exemplos, os IDs não valem 100 pontos; cada um vale [0, 1, 0, 0]pontos. Portanto, um ID supera 15 classes porque [0, 1, 0, 0]é maior do que [0, 0, 15, 0]em um sistema de números de base alta.

Matt Fenwick
fonte
4

Gosto da comparação do ranking de especificidade com a tabela de medalhas dos Jogos Olímpicos (primeiro método de ouro - baseado primeiro no número de medalhas de ouro, depois prata e depois bronze).

Também funciona com sua pergunta (grande número de seletores em um grupo de especificidade). A especificidade considerou cada grupo separadamente. No mundo real, raramente vi casos com mais de uma dúzia de seletores).

Também há uma calculadora de especificidade bastante boa disponível aqui . Você pode colocar seu exemplo (#a e .a .b .c .d .e .f .g .h .i .j .k .l .m .n .o) lá e ver os resultados.

Exemplo da tabela de medalhas dos Jogos Olímpicos Rio 2016 insira a descrição da imagem aqui

rkarczmarczyk
fonte
3

Não acredito que a explicação do blog esteja correta. A especificação está aqui:

http://www.w3.org/TR/CSS2/cascade.html#specificity

Os "pontos" de um seletor de classe não podem ser mais importantes do que um seletor de "id". Simplesmente não funciona assim.

Matthew Wilson
fonte
Como eu disse na minha resposta. ^^ No entanto, faz diferença se você tiver mais do mesmo tipo (elemento, classe, id). Mas isso é bastante óbvio se o quinto diz o vermelho e o terceiro o azul, bem, vou ficar vermelho.
Sphvn
A redação em torno da especificidade provavelmente não mudou muito entre CSS2 e CSS2.1, mas você realmente deve apontar para a especificação CSS2.1 em discussões futuras, uma vez que substitui completamente o CSS2 que, em geral, estava quebrado no momento do lançamento.
Robin Whittleton
1

Eu diria que:

Element < Class < ID

Eu acho que eles só empilham dependendo do que você recebe se for múltiplo do mesmo. Portanto, uma Classe sempre substituirá o elemento e o ID sempre sobre a Classe, mas se estiver abaixo de qual dos 4 elementos em que 3 é azul e 1 é vermelho, será azul.

Por exemplo:

.a .b .c .d .e .f .g .h .i .j .k .l
{
color: red;
}

 .m .n .o
{
color blue;
}

Deve ficar vermelho.

Veja o exemplo http://jsfiddle.net/RWFWq/

"se as quintas disserem vermelho e as três disserem azul, vou ficar vermelha"

Sphvn
fonte