CSS para quebra de linha antes / depois de um item específico `bloco inline`

202

Digamos que eu tenho esse 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>

e este CSS:

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

O resultado pode ser visto aqui: http://jsfiddle.net/YMN7U/1/

Agora imagine que eu quero dividir isso em três colunas, o equivalente a injetar um <br>após o terceiro <li>. (Na verdade, fazer isso seria semanticamente e sintaticamente inválido.)

Eu sei como selecionar o terceiro <li>no CSS, mas como forçar uma quebra de linha depois dele? Isso não funciona:

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

Também sei que esse caso em particular é possível usando em floatvez de inline-block, mas não estou interessado em soluções usando float. Eu também sei que com blocos de largura fixa isso é possível definindo a largura no pai ulcomo cerca de 3x essa largura; Não estou interessado nesta solução. Também sei que poderia usar display:table-cellse quisesse colunas reais; Não estou interessado nesta solução. Estou interessado na possibilidade de forçar uma quebra no conteúdo embutido.

Edit : Para ser claro, estou interessado em 'teoria', não a solução para um problema específico. O CSS pode injetar uma quebra de linha no meio dos display:inline(-block)?elementos ou é impossível? Se você tem certeza de que é impossível, essa é uma resposta aceitável.

Phrogz
fonte
2
Coloque o primeiro três e o segundo três em duas listas diferentes? Eu estou supondo que você não quer fazer isso, mas eu pensei que eu "D jogá-lo lá fora.
JakeParis
Parece que você precisa nos dizer o que realmente está tentando alcançar aqui, para que alguém possa recomendar o melhor método. Todas as opções excluídas existem para resolver o problema que você tem, por que outra solução é necessária?
Jake
4
@ Jake, eu estava de fato fazendo exatamente o que afirmei: usando uma lista semântica de elementos e desejando agrupar outros. Na prática, defino a largura do contêiner, mas isso só funciona no meu caso particular, porque os itens tinham a mesma largura e eu queria que eles se enrolassem em uma borda consistente. Isso pode nem sempre ser o caso. O que estou "realmente tentando alcançar" é aprender se o CSS pode ou não forçar uma quebra de linha no meio do fluxo inline. A resposta segura "Definitivamente não é possível" é aceitável (se correta).
Phrogz

Respostas:

302

Consegui fazê-lo funcionar em elementos LI embutidos. Infelizmente, ele não funciona se os elementos LI forem inline-block:

Demonstração ao vivo: http://jsfiddle.net/dWkdp/

Ou a versão do penhasco:

li { 
     display: inline; 
}
li:nth-child(3):after { 
     content: "\A";
     white-space: pre; 
}
Šime Vidas
fonte
2
Sime, por que o "\ A" não é impresso? Tudo o que tentei com o :aftersempre imprime como texto direto.
precisa saber é o seguinte
12
@JMCCreative Isso é ASCII 0x0A, também conhecido como LF (avanço de linha). Veja w3.org/TR/CSS2/syndata.html#strings
Phrogz
5
@JMC \Aé o caractere de alimentação de linha ... é uma fuga
Šime Vidas
18
comentando aqui enquanto continuo retornando a essa pergunta a cada poucos meses ... Ele não funcionará no bloco embutido porque você está adicionando quebras de linha a algo que age como um contêiner de bloco dentro de um contexto embutido. Se você pudesse sair do contexto inserindo a quebra de linha entre os <li> s, isso funcionaria. Pena que isso seja útil para pontos de interrupção de design responsivos. Eu acho que na maioria das vezes "inline" é tão útil como inline-block para listas
user1010892
21

Você não está interessado em muitas "soluções" para o seu problema. Eu não acho que realmente exista uma boa maneira de fazer o que você quer fazer. Qualquer coisa que você insira usando :aftere contenttenha exatamente a mesma validade sintática e semântica que teria feito se você tivesse escrito nela mesmo.

As ferramentas CSS fornecem trabalho. Você deve apenas flutuar os lie clear: leftquando quiser iniciar uma nova linha, como você mencionou:

Veja um exemplo: http://jsfiddle.net/marcuswhybrow/YMN7U/5/

Marcus Whybrow
fonte
18
O OP não está interessado em sua solução :)
Šime Vidas
2
Bem, nada que você possa fazer usando :afterserá sintaticamente válido ou uma boa idéia, pois já existem ferramentas para isso. Daí a resposta.
Marcus Whybrow
32
Uma razão para não usar carros alegóricos é que não existe float: center.
Eyelidlessness
7
além de inline-block permite a todos os tipos de alinhamento vertical que flutua não pode
user1010892
20
"Qualquer coisa que você insere usando: after e content tem exatamente a mesma validade sintática e semântica" - chegando atrasado à festa, mas eu discordo totalmente disso - todo o ponto de usar: before e: after é poder inserir estilos que não interfere com o significado semântico do HTML.
Rupert #
4

Quando a reescrita do html é permitida, você pode aninhar <ul>s dentro do <ul>e apenas permitir que o interior seja <li>exibido como bloco embutido. Isso também semanticamente faria sentido no IMHO, pois o agrupamento também é refletido no 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>

fabb
fonte
3

Uma maneira fácil de dividir listas em linhas é flutuando os itens de lista individuais e, no item que você deseja ir para a próxima linha, você pode limpar o flutuador.

por exemplo

<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>
mate
fonte
17
Você deve observar que a floatconfiguração substitui a inline-blockconfiguração. Eles realmente não coexistem
Itay
4
se você usa text-aling: center; ele não funcionará (a flutuação o interrompe) #
121214
3

Eu sei que você não queria usar carros alegóricos e a pergunta era apenas teoria, mas caso alguém ache isso útil, aqui está uma solução usando carros alegóricos.

Adicione uma classe de esquerda aos seus lielementos que você deseja flutuar:

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

e altere seu CSS da seguinte maneira:

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

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

Você não precisa especificar larguras ou blocos embutidos e funciona desde o IE6.

chut319
fonte
1

Consegui isso criando um seletor :: before para o primeiro elemento embutido na linha e transformando esse seletor em um bloco com uma margem superior ou inferior para separar um pouco as linhas.

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

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

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

Observe que isso funcionará, dependendo de como você renderiza a página. Mas que tal começar uma nova lista não ordenada?

ie

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

Phil LaNasa
fonte
-2

Uma solução melhor é usar -webkit-columns: 2;

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

 ul { margin:0.5em auto;
-webkit-columns:2;
}
Vivekraj KR
fonte
Para alguns casos de uso, essa pode ser uma solução razoável. Não é uma boa solução nesse caso, porque reorganiza completamente o conteúdo para ir para baixo e para baixo em vez de para baixo e para baixo.
21415 Phrogz
5
Quem gostaria de criar um aplicativo da web que funcione apenas em alguns navegadores?
user2867288
-3

Talvez seja completamente possível apenas com CSS, mas prefiro evitar "flutuar" o máximo possível, pois isso interfere na altura dos pais.

Se você estiver usando o jQuery, poderá criar um plugin `wrapN` simples que seja semelhante ao` wrapAll`, exceto que apenas envolve os elementos "N" e depois quebra e envolve os próximos elementos "N" usando um loop. Em seguida, defina sua classe de wrappers para `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);
});

Aqui está um JSFiddle do produto final:

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

Dustin Poissant
fonte