Seletor CSS "(A ou B) e C"?


176

Isso deve ser simples, mas estou tendo problemas para encontrar os termos de pesquisa.
Digamos que eu tenho isso:

<div class="a c">Foo</div>
<div class="b c">Bar</div>

No CSS, como posso criar um seletor que corresponda a algo que corresponda a "(.a ou .b) e .c"?

Eu sei que eu poderia fazer isso:

.a.c,.b.c {
  /* CSS stuff */
}

Mas, supondo que eu tenha que fazer muito esse tipo de lógica, com uma variedade de combinações lógicas, existe uma sintaxe melhor?


Tenha cuidado se precisar dar suporte ao Internet Explorer 6, pois ele ignorará mais de um nome de classe em um seletor de CSS.
fforw

24
Felizmente, para este projeto, posso dizer aos usuários do IE6 para se atualizarem.
Josh

12
Por uma questão de clareza, tento sempre colocar uma nova linha após as vírgulas, ou pelo menos um espaço.
ANeves

2
@ANeves +1 para nova linha. Esta é a melhor abordagem na minha opinião, especialmente ao usar o controle de origem.
Curt

Respostas:


149

existe uma sintaxe melhor?

Não. O oroperador CSS ' ( ,) não permite agrupamentos. É essencialmente o operador lógico de menor precedência nos seletores, então você deve usá-lo .a.c,.b.c.


25

Ainda não, mas existe a :matches()função pseudo-classe experimental que faz exatamente isso:

:matches(.a .b) .c {
  /* stuff goes here */
}

Você pode encontrar mais informações aqui e aqui . Atualmente, a maioria dos navegadores suporta sua versão inicial:any() , que funciona da mesma maneira, mas será substituída por :matches(). Nós apenas temos que esperar um pouco mais antes de usar isso em qualquer lugar (eu certamente o farei).


Não é razoável culpar o IE por não implementar algo em que eles simplesmente nunca pensaram e não estava em nenhum rascunho, para começar. :-moz-any()e :-webkit-any()apareceu muito antes da Mozilla sugerir para os seletores 4 (que antecederam sua encarnação atual como :matches()).
BoltClock

1
É igualmente irracional esperar que qualquer fornecedor implemente um recurso a partir de um rascunho instável, independentemente de quanto tempo o rascunho foi disponibilizado (isso explica o fato de que os seletores 4 permanecem instáveis ​​e praticamente não são implementados mais de três anos após a DPF). .
BoltClock

@BoltClock, eles estavam culpando o IE6 por uma década inteira por coisas que não existiam em 2001. As pessoas só querem culpar alguém.
GetFree

Uma palavra sobre as experimentais é que você não deseja começar a confiar nelas, a menos que seja oficialmente implementado. Embora possa parecer uma ótima solução - a possibilidade de desaparecer o que pessoalmente me impede de implementá-lo em meus projetos. Mesmo acompanhar uma pseudo aula experimental não me faz sentir seguro. Muito provavelmente, ele será usado em mais de um lugar no projeto e, se houver, mais de um onde você o usa - de alguma forma você precisa acompanhar tudo. Você certamente pode ter fallbacks e ainda conseguir, mas isso não soa limpo #
Alexey Shevelyov 12/08/16

eu sou o único que está recebendo um Uncaught DOMException: Failed to execute 'querySelector' on 'Document': ':any(.a .b)' is not a valid selector.erro? 🤔
thomas

12

Se você tem isso:

<div class="a x">Foo</div>
<div class="b x">Bar</div>
<div class="c x">Baz</div>

E você só deseja selecionar os elementos que possuem .xe ( .aou .b), você pode escrever:

.x:not(.c) { ... }

mas isso é conveniente apenas quando você tem três "subclasses" e deseja selecionar duas delas.

Selecionando apenas uma subclasse (por exemplo .a):.a.x

Selecionando duas subclasses (por exemplo .ae .b):.x:not(.c)

Selecionando todas as três subclasses: .x


6
Qualquer cláusula lógica do formulário a or b or c or dé igual not(not(a) and not(b) and not(c) and not(d))a 'ou' é na verdade apenas uma função de conveniência. Em teoria, deve ser possível sobreviver sem ele em todos os casos. No caso do OP (.a or .b) and .c->:not(:not(.a):not(.b)).c
Max Murphy

2
@MaxMurphy Você já testou isso?
Šime Vidas

4
Às cinco horas da manhã, sim! Eu tenho js que cospe a lógica de primeira ordem, com seletores nas folhas, dando resultados como :not(:not([data-status="ACT"]):not([data-status="ISS"]):not([data-status="COR"]))[data-month="08"]. O código ainda não está limpo o suficiente para leitura pública, caso contrário, eu o publicaria. Eu testei no chrome, safari e um telefone Android low-end.
Max Murphy

2
@MaxMurphy Você tem um ótimo argumento, mas acho que você invocou uma definição bastante torturada de "função de conveniência". Tudo o que um computador digital pode fazer pode ser decomposto em portas NAND, mas eu não chamaria o restante da engenharia de software de "um monte de funções de conveniência". As diferenças de grau rapidamente se tornam diferenças de fato de tipo quando construções podem ser combinadas.
Sarah G

1
@MaxMurphy Eu tive dificuldade em descobrir que você estava apenas brincando. :( A pseudo-classe CSS de negação,: not (X), é uma notação funcional que usa um seletor simples X como argumento. Corresponde a um elemento que não é representado pelo argumento. X não deve conter outro seletor de negação . (De Documentação do Mozilla , ênfase minha)
törzsmókus

5

Não. O CSS padrão não fornece o tipo de coisa que você está procurando.

No entanto, você pode querer analisar o LESS e o SASS .

Estes são dois projetos que visam estender a sintaxe padrão do CSS introduzindo recursos adicionais, incluindo variáveis, regras aninhadas e outros aprimoramentos.

Eles permitem que você escreva códigos CSS muito mais estruturados, e qualquer um deles certamente resolverá seu caso de uso específico.

Obviamente, nenhum dos navegadores suporta sua sintaxe estendida (especialmente porque os dois projetos têm sintaxe e recursos diferentes), mas o que eles fazem é fornecer um "compilador" que converte seu código LESS ou SASS em CSS padrão, que você pode implantar no seu site.


Nesse ponto, eu poderia muito bem apenas usar PHP imprimir "Content-type: text / css"
Josh
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.