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

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.

This question is related to html css

The answer is


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

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

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

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.


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

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

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


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>

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

i.e.

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


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/


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/