Por que esse elemento de bloco embutido é empurrado para baixo?

238

A seguir, está o meu código e quero entender por que o #firstDiv está sendo empurrado para baixo por todos os navegadores. Eu realmente quero entender o funcionamento interno do fato de que está sendo empurrado para baixo ao invés de puxá-lo para cima de uma maneira ou de outra. (e eu sei como alinhar seus tops :))

E eu sei que está transbordando: oculto, o que está causando isso, mas não sei por que está empurrando essa div para baixo.

body {
  width: 350px;
  margin: 0px auto;
}

#container {
  border: 15px solid orange;
}

#firstDiv {
  border: 10px solid brown;
  display: inline-block;
  width: 70px;
  overflow: hidden;
}

#secondDiv {
  border: 10px solid skyblue;
  float: left;
  width: 70px;
}

#thirdDiv {
  display: inline-block;
  border: 5px solid yellowgreen;
}
<div id="container">
  <div id="firstDiv">FIRST</div>
  <div id="secondDiv">SECOND</div>
  <div id="thirdDiv">THIRD
    <br>some more content<br> some more content
  </div>
</div>

http://jsfiddle.net/WGCyu/ .

Shawn Taylor
fonte

Respostas:

360

Basicamente, você adicionou mais confusão ao seu código, o que está criando mais confusão, então primeiro tento remover a confusão que dificulta a compreensão do problema real.

Antes de tudo, precisamos estabelecer que qual é a verdadeira questão? É por isso que o inline-blockelemento " " é empurrado para baixo.

Agora começamos a entender e remover a desordem primeiro.

1 - Por que não dar a todos os três divs a mesma largura de borda? Vamos dar.

2 - O elemento flutuante tem alguma conexão com o elemento de bloco embutido sendo empurrado para baixo? Não, não tem nada a ver com isso.

Então, removemos completamente essa div . E você está testemunhando o mesmo comportamento do elemento de bloco embutido sendo empurrado para baixo.

Aí vem a vez de algumas literaturas para entender a idéia das caixas de linhas e como elas são alinhadas na mesma linha, e leia atentamente o último parágrafo, porque existe a resposta da sua pergunta.

A linha de base de um 'bloco embutido' é a linha de base de sua última caixa de linha no fluxo normal, a menos que não tenha caixas de linha em fluxo ou se sua propriedade 'estouro' tiver um valor calculado diferente de 'visível', em Nesse caso, a linha de base é a borda da margem inferior.

Se você não tiver certeza da linha de base , aqui está uma breve explicação em palavras simples.

Todos os caracteres, exceto 'gjpqy', são escritos na linha de base. Você pode pensar na linha de base como se você desenhasse uma linha horizontal simples, assim como o sublinhado logo abaixo desses "caracteres aleatórios". caracteres na mesma linha, a parte inferior desses caracteres ficaria abaixo da linha.

Portanto, podemos dizer que todos os caracteres, exceto 'gjpqy', são escritos completamente acima da linha de base, enquanto parte desses caracteres é escrita abaixo da linha de base.

3 - Por que não verificar onde está a linha de base da nossa linha? Eu adicionei alguns caracteres que mostram a linha de base da nossa linha.

4 - Por que não adicionar alguns caracteres em nossos divs também para encontrar suas linhas de base no div? Aqui, alguns caracteres adicionados em divs para esclarecer a linha de base .

Agora, quando você entender sobre a linha de base, leia a seguinte versão simplificada sobre a linha de base dos blocos embutidos.

i) Se o bloco embutido em questão tiver sua propriedade de estouro definida como visível (que é por padrão, portanto, não é necessário configurá-lo). Então, sua linha de base seria a linha de base do bloco da linha que a continha.

ii) Se o bloco embutido em questão tiver sua propriedade de estouro definida como OUTROS QUE visível. Então, sua margem inferior estaria na linha de base da linha da caixa de contenção.

  • Primeiro ponto em detalhes

Agora, observe isso novamente para esclarecer seu conceito de que o que está acontecendo com a div verde . Se ainda houver alguma confusão, aqui serão adicionados mais caracteres próximos à div verde para estabelecer a linha de base do bloco que contém e div verde será alinhada.

Bem, agora estou afirmando que eles têm a mesma linha de base? CERTO?

5 - Então, por que não sobrepô-los e ver se eles se encaixam corretamente um no outro? Então, eu trago a terceira div-esquerda: 35px; verificar se eles têm a mesma linha de base agora ?

Agora, temos nosso primeiro ponto comprovado.

  • Segundo ponto em detalhes

Bem, após a explicação do primeiro ponto, o segundo ponto é facilmente digerível e você vê que a primeira div que possui uma propriedade de estouro definida como diferente de visível (oculta), tem sua margem inferior na linha de base da linha.

