134 votes

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

Je veux faire des listes "grammaticalement correctes" en utilisant les CSS. Voici ce que j'ai fait jusqu'à présent :

El <li> 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 également mettre "and" avant le "last-child". Les listes auxquelles je donne un style sont générées de manière dynamique, je ne peux donc pas simplement donner une classe aux "last-children". Vous ne pouvez pas combiner les pseudo-éléments, mais c'est en gros l'effet que je veux obtenir.

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

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

Comment faire pour que ça marche ?

4 votes

Vous ne devriez vraiment pas utiliser de css pour ça.

2 votes

Je dois être un peu d'accord avec Funky Dude. Il serait préférable de faire cela dans le HTML (ou le code derrière si c'est plus que du simple HTML). Les CSS servent à la mise en forme :)

16 votes

J'ai... personnellement, tendance à soutenir que, dans une liste, le formatage est une commodité, pas une nécessité. Dans ce cas, l'utilisation de CSS permet des ajouts ou des retraits plus simples de la liste que l'utilisation du code html ou du code côté serveur. Mais je suis étrange comme ça, parfois, et, honnêtement ymmv, etc... =)

183voto

Zyphrax Points 6603

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

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 votes

Un problème similaire se pose dans le cas où vous séparez les éléments de menu par des caractères de séparation. La même solution fonctionne. Toutefois, l'attribut de contenu final doit être défini sur {content:none;} afin d'éliminer le dernier caractère pointu.

2 votes

L'ordre est également important. li:last-child:after fonctionne mais li:after:last-child ne le fait pas.

1 votes

Gardez à l'esprit que :last-child n'appartient pas à la spécification CSS3, elle n'est donc pas prise en charge par IE8 et les versions précédentes.

30voto

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

<menu>
  <li><a href="http://stackoverflow.com/member/profile">Profile</a></li>
  <li><a href="http://stackoverflow.com/member/options">Options</a></li>
  <li><a href="http://stackoverflow.com/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 c'est possible grâce à ce que Martin Atkins a expliqué sur son site web commentaire

Notez qu'en CSS 2, vous utiliseriez :after pas ::after . Si vous utilisez CSS 3, utilisez ::after (deux demi-colonnes) car ::after est un pseudo-élément (une seule demi-colonne est réservée aux pseudo-classes).

11voto

Derek Points 289

Vous peut combinez les pseudo-éléments ! Désolé les gars, j'ai trouvé cette solution moi-même peu de temps après avoir posté la question. Il est peut-être moins utilisé en raison de problèmes de compatibilité.

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

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

Cela fonctionne à merveille. Le CSS est assez étonnant.

14 votes

C'est un peu un "coin des chicanes", mais "last-child" est en fait un pseudo-code. 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 effectivement un élément entièrement nouveau dans l'arbre de présentation qui a été généré en CSS plutôt qu'en HTML. Vous pouvez combiner ces éléments pour cette raison : l'élément last-child est un modificateur de l'élément li et ensuite, après avoir sélectionné toutes les li les éléments qui sont les derniers enfants, vous sélectionnez ensuite (et créez implicitement) un nouvel élément avant et après chacun d'eux.

0 votes

Je sais que vous avez probablement oublié depuis longtemps ce fil de discussion particulier, mais puisque vous avez mentionné que vos listes étaient de longueur variable, il est utile de signaler que, dans la plupart des contextes, une liste comportant exactement deux éléments ne serait pas correcte avec une virgule en anglais. En d'autres termes, si vous vouliez "bread and butter." plutôt que "bread, and butter." - alors la plupart des solutions proposées ici seraient incomplètes. J'ai trouvé un moyen de contourner ce problème, et je l'ai posté ci-dessous en tant que réponse, au cas où cela aiderait quelqu'un qui cherche encore dans ce fil.

6voto

Pour mémoire, en CSS 3

:après

doit être utilisé comme suit

::après

Desde 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-classes. discrimination entre les pseudo-classes et les pseudo-éléments. Les navigateurs acceptent également la notation :after introduite en CSS 2.

Il devrait en être ainsi :

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

3 votes

Tous les navigateurs qui supportent le double point :: La syntaxe CSS3 prend également en charge uniquement l'élément : syntaxe, mais IE 8 ne prend en charge que le point-virgule, donc pour l'instant, il est recommandé d'utiliser le point-virgule 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 point. De ce qui suit article

2 votes

IE 8 n'est plus un acteur en termes de normes de navigation. Il n'est pas pris en charge par Microsoft et ne prend pas en charge HTML5 ou CSS3 (pseudo-éléments, transformations, etc.). J'ai beaucoup travaillé sur la rétrocompatibilité, jusqu'à il y a un an, en remontant jusqu'à IE6/IE7 (via Modernizr.) Nous avons parcouru un long chemin, et si vous souhaitez que votre site présente son identité en ligne à long terme - sans que cela ne devienne une solution à courte vue -, il vous suffit de considérer les revenus que vous tireriez d'une personne utilisant IE8. Nada. Même les personnes âgées, qui ont 20 ans de retard, utilisent désormais des tablettes et des ordinateurs portables 2 en 1.

3voto

Matt Wagner Points 60

J'ajoute une autre réponse à cette question car j'avais précisément besoin 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 d'un CSS qui pouvait également tenir compte du cas où il y a exactement deux éléments de liste, où la virgule n'est PAS souhaitée. À titre d'exemple, les légendes de paternité que je souhaite produire ressembleraient à ce qui suit :

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 négligent de prendre en compte le cas de deux auteurs - où le style "virgule d'Oxford" (également connu sous le nom de "virgule de Harvard" dans certaines régions) 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'ai trouvé la solution suivante :

<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 légendes comme je les ai mises ci-dessus.

À la fin, j'ai aussi dû me débarrasser de tout espace blanc entre li afin de contourner un inconvénient : la propriété inline-block laisserait sinon un espace avant chaque virgule. Il existe probablement une autre solution décente, mais comme ce n'est pas le sujet de cette question, je laisse à quelqu'un d'autre le soin d'y répondre.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X