Combinaison de pseudo-éléments CSS, ": after" the ": last-child"


122

Je veux créer des listes «grammaticalement correctes» en utilisant CSS. Voici ce que j'ai jusqu'à présent:

Les <li>balises sont affichées horizontalement avec des virgules après elles.

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

li:after { content: ", "; }

Cela fonctionne, mais je veux que le "dernier enfant" ait un point au lieu d'une virgule. Et, si possible, j'aimerais aussi mettre "et" avant le "dernier enfant". Les listes que je stylise sont générées dynamiquement, donc je ne peux pas simplement donner une classe aux "derniers enfants". Vous ne pouvez pas combiner des pseudo-éléments, mais c'est essentiellement l'effet que je veux obtenir.

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

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

Comment faire fonctionner cela?


4
vous ne devriez vraiment pas utiliser css pour cela.
Funky Dude

2
Je dois être un peu d'accord avec Funky Dude. Il serait préférable de le faire dans le HTML (ou codebehind si c'est plus que du HTML simple). CSS est pour le formatage :)
Zyphrax

16
Personnellement, j'ai tendance à faire valoir que, dans une liste, le formatage est une subtilité, pas une nécessité. Cela étant, l'utilisation de CSS permet des ajouts ou des suppressions plus simples de la liste que l'utilisation du code html ou côté serveur. Mais je suis étrange comme ça, parfois, et, honnêtement, ymmv, etc ... =)
David dit de réintégrer Monica le

9
Et +1 pour utiliser la virgule d'Oxford! :)
Brandon Rhodes

5
+1 pour "+1 pour Oxford Comma". Jamais entendu parler (je ne suis pas natif). Mais une recherche rapide sur le wiki indique que c'est naturel, car il n'est pas utilisé dans de nombreuses langues. Drôle ce que l'on peut apprendre sur les problèmes de CSS sur Google;)
jakub.g

Réponses:


168

Cela fonctionne :) (j'espère que le multi-navigateur, Firefox l'aime)

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>


2
Un problème similaire est le cas où vous séparez des éléments de menu avec des caractères de tube. La même solution fonctionne. Mais, l'attribut de contenu final doit être défini sur {content: none;} afin d'éliminer le caractère de canal final.
aridlehoover

2
L'ordre est également important. li:last-child:afterfonctionne mais li:after:last-childne fonctionne pas.
Richard Ayotte

1
Gardez à l'esprit que :last-childcela n'appartient pas à la spécification CSS3, donc ce n'est pas pris en charge par IE8 et les versions précédentes.
Cthulhu

23

J'aime ceci pour les éléments de liste dans les éléments <menu>. Considérez le balisage suivant:

<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>

Je le stylise avec le CSS suivant:

menu > li {
  display: inline;
}

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

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

Cela affichera:

Profile | Options | Logout

Et cela est possible grâce à ce que Martin Atkins a expliqué dans son commentaire

Notez que dans CSS 2, vous utiliseriez :after, non ::after. Si vous utilisez CSS 3, utilisez ::after(deux demi-colonnes) car ::afterc'est un pseudo-élément (une seule demi-colonne est pour les pseudo-classes).


16

Un vieux fil, néanmoins quelqu'un peut en bénéficier:

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

Cela devrait fonctionner dans CSS3 et CSS2 [non testé].


11

Vous pouvez combiner des pseudo-éléments! Désolé les gars, j'ai compris celui-ci moi-même peu de temps après avoir publié la question. Peut-être qu'il est moins utilisé en raison de problèmes de compatibilité.

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

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

Cela fonctionne à merveille. CSS est assez incroyable.


12
C'est un peu le "coin des petits", mais "last-child" est en fait une pseudo- classe , tandis que "before" et "after" sont des pseudo-éléments. La différence est qu'une pseudo-classe est une contrainte supplémentaire sur un élément existant, tandis qu'un pseudo-élément est en fait un élément entièrement nouveau dans l'arborescence de présentation qui a été généré en CSS plutôt qu'en HTML. Vous pouvez les combiner pour cette raison: le last-childest un modificateur sur le li, puis après avoir sélectionné tous les liéléments qui sont les derniers enfants, vous sélectionnez (et créez implicitement) un nouvel élément avant et après chacun.
Martin Atkins