Agora, você pode fazer algumas experiências para ilustrar melhor.

  1. Defina o primeiro estouro de div: visível (ou remova-o completamente) .
  2. Defina o segundo estouro div: diferente de visível .
  3. Defina o estouro de ambas as divs: diferente de visível .

Agora traga de volta sua bagunça e veja se tudo está lhe agradando.

  1. Traga de volta a sua div flutuada (é claro que é necessário
    aumentar a largura do corpo) Você vê que ela não tem efeito.
  2. Traga de volta as mesmas margens ímpares .
  3. Defina div verde para transbordar: visível conforme definido na sua pergunta (esse desalinhamento deve-se ao aumento da largura da borda de 1 para 5 px; portanto, se ajustar o negativo à esquerda, você verá que não há problema)
  4. Agora remova os caracteres adicionais que adicionei para ajudar no entendimento . (e, claro, remova a esquerda negativa)
  5. Por fim, reduza a largura do corpo, porque não precisamos mais de uma largura maior.

E agora estamos de volta para onde começamos.

Espero ter respondido sua pergunta.

Gary Lindahl
fonte
1
Obrigado por uma explicação tão boa, mas não entendi seu argumento "A linha de base seria a linha de base do bloco da linha". É o mesmo da linha de base da linha que você deixou claro no segundo ponto?
Shawn Taylor
2
Resposta atrasada. Acabei de notar o mesmo problema e só queria agradecer a Gary Lindahl pela explicação do NICE.
TimSPQR
+1 ntgCleaner Mesmo que eu aprecio boas respostas, Gary Lindahl de tanta coisa para ler e eu estou faltando apenas aquelas poucas linhas onde diz 'Solução: XY'
Coder Básico
Achei esta explicação detalhada incrivelmente informativa, obrigado. Eu lutei com um conceito por um tempo e fiz um Fiddle atualizado que poderia esclarecer para outros.
jonsanders101
@ntgCleaner obrigado cara .. mesmo depois de toda a explicação, eu não conseguia fazê-lo funcionar. mas o seu comentário fez :)
supersan
329

O valor padrão para vertical-alignCSS é baseline& esta regra também se aplica a inline-blockleia este http://www.brunildo.org/test/inline-block.html

Escreva vertical-align:topno seu inline-blockDIV.

Verifique isso http://jsfiddle.net/WGCyu/1/

sandeep
fonte
3
Você leu minha pergunta? Eu nunca pedi para corrigir o problema.
Shawn Taylor
23
@ ShawnTaylor: O título da pergunta é muito enganador. Nós instintivamente lemos o título e depois procuramos o código, se houver algum. Raramente lemos o texto real. É um mau hábito, mas você provavelmente deve entender por que isso acontece. : P
Purag
@sandeep: sobre a sua edição, então porque firstDiv está alinhada ao topo, mesmo quando vertical-align é removido a partir dele
Shawn Taylor
@sandeep: O link que você forneceu é informativo, mas isso não ajuda sobre esta questão, uma vez que não está descrevendo o comportamento dos display:inline-blockcombinado com float:left/right.
Zeta
2
@ThomasMcCabe Hardly; se alguém postar uma resposta ruim, merece ser votado para sinalizar aos futuros espectadores que há algo errado com ela, independentemente de suas boas intenções. Dito isto, acho que essa resposta nunca mereceu voto negativo; mesmo em sua forma original, fornecia uma peça essencial do quebra-cabeça omitida pela resposta aceita - que o alinhamento da linha de base não é a única maneira de os elementos ficarem alinhados verticalmente e que, se você alterar a vertical-alignpropriedade, nenhuma da complexidade descrita no resposta aceita se aplica.
Mark Amery
33

Apenas use vertical-align:top;

Demo

Elyor
fonte
9

Veja este exemplo alternativo. A razão para esse comportamento é descrita no módulo CSS3: line: 3.2. Embrulho de caixa de linha [1] :

Em geral, a aresta inicial de uma caixa de linha toca a aresta inicial de seu bloco contendo e a aresta final toca a aresta final de seu bloco contendo. No entanto, caixas flutuantes podem ficar entre a borda do bloco que contém e a borda da caixa de linha. Assim, embora as caixas de linha no mesmo contexto de formatação em linha geralmente tenham o mesmo avanço de progressão em linha (o do bloco que contém), elas podem variar se o espaço disponível para progressão em linha for reduzido devido a flutuações [...]

Como você pode ver, o terceiro elemento é empurrado para baixo, embora não tenha uma overflowpropriedade. O motivo deve estar em outro lugar para encontrar. O segundo comportamento observado é descrito na especificação 1 da revisão 2 do Cascading Style Sheets Level 1 (CSS 2.1): 9.5 flutuadores [2] :

