Combinando pseudo-elementos CSS, “: after” e “: last-child”

122

Eu quero fazer listas "gramaticalmente corretas" usando CSS. Isto é o que eu tenho até agora:

As <li>tags são exibidas horizontalmente com vírgulas após elas.

li { display: inline; list-style-type: none; }

li:after { content: ", "; }

Isso funciona, mas quero que o "último filho" tenha um ponto final em vez de vírgula. E, se possível, eu gostaria de colocar "e" antes do "último filho" também. As listas que estou criando são geradas dinamicamente, então não posso simplesmente dar uma aula aos "últimos filhos". Você não pode combinar pseudoelementos, mas esse é basicamente o efeito que eu quero alcançar.

li:last-child li:before { content: "and "; }

li:last-child li:after { content: "."; }

Como eu faço isso funcionar?

Derek
fonte
4
você realmente não deveria estar usando css para isso.
Funky Dude
2
Devo concordar um pouco com o Funky Dude. Seria melhor fazer isso no HTML (ou no código abaixo, se for mais do que HTML simples). CSS é para formatação :)
Zyphrax
16
Eu ... pessoalmente, costumo argumentar que, em uma lista, a formatação é uma gentileza, não uma necessidade. Sendo esse o caso, usar CSS permite adições ou remoções mais simples da lista do que usar a codificação html ou do lado do servidor. Mas eu sou estranho assim, às vezes, e, honestamente, sim ... etc) =
David diz para reinstalar Monica
9
E +1 por usar a vírgula de Oxford! :)
Brandon Rhodes
5
+1 para "+1 para vírgula de Oxford". Nunca ouvi falar sobre isso (não sou nativo). Mas a pesquisa rápida do wiki diz que é natural, porque não é usada em muitos idiomas. Engraçado o que se pode aprender questões CSS-pesquisando pilha;)
jakub.g

Respostas:

168

Isso funciona :) (espero que vários navegadores, o Firefox goste)

li { display: inline; list-style-type: none; }
li:after { content: ", "; }
li:last-child:before { content: "and "; }
li:last-child:after { content: "."; }
<html>
  <body>
    <ul>
      <li>One</li>
      <li>Two</li>
      <li>Three</li>
    </ul>
  </body>
</html>

Zyphrax
fonte
2
Um problema semelhante é o caso em que você está separando itens de menu com caracteres de barra vertical. A mesma solução funciona. Porém, o atributo de conteúdo final precisa ser definido como {content: none;} para eliminar o caractere final do canal.
Aridlehoover 19/08/11
2
A ordem também é importante. li:last-child:afterfunciona mas li:after:last-childnão funciona .
precisa
1
Lembre-se de que :last-childnão pertence à especificação CSS3, portanto não é suportado pelo IE8 e versões anteriores.
Cthulhu
23

Eu gosto disso para itens de lista nos elementos <menu>. Considere a seguinte marcação:

<menu>
  <li><a href="/member/profile">Profile</a></li>
  <li><a href="/member/options">Options</a></li>
  <li><a href="/member/logout">Logout</a></li>
</menu>

Eu o denomino com o seguinte CSS:

menu > li {
  display: inline;
}

menu > li::after {
  content: ' | ';
}

menu > li:last-child::after {
  content: '';
}

Isso exibirá:

Profile | Options | Logout

E isso é possível por causa do que Martin Atkins explicou em seu comentário

Observe que no CSS 2 você usaria :after, não ::after. Se você usa CSS 3, use ::after(duas semicolunas) porque ::afteré um pseudoelemento (uma única semicoluna é para pseudo-classes).

Gabriel Hautclocq
fonte
16

Um thread antigo, no entanto, alguém pode se beneficiar com isso:

li:not(:last-child)::after { content: ","; }
li:last-child::after { content: "."; }

Isso deve funcionar no CSS3 e no CSS2 [não testado].

user5341733
fonte
11

Você pode combinar pseudo-elementos! Desculpe pessoal, eu descobri isso sozinho depois de postar a pergunta. Talvez seja menos usado por causa de problemas de compatibilidade.

li:last-child:before { content: "and "; }

li:last-child:after { content: "."; }

Isso funciona muito bem. CSS é meio incrível.

Derek
fonte
12
Este é um pouco do "canto do buscador", mas "último filho" é na verdade uma pseudo- classe , enquanto "antes" e "depois" são pseudo-elementos. A diferença é que uma pseudo-classe é uma restrição adicional a um elemento existente, enquanto um pseudo-elemento é efetivamente um elemento inteiramente novo na árvore de apresentação que foi gerada em CSS e não em HTML. Você pode combiná-los por esse motivo: o last-childé um modificador no lie, depois de selecionar todos os lielementos que são os últimos filhos, você seleciona (e cria implicitamente) um novo elemento antes e depois de cada um.
Martin Atkins
Eu sei que você provavelmente esqueceu por muito tempo esse segmento em particular, mas desde que você mencionou que suas listas eram de tamanho variável, vale ressaltar que, na maioria dos contextos, uma lista com exatamente dois itens não seria correta com uma vírgula em inglês. Em outras palavras, se você quisesse "pão com manteiga". ao invés de "pão e manteiga". - então a maioria das soluções fornecidas aqui estaria incompleta. Eu criei uma maneira de contorná-la e a postei abaixo como resposta, caso isso ajude alguém que ainda esteja olhando tão longe no tópico.
Matt Wagner
6

