Dlaczego ten element bloku wbudowanego jest przesuwany w dół?

238

Poniżej znajduje się mój kod i chcę zrozumieć, dlaczego #firstDiv jest spychany w dół przez wszystkie przeglądarki. Naprawdę chcę zrozumieć wewnętrzne działanie faktu, że jest on popychany w dół, a nie w ten czy inny sposób. (i wiem, jak wyrównać ich bluzki :))

I wiem, że jest przepełniony: ukryty, co go powoduje, ale nie jestem pewien, dlaczego popycha go w dół.

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
źródło

Odpowiedzi:

361

Zasadniczo dodałeś więcej bałaganu w swoim kodzie, co powoduje więcej zamieszania, więc najpierw próbuję usunąć bałagan, który utrudnia zrozumienie prawdziwego problemu.

Przede wszystkim musimy ustalić, jakie jest prawdziwe pytanie? Właśnie dlatego inline-blockelement „ ” jest przesuwany w dół.

Teraz zaczynamy to rozumieć i najpierw usuwamy bałagan.

1 - Dlaczego nie nadać wszystkim trzem divom tej samej szerokości obramowania? Dajmy to.

2 - Czy element pływający ma jakieś połączenie z elementem blokowym wstawionym w dół? Nie, to nie ma z tym nic wspólnego.

Więc całkowicie usunęliśmy ten div . I jesteś świadkiem tego samego zachowania elementu inline-block popychanego w dół.

Nadchodzi kolejna literatura, aby zrozumieć ideę pól liniowych i sposób ich wyłożenia w tej samej linii, szczególnie uważnie przeczytaj ostatni akapit, ponieważ leży odpowiedź na twoje pytanie.

Linia bazowa „bloku śródliniowego” jest linią bazową ostatniego pola liniowego w normalnym przepływie, chyba że nie ma żadnych pól liniowych w dopływie lub jeśli jego właściwość „przepełnienia” ma obliczoną wartość inną niż „widoczna”, w w takim przypadku linia bazowa jest dolną krawędzią marginesu.

Jeśli nie masz pewności co do linii bazowej, oto krótkie wyjaśnienie w prostych słowach.

Wszystkie znaki z wyjątkiem „gjpqy” są zapisywane na linii podstawowej, którą można pomyśleć o linii podstawowej, tak jakby narysować prostą linię poziomą, taką samą jak podkreślenie tuż pod tymi „losowymi znakami”, wówczas będzie to linia podstawowa, ale teraz, jeśli napiszesz dowolną z „gjpqy” znaki w tej samej linii, a następnie dolna część tych znaków spadnie poniżej linii.

Możemy więc powiedzieć, że wszystkie znaki oprócz „gjpqy” są napisane całkowicie powyżej linii podstawowej, podczas gdy część tych znaków jest zapisana poniżej linii podstawowej.

3 - Dlaczego nie sprawdzić, gdzie jest linia bazowa naszej linii? Dodałem kilka znaków, które pokazują linię bazową naszej linii.

4 - Dlaczego nie dodać także niektórych postaci do div, aby znaleźć ich linie bazowe w div? Tutaj niektóre znaki dodane w div, aby wyjaśnić linię bazową .

Teraz, gdy zrozumiesz o linii bazowej, przeczytaj następującą uproszczoną wersję o linii bazowej bloków wbudowanych.

i) Jeśli dla danego bloku wbudowanego właściwość przepełnienia jest ustawiona na widoczną (co jest domyślnie, więc nie trzeba go ustawiać). Wtedy jego linia bazowa byłaby linią bazową zawierającego blok linii.

ii) Jeśli dla danego bloku wbudowanego widoczna jest właściwość przepełnienia INNA NIŻ. Wtedy jego dolny margines będzie na linii podstawowej linii zawierającej pole.

  • Pierwszy punkt w szczegółach

Teraz spójrz na to jeszcze raz, aby wyjaśnić swoją koncepcję tego, co dzieje się z zielonym divem . Jeśli jeszcze jakieś zamieszanie, to tutaj dodaje się więcej znaków w pobliżu zielonej div, aby ustalić linię bazową zawierającego blok a zielona linia bazowa div jest wyrównana.

Cóż, teraz twierdzę, że mają tę samą linię bazową? DOBRZE?

5 - Dlaczego więc ich nie nakładać i nie sprawdzać, czy są odpowiednio dopasowane? Tak więc przynoszę trzeci div-left: 35px; sprawdzić, czy mają teraz ten sam poziom podstawowy ?

Teraz nasz pierwszy punkt został udowodniony.

  • Drugi punkt w szczegółach

