Posso ter vários: before pseudo-elementos para o mesmo elemento?

116

É possível ter vários :beforepseudos para o mesmo elemento?

.circle:before {
    content: "\25CF";
    font-size: 19px;
}
.now:before{
    content: "Now";
    font-size: 19px;
    color: black;
}

Estou tentando aplicar os estilos acima ao mesmo elemento usando jQuery, mas apenas o mais recente é aplicado, nunca os dois.

ChrisOdney
fonte

Respostas:

94

No CSS2.1, um elemento só pode ter no máximo um de qualquer tipo de pseudoelemento a qualquer momento. (Isso significa que um elemento pode ter um :beforee um :afterpseudo-elemento - ele simplesmente não pode ter mais de um de cada tipo.)

Como resultado, quando você tem várias :beforeregras correspondendo ao mesmo elemento, todas elas se propagam em cascata e se aplicam a um único :beforepseudoelemento, como acontece com um elemento normal. Em seu exemplo, o resultado final se parece com este:

.circle.now:before {
    content: "Now";
    font-size: 19px;
    color: black;
}

Como você pode ver, apenas a contentdeclaração que tem a precedência mais alta (como mencionado, a que vem por último) terá efeito - o resto das declarações são descartadas, como é o caso com qualquer outra propriedade CSS.

Esse comportamento é descrito na seção Seletores do CSS2.1 :

Pseudo-elementos se comportam como elementos reais em CSS, com as exceções descritas abaixo e em outros lugares.

Isso implica que os seletores com pseudoelementos funcionam da mesma forma que os seletores para elementos normais. Isso também significa que a cascata deve funcionar da mesma maneira. Estranhamente, CSS2.1 parece ser a única referência; nem css3-selectors nem css3-cascade mencionam isso de forma alguma, e resta saber se isso será esclarecido em uma especificação futura.

Se um elemento pode corresponder a mais de um seletor com o mesmo pseudo-elemento, e você deseja que todos eles se apliquem de alguma forma, você precisará criar regras CSS adicionais com seletores combinados para que possa especificar exatamente o que o navegador deve fazer nesses casos. Não posso fornecer um exemplo completo incluindo a contentpropriedade aqui, uma vez que não está claro, por exemplo, se o símbolo ou o texto deve vir primeiro. Mas o seletor de que você precisa para esta regra combinada é .circle.now:beforeou .now.circle:before- o seletor que você escolher é a preferência pessoal, pois os dois seletores são equivalentes, é apenas o valor da contentpropriedade que você precisa para definir você mesmo.

Se você ainda precisa de um exemplo concreto, veja minha resposta a esta pergunta semelhante .

A especificação do conteúdo css3 legado contém uma seção sobre a inserção de vários ::beforee ::afterpseudo-elementos usando uma notação compatível com a cascata CSS2.1, mas observe que esse documento específico está obsoleto - não foi atualizado desde 2003 e ninguém o fez implementou esse recurso na última década. A boa notícia é que o documento abandonado está sendo reescrito ativamente sob o disfarce de css-content-3 e css-pseudo-4 . A má notícia é que o recurso de múltiplos pseudoelementos não pode ser encontrado em nenhuma das especificações, provavelmente devido, novamente, à falta de interesse do implementador.

BoltClock
fonte
12
No caso dado, se um elemento pertencer à classe circlee à classe now, ambas as regras se aplicam ao :beforepseudoelemento do elemento, mas o CSS normal implica que apenas uma das contentconfigurações pode ter efeito (por regras normais em cascata). A questão é que contentnão se acumula.
Jukka K. Korpela
Acontece que esta pergunta que respondi vários meses depois é uma duplicata desta. Desde então, mesclei a maior parte das informações da outra resposta, que basicamente expande tudo o que @Jukka disse acima, nesta porque está recebendo muito mais tráfego, além de vir primeiro.
BoltClock
1
Após 13 anos, o rascunho css-content-3 foi finalmente atualizado . A seção de pseudo-elementos foi definitivamente removida em favor de css-pseudo-4, que não permite múltiplos ::beforenem ::afterpseudo-elementos.
Oriol
@Oriol: 12 anos, na verdade. o FPWD de css-pseudo-4 foi introduzido no ano passado, momento em que o css-content-3 já havia sido atualizado para apontar para a nova especificação.
BoltClock
@BoltClock O rascunho do editor css-content-3 em drafts.csswg.org foi atualizado há algum tempo, mas o rascunho de trabalho em w3.org ainda era o de 2003 até recentemente. Eu ainda tinha algumas esperanças ...
Oriol
31

Se o seu elemento principal tiver alguns elementos filho ou texto, você pode fazer uso dele.

Posicione seu elemento principal relativo (ou absoluto / fixo) e use ambos: antes e: depois posicionado em absoluto (na minha situação tinha que ser absoluto, não sei sobre o seu).

Agora, se você quiser mais um pseudo-elemento, anexe um absoluto: antes a um dos filhos do elemento principal (se você tiver apenas texto, coloque-o em um intervalo, agora você tem um elemento), que não é relativo / absoluto / fixo .

Este elemento começará a agir como se seu dono fosse o seu elemento principal.

HTML

<div class="circle">
    <span>Some text</span>
</div>

CSS

.circle {
    position: relative; /* or absolute/fixed */
}

.circle:before {
    position: absolute;
    content: "";
    /* more styles: width, height, etc */
}

.circle:after {
    position: absolute;
    content: "";
    /* more styles: width, height, etc */
}

.circle span {
    /* not relative/absolute/fixed */
}

.circle span:before {
    position: absolute;
    content: "";
    /* more styles: width, height, etc */
}
HydraOrc
fonte
2
Embora a resposta selecionada seja precisa, essa foi uma solução alternativa viável para o meu caso. Consegui simular vários elementos psuedo sem a necessidade de adicionar mais nós ao DOM!
matt.kauffman23
@ matt.kauffman23 então, você poderia dizer como você simulou?
BbIKTOP
1
@BbIKTOP desculpe, acabei de ver seu comentário. No meu caso, eu estava trabalhando em um modal que sempre teve filhos, então terminei com algo como:.modal:first-child:before { …
matt.kauffman23
@ matt.kauffman23 Para se lembrar de um detalhe como esse depois de mais de 6 anos, você tem uma ótima memória!
ChrisOdney
1

Resolvi isso usando:

.element:before {
    font-family: "Font Awesome 5 Free" , "CircularStd";
    content: "\f017" " Date";
}

Usando a família de fontes "font awesome 5 free" para o ícone, e depois, temos que especificar a fonte que estamos usando novamente porque se não fizermos isso, o navegador usará a fonte padrão (times new roman ou algo parecido isto).

Keko Perera
fonte