ChatGPT解决这个技术问题 Extra ChatGPT

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.

Put the 1st three and the 2nd three in two different lists? I'm assuming you don't want to do this, but I thought I"d throw it out there.
Looks like you need to tell us what you are really trying to achieve here so someone can recommend the best method. All the options you excluded exist to solve the problem you have, why is another solution needed?
@Jake I was in fact doing exactly what I stated: using a semantic list of elements and wanting to wrap after particular ones. In practice I set the width of the container, but this only works in my particular case because the items happened to be the same width and I wanted them to wrap at a consistent edge. This might not always be the case. What I am "really trying to achieve" is learn whether or not CSS can force a line break in the middle of inline flow. The confident answer "This is definitely not possible" is acceptable (if correct).

L
Luca

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

Sime, why does the "\A" not get printed out? Everything I've tried with the :after always prints as straight text.
@JMCCreative That's ASCII 0x0A, AKA a LF (line feed) character. See w3.org/TR/CSS2/syndata.html#strings
@JMC \A is the line feed character... it's an escape
commenting here as I keep coming back to this question every few months... It won't work on inline-block because you are adding line breaks within something that it acting like a block container within an inline context. If you could break out of the context by inserting the line break between the
  • s it would work. Shame really as this is useful for responsive design breakpoints. I guess most of the time "inline" is just as useful as inline-block for lists
  • M
    Marcus Whybrow

    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/


    The OP is not interested in your solution :)
    Well nothing you can do by using :after will be syntactically valid or a good idea, since there are already tools in place to do this. Hence the answer.
    One reason to not use floats is that there is no such thing as float: center.
    plus inline-block allows for all sorts of vertical alignment that floats can't
    "Anything you insert using :after and content has exactly the same syntactic and semantic validity" - coming late to the party, but I totally disagree with this - the whole point of using :before and :after is to be able to insert styling that does not interfere with the semantic meaning of the Html.
    M
    Mr. Polywhirl

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

    Features

      • Smells Good
      • Tastes Great
      • Delicious
      • Wholesome
      • Eats Children
      • Yo' Mama


    m
    matt

    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>
    

    You should notice that the float setting overrides the inline-block setting. They don't really coexist together
    if you use text-aling: center; it will not work (floating breaks it)
    c
    chut319

    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.


    D
    Deji

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

    V
    Vivekraj K R

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

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

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

    For some use cases, this may be a reasonable solution. It is not a good solution in this case, because it completely re-orders the content to go down-then-across instead of across-then-down.
    Who would wants to make a web application that only works in a few browsers?
    P
    Phil LaNasa

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

    i.e.


      This causes accessibility issues.
    D
    Dustin Poissant

    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/