Cóż, po wyjaśnieniu pierwszego punktu, drugi punkt jest łatwo przyswajalny i widać, że pierwszy div, który ma właściwość przepełnienia ustawioną na inną niż widoczna (ukryta), ma dolny margines na linii podstawowej linii.

Teraz możesz wykonać kilka eksperymentów, aby dodatkowo to zilustrować.

  1. Ustaw pierwsze przepełnienie div: widoczne (lub całkowicie je usuń) .
  2. Ustaw drugi przelew div: inny niż widoczny .
  3. Ustaw przepełnienie obu div: inne niż widoczne .

Teraz przywróć swój bałagan i sprawdź, czy wszystko jest w porządku.

  1. Przynieś swój pływający div (oczywiście trzeba
    zwiększyć szerokość ciała) Widzisz, że to nie ma wpływu.
  2. Przywróć te same nieparzyste marginesy .
  3. Ustaw zielony div na przepełnienie: widoczny, jak ustawiłeś w swoim pytaniu (to przesunięcie jest spowodowane wzrostem szerokości ramki z 1px do 5px, więc jeśli dostosujesz lewą stronę , zobaczysz, że nie ma problemu)
  4. Teraz usuń dodatkowe znaki, które dodałem, aby pomóc w zrozumieniu . (i oczywiście usuń lewy minus)
  5. Wreszcie zmniejsz szerokość ciała, ponieważ nie potrzebujemy już szerszego.

A teraz wróciliśmy do miejsca, od którego zaczęliśmy.

Mam nadzieję, że odpowiedziałem na twoje pytanie.

Gary Lindahl
źródło
1
Dziękuję za tak świetne wyjaśnienie, ale nie zrozumiałem, że „wtedy jego linia podstawowa byłaby linią bazową zawierającego blok linii”. Czy jest to to samo, co linia podstawowa, jak wyjaśniono w drugim punkcie?
Shawn Taylor
2
Spózniona odpowiedź. Właśnie zauważyłem ten sam problem i chciałem tylko podziękować Gary'emu Lindahlowi za wyjaśnienie NICE.
TimSPQR
+1 ntgCleaner Mimo, że doceniam dobre odpowiedzi, Gary'ego Lindahla jest tak wiele do przeczytania i brakuje mi tylko kilku wierszy, w których jest napisane „Rozwiązanie: XY”
Basic Coder
Uważam, że to szczegółowe wyjaśnienie jest niezwykle pouczające, dziękuję. Przez jakiś czas walczyłem z jedną koncepcją i stworzyłem zaktualizowany Fiddle, który może wyjaśnić innym.
jonsanders101
@ntgCleaner dzięki stary .. nawet po wszystkich wyjaśnieniach nie mogłem sprawić, żeby działało. ale twój komentarz to zrobił :)
supersan
329

Domyślna wartość vertical-alignw CSS to baselinei ta zasada obowiązuje również w przypadku inline-blockprzeczytania tego http://www.brunildo.org/test/inline-block.html

Napisz vertical-align:topw swoim inline-blockDIV.

Sprawdź to http://jsfiddle.net/WGCyu/1/

sandeep
źródło
3
Czy przeczytałeś moje pytanie? Nigdy nie prosiłem o rozwiązanie problemu.
Shawn Taylor
23
@ShawnTaylor: Tytuł pytania jest bardzo mylący. Instynktownie czytamy tytuł, a następnie strzelamy do kodu, jeśli taki istnieje. Rzadko czytamy tekst. To zły nawyk, ale prawdopodobnie powinieneś zrozumieć, dlaczego tak się dzieje. : P
Purag
@sandeep: jeśli chodzi o twoją edycję, to dlaczego firstDiv jest wyrównany do góry nawet po usunięciu z niego
Shawn Taylor
@sandeep: Podany przez Ciebie link ma charakter informacyjny, ale nie pomaga w tym pytaniu, ponieważ nie opisuje zachowania w display:inline-blockpołączeniu z float:left/right.
Zeta
2
@ThomasMcCabe Hardly; jeśli ktoś opublikuje złą odpowiedź, zasługuje na pochwałę, aby zasygnalizować przyszłym widzom, że coś jest z nią nie tak, bez względu na ich dobre intencje. To powiedziawszy, nie sądzę, aby ta odpowiedź kiedykolwiek zasługiwała na głosowanie; nawet w oryginalnej formie stanowi kluczowy element układanki pominięty w zaakceptowanej odpowiedzi - to wyrównanie linii bazowej nie jest jedynym sposobem, w jaki elementy wyrównują się w pionie, a jeśli zmienisz vertical-alignwłaściwość, żadna ze złożoności opisanych w obowiązuje zaakceptowana odpowiedź.
Mark Amery
9