Como uma bóia não está no fluxo, as caixas de bloco não posicionadas criadas antes e depois da caixa de bóia fluem verticalmente, como se a bóia não existisse. No entanto, as caixas de linha atuais e subseqüentes criadas ao lado do flutuador são reduzidas conforme necessário para abrir espaço para a caixa de margem do flutuador.

Todas as suas display:inline-block;divs estão usando um tipo especial, baselineneste caso 10.8 Cálculos de altura da linha: as propriedades 'line-height' e 'vertical-align' (very end) [3] :

A linha de base de um 'bloco embutido' é a linha de base de sua última caixa de linha no fluxo normal, a menos que não tenha caixas de linha em fluxo ou se sua propriedade 'estouro' tiver um valor calculado diferente de 'visível', em Nesse caso, a linha de base é a borda da margem inferior.

Portanto, quando você estiver usando elementos e inline-blockelementos flutuantes, o elemento flutuante será empurrado para o lado e a formatação embutida será recalculada de acordo com 1 . Por outro lado, os próximos elementos são reduzidos se não couberem. Como você já está trabalhando com uma quantidade mínima de espaço, não há outra maneira de modificar seus elementos, pressionando-os 2 . Nesse caso, o elemento mais alto definirá o tamanho da sua divisória de empacotamento, definindo assim o baseline 3 , enquanto, por outro lado, a modificação de posição e largura indicada em 2 não pode ser aplicada a elementos de altura máxima com espaçamento mínimo. Nesse caso, resultará em um comportamento como na minha primeira demonstração.

Por fim, o motivo pelo qual você overflow:hiddenevitará #firstDivser empurrado para a borda inferior do seu #container, embora eu não tenha encontrado um motivo na seção 11 . Sem overflow:hiddenele funciona como excedido e definido por 2 e 3 . Demo

TL; DR: Observe atentamente as recomendações do W3 e as implementações no navegador. Na minha humilde opinião, os elementos flutuantes estão determinados a mostrar um comportamento inesperado, se você não souber todas as alterações que eles fazem nos elementos circundantes. Aqui está outra demonstração que mostra um problema comum com carros alegóricos.

Zeta
fonte
3
Esse "padrão" é uma bagunça inacreditável. É incrível que eles tenham conseguido fazer com que essas coisas se comportassem consistentemente nos navegadores. Oh espere, não, eles nunca foram capazes de fazer isso.
Triynko 16/03/16
6

Inicialmente, comecei a responder a essa pergunta , mas ela estava travada como dupe antes que eu pudesse terminar, por isso, posto a resposta aqui.

Primeiro, precisamos entender o que inline-blocké.
A definição no MDN diz:

O elemento gera uma caixa de elemento de bloco que será transmitida com o conteúdo circundante, como se fosse uma única caixa embutida (se comportando como um elemento substituído)

Para entender o que está acontecendo aqui, precisamos ver vertical-aligno valor padrão baseline.

visualizações de posição vertical
Nesta ilustração, você tem esta tabela de cores:
Azul: A linha de base
Vermelho: A parte superior e inferior da altura da linha
Verde: A parte superior e inferior da caixa de conteúdo embutido.

No elemento #left, você tem algum conteúdo de texto que controla qual é a linha de base. Isso significa que o texto interno define a linha de base para #left.
À direita, não há conteúdo; portanto, o navegador não tem outra opção senão usar a parte inferior da caixa como linha de base.

Veja esta visualização em que eu desenhei a linha de base em um exemplo em que o primeiro contêiner embutido possui algum texto e o próximo está vazio:

Linha de base desenhada

Se você alinhar especificamente um elemento à parte superior, realmente diz que alinha a parte superior desse elemento à parte superior da caixa de linha.

Isso pode ser mais fácil de entender por um exemplo.

div {
    display: inline-block;
    width: 100px;
    height: 150px;
    background: gray;
    vertical-align: baseline;
}
div#middle {
    vertical-align: top;
    height: 50px
}
   
div#right {
    font-size: 30px;
    height: 100px
}
<div id="left">
  <span>groovy</span>
</div>
<div id="middle">groovy</div>

<div id="right">groovy</div>

O resultado é este - e eu adicionei a linha de base azul e a caixa de linha vermelha: o que acontece aqui é que a altura da caixa de linha depende de como o conteúdo de toda a linha é organizado. Isso significa que, para calcular o alinhamento superior, os alinhamentos da linha de base devem ser calculados primeiro. O elemento possui , portanto, isso não é usado para o posicionamento da linha de base. mas oe são posicionados verticalmente para que suas linhas de base estejam alinhadas. Quando isso é feito, a altura da caixa de linha aumenta, porque o elemento foi pressionado um pouco como resultado do tamanho da fonte maior. Em seguida, a posição superior do elemento pode ser calculada, e isso ocorre na parte superior da caixa de linha.Alinhamento vertical explicado
#middlevertical-align:top#left#right#right#middle

