CSS pour un saut de ligne avant / après un élément particulier du «bloc en ligne»

202

Disons que j'ai ce HTML:

<h3>Features</h3>
<ul>
    <li><img src="alphaball.png">Smells Good</li>
    <li><img src="alphaball.png">Tastes Great</li>
    <li><img src="alphaball.png">Delicious</li>
    <li><img src="alphaball.png">Wholesome</li>
    <li><img src="alphaball.png">Eats Children</li>
    <li><img src="alphaball.png">Yo' Mama</li>
</ul>

et ce CSS:

li { text-align:center; display:inline-block; padding:0.1em 1em }
img { width:64px; display:block; margin:0 auto }

Le résultat peut être vu ici: http://jsfiddle.net/YMN7U/1/

Imaginez maintenant que je veux diviser cela en trois colonnes, l'équivalent d'injecter un <br>après le troisième <li>. (En fait, cela serait invalide sémantiquement et syntaxiquement.)

Je sais comment sélectionner le troisième <li>en CSS, mais comment puis-je forcer un saut de ligne après lui? Cela ne fonctionne pas:

li:nth-child(4):after { content:"xxx"; display:block }

Je sais également que ce cas particulier est possible en utilisant floatau lieu de inline-block, mais je ne suis pas intéressé par les solutions en utilisant float. Je sais également qu'avec des blocs à largeur fixe, cela est possible en définissant la largeur sur le parent ulà environ 3 fois cette largeur; Je ne suis pas intéressé par cette solution. Je sais aussi que je pourrais utiliser display:table-cellsi je voulais de vraies colonnes; Je ne suis pas intéressé par cette solution. Je suis intéressé par la possibilité de forcer une rupture dans le contenu en ligne.

Edit : Pour être clair, je m'intéresse à la «théorie», pas à la solution à un problème particulier. Le CSS peut-il injecter un saut de ligne au milieu des display:inline(-block)?éléments, ou est-ce impossible? Si vous êtes certain que c'est impossible, c'est une réponse acceptable.

Phrogz
la source
2
Mettez les 1 er et 2 e dans deux listes différentes? Je suppose que vous ne voulez pas faire ça, mais je pensais que je le jetterais là-bas.
JakeParis
On dirait que vous devez nous dire ce que vous essayez vraiment de réaliser ici afin que quelqu'un puisse recommander la meilleure méthode. Toutes les options que vous avez exclues existent pour résoudre le problème que vous avez, pourquoi une autre solution est-elle nécessaire?
Jake
4
@Jake En fait, je faisais exactement ce que je disais: utiliser une liste sémantique d'éléments et vouloir envelopper des éléments particuliers. Dans la pratique, j'ai défini la largeur du conteneur, mais cela ne fonctionne que dans mon cas particulier car les éléments se trouvaient être de la même largeur et je voulais qu'ils enveloppent à un bord cohérent. Ce n'est pas toujours le cas. Ce que j'essaie vraiment de réaliser, c'est d'apprendre si CSS peut forcer ou non une rupture de ligne au milieu du flux en ligne. La réponse confiante "Ce n'est certainement pas possible" est acceptable (si elle est correcte).
Phrogz

Réponses:

302

J'ai pu le faire fonctionner sur des éléments LI en ligne. Malheureusement, cela ne fonctionne pas si les éléments LI sont en bloc:

Démo en direct: http://jsfiddle.net/dWkdp/

Ou la version des notes de falaise:

li { 
     display: inline; 
}
li:nth-child(3):after { 
     content: "\A";
     white-space: pre; 
}
Šime Vidas
la source
2
Sime, pourquoi le "\ A" n'est-il pas imprimé? Tout ce que j'ai essayé avec le :aftertoujours imprime en texte simple.
JakeParis
12
@JMCCreative C'est ASCII 0x0A, AKA un caractère LF (saut de ligne). Voir w3.org/TR/CSS2/syndata.html#strings
Phrogz
5
@JMC \Aest le personnage de saut de ligne ... c'est une évasion
Šime Vidas
3
@JMC Spec officiel: w3.org/TR/CSS21/syndata.html#strings Sitepoint: reference.sitepoint.com/css/content
Šime Vidas
18
commentant ici car je reviens à cette question tous les quelques mois ... Cela ne fonctionnera pas sur le bloc en ligne parce que vous ajoutez des sauts de ligne dans quelque chose qui agit comme un conteneur de bloc dans un contexte en ligne. Si vous pouviez sortir du contexte en insérant le saut de ligne entre les <li>, cela fonctionnerait. Dommage vraiment car cela est utile pour les points d'arrêt de conception réactifs. Je suppose que la plupart du temps "en ligne" est tout aussi utile que le bloc en ligne pour les listes
user1010892
21

Vous n'êtes pas intéressé par beaucoup de "solutions" à votre problème. Je ne pense pas qu'il existe vraiment un bon moyen de faire ce que vous voulez faire. Tout ce que vous insérez en utilisant :afteret contenta exactement la même validité syntaxique et sémantique qu'il l'aurait fait si vous l'aviez écrit vous-même.

Les outils CSS fournissent du travail. Vous devez simplement faire flotter le lis puis clear: leftlorsque vous voulez commencer une nouvelle ligne, comme vous l'avez mentionné:

Voir un exemple: http://jsfiddle.net/marcuswhybrow/YMN7U/5/

Marcus Whybrow
la source
18
L'OP n'est pas intéressé par votre solution :)
Šime Vidas
2
Eh bien, rien de ce que vous pouvez faire en utilisant :afterne sera syntaxiquement valide ou une bonne idée, car il existe déjà des outils pour le faire. D'où la réponse.
Marcus Whybrow
32
Une raison de ne pas utiliser de flotteurs est qu'il n'y a rien de tel que float: center.
paupières
7
plus le bloc en ligne permet toutes sortes d'alignement vertical que les flotteurs ne peuvent pas
user1010892
20
"Tout ce que vous insérez en utilisant: après et le contenu a exactement la même validité syntaxique et sémantique" - tard dans la soirée, mais je ne suis absolument pas d'accord avec cela - tout l'intérêt d'utiliser: avant et: après est de pouvoir insérer un style qui n'interfère pas avec le sens sémantique du HTML.
Rupert
4

Lorsque la réécriture du code HTML est autorisée, vous pouvez imbriquer les <ul>s dans le <ul>et laisser les <li>s intérieurs s'afficher sous forme de bloc en ligne. Cela aurait également un sens sémantique à mon humble avis, car le regroupement est également reflété dans le html.


<ul>
    <li>
        <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
        </ul>
    </li>
    <li>
        <ul>
            <li>Item 4</li>
            <li>Item 5</li>
            <li>Item 6</li>
        </ul>
    </li>
</ul>

li li { display:inline-block; }

Démo