Zobacz ten alternatywny przykład. Przyczynę takiego zachowania opisano w module CSS3: wiersz: 3.2. Owijanie Line Box [1] :

Zasadniczo krawędź początkowa pola linii dotyka krawędzi początkowej jego bloku zawierającego, a krawędź końcowa dotyka krawędzi końcowej bloku zawierającego. Jednak ramki pływające mogą znajdować się między zawierającą blok krawędzią a krawędzią ramki liniowej. Tak więc, chociaż pola liniowe w tym samym kontekście formatowania liniowego mają na ogół ten sam postęp liniowy (w bloku zawierającym), mogą się one różnić, jeśli dostępna przestrzeń progresji liniowej jest zmniejszona ze względu na zmiennoprzecinkowe [...]

Jak widać, trzeci element jest przesuwany w dół, chociaż nie ma overflowwłaściwości. Powodem musi być gdzie indziej do znalezienia. Drugie zauważone zachowanie opisano w Kaskadowych arkuszach stylów Poziom 2, wersja 1 (CSS 2.1) Specyfikacja: 9.5 Floats [2] :

Ponieważ liczba zmiennoprzecinkowa nie znajduje się w przepływie, niepozycjonowane pola bloków utworzone przed i za zmiennoprzecinkową pływają pionowo, tak jakby zmienna nie istniała. Jednak bieżące i kolejne pola liniowe utworzone obok pływaka są w razie potrzeby skracane, aby zrobić miejsce dla pola marginesu pływaka.

Wszystkie twoje display:inline-block;div używają baselinew tym przypadku specjalnego rodzaju 10.8 Obliczenia wysokości linii: właściwości „wysokość linii” i „wyrównanie w pionie” (na samym końcu) [3] :

Linia bazowa „bloku śródliniowego” jest linią bazową ostatniego pola liniowego w normalnym przepływie, chyba że nie ma żadnych pól liniowych w dopływie lub jeśli jego właściwość „przepełnienia” ma obliczoną wartość inną niż „widoczna”, w w takim przypadku linia bazowa jest dolną krawędzią marginesu.

Kiedy więc używasz elementów i inline-blockelementów pływających, element pływający zostanie przesunięty na bok, a formatowanie wbudowane zostanie ponownie obliczone zgodnie z 1 . Z drugiej strony kolejne elementy są skracane, jeśli nie pasują. Ponieważ pracujesz już z minimalną ilością miejsca, nie ma innego sposobu na zmodyfikowanie elementów niż ich przesunięcie 2 . W tym przypadku najwyższy element określi rozmiar owinięcia div, tym samym definiując baseline 3 , podczas gdy z drugiej strony modyfikacja pozycji i szerokości określona w 2 nie może być zastosowana do tak minimalnie rozmieszczonych elementów o maksymalnej wysokości. W takim przypadku nastąpi zachowanie takie jak w mojej pierwszej wersji demo.

Wreszcie, powód swojej overflow:hiddenuniemożliwi #firstDivzostać przesunięta do dolnej krawędzi twoich #container, choć nie mogę znaleźć powód w punkcie 11 . Bezoverflow:hidden tego działa jak wyjątki i zdefiniowane przez 2 i 3 . Próbny

TL; DR: Przyjrzyj się dokładnie zaleceniom W3 i implementacjom w przeglądarce. Moim skromnym zdaniem elementy pływające są zdeterminowane, aby wykazywać nieoczekiwane zachowanie, jeśli nie znasz wszystkich zmian, które wprowadzają w otaczających elementach. Oto kolejne demo które pokazuje typowy problem z pływakami.

Zeta
źródło
3
Ten „standard” to niewiarygodny bałagan. To niesamowite, że udało się sprawić, że te rzeczy zachowują spójność w różnych przeglądarkach. Och, czekaj, nie, nigdy nie byli w stanie tego zrobić.
Triynko
6

Początkowo zacząłem odpowiadać na to pytanie , ale zanim skończyłem, zostało zablokowane jako dupe, więc zamiast tego zamieszczam tutaj odpowiedź.

Po pierwsze musimy zrozumieć, co inline-blockjest. Definicja w MDN mówi:

Element generuje pole elementu blokowego, które będzie przepływać z otaczającą zawartością, tak jakby to było pojedyncze pole śródliniowe (zachowując się podobnie jak element zastąpiony)

Aby zrozumieć, co się tutaj dzieje, musimy przyjrzeć się vertical-alignjego wartości domyślnej baseline.

