CSS to line break before/after a particular `inline-block` item

HtmlCss

Html Problem Overview


Let's say I have this 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>

and this CSS:

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

The result can be seen here: http://jsfiddle.net/YMN7U/1/

Now imagine that I want to break this into three columns, the equivalent of injecting a <br> after the third <li>. (Actually doing that would be semantically and syntactically invalid.)

I know how to select the third <li> in CSS, but how do I force a line break after it? This does not work:

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

I also know that this particular case is possible by using float instead of inline-block, but I am not interested in solutions using float. I also know that with fixed-width blocks this is possible by setting the width on the parent ul to about 3x that width; I am not interested in this solution. I also know that I could use display:table-cell if I wanted real columns; I am not interested in this solution. I am interested in the possibility of forcing a break inside inline content.

Edit: To be clear, I am interested in 'theory', not the solution to a particular problem. Can CSS inject a line break in the middle of display:inline(-block)? elements, or is it impossible? If you are certain that it is impossible, that is an acceptable answer.

Html Solutions


Solution 1 - Html

I've been able to make it work on inline LI elements. Unfortunately, it does not work if the LI elements are inline-block:

Live demo: http://jsfiddle.net/dWkdp/

Or the cliff notes version:

li { 
     display: inline; 
}
li:nth-child(3):after { 
     content: "\A";
     white-space: pre; 
}

Solution 2 - Html

You are not interested in a lot of "solutions" to your problem. I do not think there really is a good way to do what you want to do. Anything you insert using :after and content has exactly the same syntactic and semantic validity it would have done if you had just written it in there yourself.

The tools CSS provide work. You should just float the lis and then clear: left when you want to start a new line, as you have mentioned:

See an example: http://jsfiddle.net/marcuswhybrow/YMN7U/5/

Solution 3 - Html

When rewriting the html is allowed, you can nest <ul>s within the <ul> and just let the inner <li>s display as inline-block. This would also semantically make sense IMHO, as the grouping also is reflected within the 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; }

Demo

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

Solution 4 - Html

An easy way to split lists into rows is by floating the individual list items and then the item that you want to go to the next line you can clear the float.

for example

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

Solution 5 - Html

I know you didn't want to use floats and the question was just theory but in case anyone finds this useful, here's a solution using floats.

Add a class of left to your li elements that you want to float:

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

and amend your CSS as follows:

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

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

You don't need to specify widths or inline-blocks and works as far back as IE6.

Solution 6 - Html

I accomplished this by creating a ::before selector for the first inline element in the row, and making that selector a block with a top or bottom margin to separate rows a little bit.

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

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

.2nd_item
{
  color: blue;
}

Solution 7 - Html

A better solution is to use -webkit-columns:2;

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

 ul { margin:0.5em auto;
-webkit-columns:2;
}

Solution 8 - Html

Note sure this will work, depending how you render the page. But how about just starting a new unordered list?

i.e.

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

Solution 9 - Html

Maybe it's is completely possible with only CSS but I prefer to avoid "float" as much as I can because it interferes with it's parent's height.

If you are using jQuery, you can create a simple wrapN plugin that is similar to wrapAll except it only wraps "N" elements and then breaks and wraps the next "N" elements using a loop. Then set your wrappers class to 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);
});

Here is a JSFiddle of the finished product:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPhrogzView Question on Stackoverflow
Solution 1 - HtmlŠime VidasView Answer on Stackoverflow
Solution 2 - HtmlMarcus WhybrowView Answer on Stackoverflow
Solution 3 - HtmlfabbView Answer on Stackoverflow
Solution 4 - HtmlmattView Answer on Stackoverflow
Solution 5 - Htmlchut319View Answer on Stackoverflow
Solution 6 - HtmlDejiView Answer on Stackoverflow
Solution 7 - HtmlVivekraj K RView Answer on Stackoverflow
Solution 8 - HtmlPhil LaNasaView Answer on Stackoverflow
Solution 9 - HtmlDustin PoissantView Answer on Stackoverflow