$(function() { $('img').attr('src', 'http://phrogz.net/tmp/alphaball.png'); });
h3 {
  border-bottom: 1px solid #ccc;
  font-family: sans-serif;
  font-weight: bold;
}
ul {
  margin: 0.5em auto;
  list-style-type: none;
}
li li {
  text-align: center;
  display: inline-block;
  padding: 0.1em 1em;
}
img {
  width: 64px;
  display: block;
  margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h3>Features</h3>
<ul>
  <li>
    <ul>
      <li><img />Smells Good</li>
      <li><img />Tastes Great</li>
      <li><img />Delicious</li>
    </ul>
  </li>
  <li>
    <ul>
      <li><img />Wholesome</li>
      <li><img />Eats Children</li>
      <li><img />Yo' Mama</li>
    </ul>
  </li>
</ul>

fabb
la source
3

Un moyen simple de fractionner des listes en lignes consiste à faire flotter les éléments de liste individuels, puis l'élément que vous souhaitez atteindre à la ligne suivante, vous pouvez effacer le flottant.

par exemple

<li style="float: left; display: inline-block"></li>
<li style="float: left; display: inline-block"></li>
<li style="float: left; display: inline-block"></li>

<li style="float: left; display: inline-block; clear: both"></li> --- this will start on a new line
<li style="float: left; display: inline-block"></li>
<li style="float: left; display: inline-block"></li>
mat
la source
17
Vous devez noter que le floatparamètre remplace le inline-blockparamètre. Ils ne coexistent pas vraiment ensemble
Itay
4
si vous utilisez text-aling: center; cela ne fonctionnera pas (flottant le brise)
Павел Иванов
3

Je sais que vous ne vouliez pas utiliser de flotteurs et la question n'était qu'une théorie, mais au cas où quelqu'un trouverait cela utile, voici une solution utilisant des flotteurs.

Ajoutez une classe de gauche à vos liéléments que vous souhaitez faire flotter:

<li class="left"><img src="http://phrogz.net/tmp/alphaball.png">Smells Good</li>

et modifiez votre CSS comme suit:

li { text-align:center; float: left; clear: left; padding:0.1em 1em }
.left {float: left; clear: none;}

http://jsfiddle.net/chut319/xJ3pe/

Vous n'avez pas besoin de spécifier des largeurs ou des blocs en ligne et cela remonte à IE6.

chut319
la source
1

J'ai accompli cela en créant un sélecteur :: before pour le premier élément en ligne de la ligne, et en faisant de ce sélecteur un bloc avec une marge supérieure ou inférieure pour séparer un peu les lignes.

.1st_item::before
{
  content:"";
  display:block;
  margin-top: 5px;
}

.1st_item
{
  color:orange;
  font-weight: bold;
  margin-right: 1em;
}

.2nd_item
{
  color: blue;
}
Deji
la source
-1

Notez que cela fonctionnera, selon la façon dont vous rendez la page. Mais que diriez-vous de commencer une nouvelle liste non ordonnée?

c'est à dire

<ul>
<li>
<li>
<li>
</ul>
<!-- start a new ul to line break it -->
<ul>

Phil LaNasa
la source
-2

Une meilleure solution consiste à utiliser -webkit-columns: 2;

http://jsfiddle.net/YMN7U/889/

 ul { margin:0.5em auto;
-webkit-columns:2;
}
Vivekraj KR
la source
Pour certains cas d'utilisation, cela peut être une solution raisonnable. Ce n'est pas une bonne solution dans ce cas, car il réordonne complètement le contenu pour aller vers le bas plutôt que vers le haut puis vers le bas.
Phrogz
5
Qui voudrait créer une application Web qui ne fonctionne que dans quelques navigateurs?
user2867288
-3

Peut-être que c'est complètement possible avec seulement CSS mais je préfère éviter de "flotter" autant que possible car cela interfère avec la hauteur de son parent.

Si vous utilisez jQuery, vous pouvez créer un simple plugin `wrapN` qui est similaire à` wrapAll` sauf qu'il enveloppe uniquement les éléments "N", puis rompt et encapsule les éléments "N" suivants à l'aide d'une boucle. Ensuite, définissez votre classe wrappers sur `display: block;`.

(function ($) {
    $.fn.wrapN = function (wrapper, n, start) {
        if (wrapper === undefined || n === undefined) return false;
        if (start === undefined) start = 0;
        for (var i = start; i < $(this).size(); i += n)
           $(this).slice(i, i + n).wrapAll(wrapper);
        return this;
    };
}(jQuery));

$(document).ready(function () {
    $("li").wrapN("<span class='break' />", 3);
});

Voici un JSFiddle du produit fini:

http://jsfiddle.net/dustinpoissant/L79ahLoz/

Dustin Poissant
la source