Je sais que vous avez probablement oublié depuis longtemps ce fil particulier, mais puisque vous avez mentionné que vos listes étaient de longueur variable, il convient de souligner que, dans la plupart des contextes, une liste avec exactement deux éléments ne serait pas correcte avec une virgule en anglais. En d'autres termes, si vous vouliez «du pain et du beurre». plutôt que «du pain et du beurre». - alors la plupart des solutions proposées ici seraient incomplètes. J'ai trouvé un moyen de contourner le problème et je l'ai posté ci-dessous en tant que réponse, au cas où cela aiderait quelqu'un à chercher encore aussi loin dans le fil.
Matt Wagner

6

Juste pour mentionner, dans CSS 3

:après

devrait être utilisé comme ça

::après

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

La notation :: after a été introduite dans CSS 3 afin d'établir une discrimination entre les pseudo-classes et les pseudo-éléments. Les navigateurs acceptent également la notation: après avoir été introduite dans CSS 2.

Donc ça devrait être:

li { display: inline; list-style-type: none; }
li::after { content: ", "; }
li:last-child::before { content: "and "; }
li:last-child::after { content: "."; }

3
Chaque navigateur qui prend en charge la ::syntaxe CSS3 double-virgule ne prend également en charge que la :syntaxe, mais IE 8 ne prend en charge que le simple-deux-points, donc pour le moment, il est recommandé d'utiliser simplement le simple-deux-points pour une meilleure prise en charge du navigateur. ::est le nouveau format en retrait pour distinguer le pseudo contenu des pseudo sélecteurs. Si vous n'avez pas besoin de la prise en charge d'IE 8, n'hésitez pas à utiliser le double-virgule. De cet article
JohnnyQ

2
IE 8 n'est plus un acteur en termes de standards de navigateur. Non pris en charge par Microsoft et ne prend pas en charge HTML5 ou CSS3 (pseudo éléments, transformations, etc.) J'avais l'habitude de faire beaucoup de travail sur la rétrocompatibilité, jusqu'à il y a un an, en remontant à IE6 / IE7 (via Modernizr.) Nous avons parcouru un long chemin, et si vous avez l'intention que votre site présente son identité en ligne à long terme - sans que cela devienne une solution à courte vue - alors considérez simplement les revenus que vous gagneriez d'une personne utilisant IE8. Nada. Même les seniors, 20 ans de retard, utilisent désormais des tablettes et des ordinateurs portables 2-en-1.
Steven Ventimiglia

2

Ajouter une autre réponse à cette question car j'avais besoin précisément de ce que @derek demandait et j'étais déjà allé un peu plus loin avant de voir les réponses ici. Plus précisément, j'avais besoin de CSS qui pourrait également expliquer le cas avec exactement deux éléments de liste, où la virgule n'est PAS souhaitée. À titre d'exemple, certaines signatures d'auteur que je souhaitais produire ressembleraient à ceci:

Un auteur: By Adam Smith.

Deux auteurs: By Adam Smith and Jane Doe.

Trois auteurs: By Adam Smith, Jane Doe, and Frank Underwood.

Les solutions déjà données ici fonctionnent pour un auteur et pour 3 auteurs ou plus, mais ne prennent pas en compte le cas des deux auteurs - où le style "Oxford Comma" (également connu sous le nom de style "Harvard Comma" dans certaines parties) ne s'applique pas - c'est-à-dire qu'il ne doit pas y avoir de virgule avant la conjonction.

Après un après-midi de bricolage, j'avais proposé ce qui suit:

<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>

Il affiche les bylines comme je les ai ci-dessus.

En fin de compte, j'ai également dû me débarrasser de tout espace entre les liéléments, afin de contourner une gêne: la propriété inline-block laisserait sinon un espace avant chaque virgule. Il y a probablement un hack alternatif décent pour cela, mais ce n'est pas le sujet de cette question, je vais donc laisser à quelqu'un d'autre le soin de répondre.

Fiddle ici: http://jsfiddle.net/5REP2/


2

Pour avoir quelque chose comme un, deux et trois, vous devez ajouter un autre style css

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

Cela supprimerait la virgule de l'avant-dernier élément.

Code complet

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>


0

J'utilise la même technique dans une requête multimédia qui transforme efficacement une liste à puces en une liste en ligne sur des appareils plus petits car ils économisent de l'espace.

Donc, le changement de:

  • Élément de liste 1
  • Élément de liste 2
  • Élément de liste 3

à:

Élément de liste 1; Élément de liste 2; Élément de liste 3.


Il essaie de faire cela avec CSS. Votre méthode est du HTML codé en dur. Cette méthode est normalement utilisée pour afficher la navigation.
Sparatan117
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.