wizualizacje pozycji pionowej
Na tej ilustracji przedstawiono następującą paletę kolorów:
Niebieski: linia podstawowa
Czerwony: góra i dół wysokości linii
Zielony: góra i dół pola zawartości w wierszu .

W elemencie #left znajduje się treść tekstowa, która kontroluje linię bazową. Oznacza to, że tekst wewnątrz określa linię bazową dla #left.
W #right nie ma treści, więc przeglądarka nie ma innej opcji niż użycie dolnej krawędzi pola jako linii bazowej.

Zobacz tę wizualizację, w której narysowałem linię bazową na przykładzie, w którym pierwszy kontener wbudowany zawiera tekst, a następny jest pusty:

Narysowana linia bazowa

Jeśli specjalnie wyrównasz jeden element do góry, naprawdę mówisz, że wyrównujesz górę tego elementu do góry pola linii.

Przykład może być łatwiejszy do zrozumienia.

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>

Rezultat jest następujący - i dodałem niebieską linię bazową oraz czerwone pole linii: To, co się tutaj dzieje, polega na tym, że wysokość pola linii zależy od tego, jak jest ułożona zawartość całej linii. Oznacza to, że aby obliczyć górne wyrównanie, najpierw należy obliczyć wyrównanie linii bazowej. Element ma , więc nie jest używany do ustawiania początkowej. ale i są ustawione pionowo, tak aby ich linie bazowe były wyrównane. Po wykonaniu tej czynności wysokość pola linii wzrosła, ponieważ element został nieco przesunięty w górę w wyniku większego rozmiaru czcionki. Następnie można obliczyć górną pozycję elementu, która znajduje się na górze pola linii.Wyjaśnione wyrównywanie pionowe
#middlevertical-align:top#left#right#right#middle

groza
źródło
1

problem polega na tym, że zastosowałeś float: left na drugim div. co sprawia, że ​​drugi div przychodzi po lewej stronie, a pierwszy div spada i przychodzi po drugim div. Jeśli zastosujesz float: pozostawiony również na pierwszym divu, twój problem zniknie.

przepełnienie: ukryte nie powoduje żadnego problemu w układzie, przepełnienie: ukryte wpływa tylko na wewnętrzne elementy div, nie ma to nic wspólnego z innymi elementami, które są na zewnątrz.

Pal Singh
źródło
Cóż, jeśli jest wypychany, ponieważ zajmuje drugie miejsce po zmiennym div, to dlaczego thirdDiv nie idzie w dół?
Shawn Taylor
ponieważ trzeci div ma przed nim drugi div, który nie ma pływaka: left;
Pal Singh
Ale gdzie wspomniana jest ta zasada, że ​​jeśli jakiś div przyjdzie po div floated, to spadnie w dół? Sprawdziłem w3.org.
Shawn Taylor
element, który nie unosi się, spada do linii podstawowej i jeśli zrobiłeś głos negatywny, to muszę powiedzieć, że była to najbardziej logiczna odpowiedź
Pal Singh
Nie, nie głosowałem negatywnie i tak, twoja odpowiedź nie zasługuje na negatywną. Właśnie zagłosowałem w górę.
Shawn Taylor
0

Spróbuj dodać padding:0;do ciała i usunąć margines swoich div.

Dodaj background-color:*anykolor oprócz tła *, aby sprawdzić różnicę.

LOLZ
źródło
Edytuj odpowiedź na formatuj kod. Możesz sformatować kod, dodając symbol `przed uruchomieniem kodu i po jego zakończeniu. jak codenp .: background-color:any color
JINO SHAJI,
0

Spróbuj, aby wszystkie właściwości CSS wszystkich elementów były takie same.

Miałem podobny problem i podczas naprawy stwierdziłem, że upuszczam element z właściwością Font do elementu Div.

Po upuszczeniu tego elementu z właściwością Font wyrównanie całego DIV zostało zaburzone. Aby to naprawić, ustawiam właściwość Font na wszystkie elementy DIV tak samo, jak element, który jest do niej upuszczany.

W poniższym przykładzie element Dropped klasy „.dldCuboidButton” zdefiniowany przy użyciu rozmiaru czcionki: 30 px.

Dodałem więc tę samą właściwość do pozostałych klas tj. .CuboidRecycle, .liCollect, .dldCollect, które są używane przez elementy DIV. W ten sposób wszystkie elementy DIV wykonują te same pomiary przed i po wrzuceniu do niego elementu.

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

Oto przykład HTML tworzonego dynamicznie przy użyciu powyższego CSS.

$("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
źródło