temor
fonte
1

o problema é porque você aplicou float: left na segunda div. o que faz com que o segundo div apareça no lado esquerdo e o primeiro div cai e vem depois do segundo div. Se você aplicar float: left na primeira div também, seu problema desaparecerá.

overflow: hidden não causa problemas ao seu layout, overflow: hidden afeta apenas os elementos internos de uma div, não tem nada a ver com outros elementos que estão fora.

Pal Singh
fonte
Bem, se está sendo empurrado porque vem em segundo após div flutuado, então por que thirdDiv não desce?
Shawn Taylor
porque a terceira div tem a segunda div antes dela, que não possui float: left;
Pal Singh
Mas onde esta regra menciona que, se alguma div vier depois da div flutuada, ela cairá para baixo? Eu verifiquei o w3.org.
Shawn Taylor
o elemento que não está flutuando gotas à linha de base e se você tivesse feito voto negativo do que devo dizer que foi a resposta mais lógica
Pal Singh
Não, não votei negativo e sim, sua resposta não merece resultado negativo. Apenas votado para cima.
Shawn Taylor
0

Tente adicionar padding:0;ao corpo e remover a margem dos seus divs.

Adicione background-color:*anycor além do plano de fundo * para verificar a diferença.

LOLZ
fonte
Edite a resposta para formatar o código. Para formatar o código, adicione o símbolo `antes de iniciar o código e depois de finalizá-lo. como codepor exemplo:. background-color:any color
JINO SHAJI
0

Tente fazer todas as propriedades CSS de todos os elementos iguais.

Eu tive um problema semelhante e, ao corrigir isso, identifiquei que estava soltando um elemento com a propriedade Font no Div Element.

Depois de eliminar esse elemento com a propriedade Font, o alinhamento de todos os DIV foi interrompido. Para corrigir isso, defino a propriedade Font para todos os elementos DIV da mesma forma que o elemento que é solto nela.

No exemplo a seguir, o elemento Dropped da classe ".dldCuboidButton" definido com o tamanho da fonte: 30 px.

Então, adicionei a mesma propriedade às classes restantes, como .cuboidRecycle, .liCollect, .dldCollect, que são usados ​​pelos elementos DIV. Dessa forma, todo elemento DIV segue as mesmas medições antes e depois de soltar o elemento nele.

.cuboidRecycle {
    height:40px; 
    width:'20px; float:right';
    overflow:'none';
    background-color:#cab287;
    color:#ffffff; 
    border-radius:8px; 
    text-align:'center'; 
    vertical-align:'top';
    display: inline-block;
    font-size: 30px; /* Set a font-size */
}


.liCollect {
    height:40px; 
    width:'20px; float:right';
    overflow:'none';
    background-color:#cab287;
    color:#ffffff; 
    border-radius:8px; 
    text-align:'center'; 
    vertical-align:'top';
    display: inline-block;
    font-size: 30px; /* Set a font-size */
}

.dldCollect {
    height:40px; 
    width:'20px; float:right';
    overflow:'none';
    background-color:#009933;
    color:#ffffff; 
    border-radius:8px; 
    text-align:'center'; 
    vertical-align:'top';
    display: inline-block;
    font-size: 30px; /* Set a font-size */
}


.dldCuboidButton {
    background-color:  #7c6436;
    color: white; /* White text */
    font-size: 30px; /* Set a font-size */
    border-radius: 8px;
    margin-top: 1px;
  }

Aqui está o exemplo de HTML criado dinamicamente usando o CSS acima.

$("div#tabs").append(
  "<div id='" + newTabId + "'>#" + uniqueId + 
  "<input type=hidden id=hdn_tmsource_" + uniqueId + "  value='" + divTmpfest + "'>" + 
  "<input type=hidden id=leCuboidInfo_" + uniqueId + " value=''>" + 
  "<div id='" + divRecycleCuboid + "' class=cuboidRecycle ondrop='removeDraggedCuboids(event, ui)'  ondragover='allowDrop(event)'><font size='1' color='red'> Trash bin </font></div>" +
  "<div id='" + divDropLeCuboid  + "' class=liCollect ondrop='dropForLinkExport(event)'  ondragover='allowDrop(event)'><font size='1' color='red'>Drop Template Manifest Cuboid here</font></div>" +
  "<div id='" + divDropDwldCuboid  + "' class=dldCollect ondrop='dropForTMEntry(event)'  ondragover='allowDrop(event)'><font size='1' color='red'>Drop Template Cuboids here..</font></div>" +
  "</div>" 
);
Rahul Varadkar
fonte