Apenas para mencionar, no CSS 3

:depois de

deve ser usado assim

::depois de

De https://developer.mozilla.org/de/docs/Web/CSS/::after :

A notação :: after foi introduzida no CSS 3 para estabelecer uma discriminação entre pseudo-classes e pseudo-elementos. Os navegadores também aceitam a notação: depois de introduzidos no CSS 2.

Então deve ser:

li { display: inline; list-style-type: none; }
li::after { content: ", "; }
li:last-child::before { content: "and "; }
li:last-child::after { content: "."; }
Wolfgang Blessen
fonte
3
Todos os navegadores que suportam a ::sintaxe CSS3 de dois pontos duplos também suportam apenas a :sintaxe, mas o IE 8 suporta apenas os dois pontos, portanto, por enquanto, é recomendável usar apenas os dois pontos para melhor suporte ao navegador. ::é o formato mais recente recuado para distinguir pseudo conteúdo de pseudo seletores. Se você não precisar do suporte do IE 8, sinta-se à vontade para usar o dois-pontos. Deste artigo
JohnnyQ 26/07/16
2
O IE 8 não é mais um jogador em termos de padrões do navegador. Não suportado pela Microsoft e não suporta HTML5 ou CSS3 (pseudoelementos, transformações etc.). Eu fazia muito trabalho sobre compatibilidade com versões anteriores, até um ano atrás, voltando ao IE6 / IE7 (via Modernizr.) Percorremos um longo caminho e, se você pretende que seu site apresente sua identidade on-line a longo prazo - sem que isso se torne uma solução míope -, basta considerar a receita que você obteria com alguém que usa o IE8. Nada. Até idosos, 20 anos atrás, estão usando tablets e laptops 2 em 1 agora.
Steven Ventimiglia
2

Adicionando outra resposta a esta pergunta, porque eu precisava exatamente do que @derek estava pedindo e já havia me aprofundado um pouco antes de ver as respostas aqui. Especificamente, eu precisava de CSS que também pudesse explicar o caso com exatamente dois itens de lista, nos quais a vírgula NÃO é desejada. Como exemplo, algumas linhas de autoria que eu queria produzir teriam a seguinte aparência:

Um autor: By Adam Smith.

Dois autores: By Adam Smith and Jane Doe.

Três autores: By Adam Smith, Jane Doe, and Frank Underwood.

As soluções já fornecidas aqui funcionam para um autor e para três ou mais autores, mas negligenciam o caso de dois autores - onde o estilo "Oxford Comma" (também conhecido como estilo "Harvard Comma" em algumas partes) não se aplica - ou seja, não deve haver vírgula antes da conjunção.

Depois de uma tarde de mexer, eu vim com o seguinte:

<html>
 <head>
  <style type="text/css">
    .byline-list {
      list-style: none;
      padding: 0;
      margin: 0;
    }
    .byline-list > li {
      display: inline;
      padding: 0;
      margin: 0;
    }
    .byline-list > li::before {
      content: ", ";
    }
    .byline-list > li:last-child::before {
      content: ", and ";
    }
    .byline-list > li:first-child + li:last-child::before {
      content: " and ";
    }
    .byline-list > li:first-child::before {
      content: "By ";
    }
    .byline-list > li:last-child::after {
      content: ".";
    }
  </style>
 </head>
 <body>
  <ul class="byline-list">
   <li>Adam Smith</li>
  </ul>
  <ul class="byline-list">
   <li>Adam Smith</li><li>Jane Doe</li>
  </ul>
  <ul class="byline-list">
   <li>Adam Smith</li><li>Jane Doe</li><li>Frank Underwood</li>
  </ul>
 </body>
</html>

Ele exibe os bylines como os tenho acima.

No final, eu também tive que me livrar de qualquer espaço em branco entre lielementos, a fim de evitar um aborrecimento: a propriedade inline-block deixaria um espaço antes de cada vírgula. Provavelmente existe um truque decente alternativo para ele, mas esse não é o assunto desta pergunta, então deixarei isso para outra pessoa responder.

Violino aqui: http://jsfiddle.net/5REP2/

Matt Wagner
fonte
2

Para ter algo como Um, dois e três, você deve adicionar mais um estilo css

li:nth-last-child(2):after {
    content: ' ';
}

Isso removeria a vírgula do segundo último elemento.

Código completo

li {
  display: inline;
  list-style-type: none;
}

li:after {
  content: ", ";
}

li:nth-last-child(2):after {
  content: '';
}

li:last-child:before {
  content: " and ";
}

li:last-child:after {
  content: ".";
}
<html>

<body>
  <ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
  </ul>
</body>

</html>

Raj Sharma
fonte
0

Estou usando a mesma técnica em uma consulta de mídia que efetivamente transforma uma lista de marcadores em uma lista embutida em dispositivos menores, pois eles economizam espaço.

Então a mudança de:

  • Item da lista 1
  • Item da lista 2
  • Item da lista 3

para:

Item da lista 1; Item da lista 2; Item da lista 3.

user3064058
fonte
Ele está tentando fazer isso com CSS. Seu método é HTML codificado. Este método é normalmente usado para exibir a Navegação.
precisa saber é o seguinte