Jak sprawić, by element bloku wbudowanego wypełniał resztę wiersza?

186

Czy taka rzecz jest możliwa przy użyciu CSS i dwóch tagów DIV z wbudowanym blokiem (lub czymkolwiek) zamiast tabeli?

Wersja tabeli jest następująca (dodano ramki, dzięki czemu można ją zobaczyć):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
<table style="width:100%;">
<tr>
<td style="border:1px solid black;width:100px;height:10px;"></td>
<td style="border:1px solid black;height:10px;"></td>
</tr>
</table>
</body>
</html>

Tworzy lewą kolumnę o STAŁEJ SZEROKOŚCI (nie procentowej szerokości) i prawą kolumnę, która rozszerza się, aby wypełnić PRZESTRZEŃ POZOSTAŁĄ w wierszu. Brzmi dość prosto, prawda? Ponadto, ponieważ nic nie jest „unoszone”, wysokość kontenera nadrzędnego odpowiednio powiększa się, aby objąć wysokość zawartości.

- POCZĄTEK RANT
- Widziałem implementacje „clear fix” i „Holy Graal” dla układów wielokolumnowych z kolumną boczną o stałej szerokości, a one są do kitu i są skomplikowane. Odwracają kolejność elementów, używają szerokości procentowych lub używają liczb zmiennoprzecinkowych, marginesów ujemnych, a związek między atrybutami „lewy”, „prawy” i „margines” jest złożony. Co więcej, układy są wrażliwe na subpiksele, więc dodanie nawet jednego piksela ramek, wypełnienia lub marginesów spowoduje uszkodzenie całego układu i przeniesienie zawijania całych kolumn do następnego wiersza. Na przykład błędy zaokrąglania są problemem, nawet jeśli próbujesz zrobić coś prostego, na przykład umieścić 4 elementy w linii, a szerokość każdego z nich wynosi 25%.
--END RANT--

Próbowałem użyć „inline-block” i „white-space: nowrap;”, ale problem polega na tym, że po prostu nie mogę uzyskać drugiego elementu do wypełnienia pozostałego miejsca w linii. Ustawienie szerokości na coś w rodzaju „szerokość: 100% - (LeftColumWidth) px” będzie działać w niektórych przypadkach, ale wykonywanie obliczeń we właściwości width nie jest tak naprawdę obsługiwane.

Triynko
źródło
1
Nie sądzę, że istnieje rozsądny sposób, aby to zrobić, z wyjątkiem przekształcenia go w display: table-*konstrukcję, która zadziała, ale nie jest też tak naprawdę „bardziej semantyczna” (jest to straszny przypadek divzupy) i łamie kompatybilność z IE6. Osobiście trzymałbym się tego <table>, chyba że komuś uda się wymyślić genialny prosty pomysł, który działa bez
Pekka
51
Tak. Ciągle napotykam na te wszystkie argumenty „unikaj tabel” od zarania ery CSS, a ich sformułowania sprawiają, że brzmisz jak niekompetentny leniwy kretyn, jeśli nadal używasz tabel do układów. Przewiń do przodu o dekadę, a to wciąż idealistyczny marzenie o fajce. Faktem jest, że semantyka układu przepływu SUCK dla stałych, ale elastycznych układów, takich jak interfejsy użytkownika i formularze. Prawda jest taka, że ​​inteligentni ludzie będą używać tabel tam, gdzie jest to wygodne, ponieważ wyczerpali wszystkie możliwe rozwiązania CSS i zdali sobie sprawę, że wszystkie są niedoskonałe i znacznie bardziej złożone niż zwykłe korzystanie ze stołu.
Triynko
4
Pływaki? Pokaż mi działający kod, w którym elementy końca linii nie zawijają się nieprzewidywalnie, a granice i marginesy nie psują układu. To jest z nimi nie tak. Ponadto, czy kontener nadrzędny o automatycznym rozmiarze prawidłowo rozszerza się, aby objąć elementy pływające bez hacków „clear fix”? Nie myślałem tak.
Triynko
Jeśli masz co najmniej jeden element pływający w kontenerze nadrzędnym, to tak naprawdę nie jest to „hack” do usuwania pływaków, prawda? Pamiętaj, że CSS ma swoje korzenie w drukowaniu - zobacz css-tricks.com/containers-dont-clear-floats, aby uzyskać dobre omówienie powodów braku automatycznego czyszczenia.
Chowlett
3
@Triynko: Oto, co zrobiłem wcześniej: jsfiddle.net/thirtydot/qx32C - Myślę, że trafia w większość twoich punktów. Usłyszę twoją krytykę tego dema, które zrobiłem, i spróbuję to naprawić później.
thirtydot

Odpowiedzi:

169

Zobacz: http://jsfiddle.net/qx32C/36/

.lineContainer {
    overflow: hidden; /* clear the float */
    border: 1px solid #000
}
.lineContainer div {
    height: 20px
} 
.left {
    width: 100px;
    float: left;
    border-right: 1px solid #000
}
.right {
    overflow: hidden;
    background: #ccc
}
<div class="lineContainer">
    <div class="left">left</div>
    <div class="right">right</div>
</div>


Dlaczego wymienić margin-left: 100pxz overflow: hiddenna .right?

EDYCJA: Oto dwa kopie lustrzane powyższego (martwego) linku:

trzydzieści
źródło
60
Jeśli nazywasz się programistą, musisz kliknąć ten link. Tak zrobiłem i czułem się jak Jasmine na magicznej przejażdżce dywanowej.
Chris Shouts
2
@ChrisShouts, to prawdopodobnie najlepszy sposób na opisanie tego. Ta metoda po prostu nie ma sensu, ale z drugiej strony ... Cudowne obejście czegoś, co powinieneś być w stanie zrobić wyraźnie.
mjvotaw
14
Przepełnienie ukryte nie jest rozwiązaniem. Załóżmy, że nie chcesz ukryć przelewu odpowiedniego kontenera. Nie powoduje to, że rozmiar odpowiedniego pojemnika wypełnia pozostałe miejsce w linii. To przykład dwuletniego pytania, na które wciąż nie zaznaczyłem odpowiedzi, ponieważ wciąż nie ma zadowalającej odpowiedzi.
Triynko
3
Triynko: nawet jeśli używasz opcji „przepełnienie: ukryte”, ogólnie nic nie będzie ukryte (przynajmniej jeśli masz tam tylko tekst). Tekst / elementy wewnątrz div będą ułożone tak, aby pasowały do ​​div (oczywiście jeśli nie masz elementu większego niż div).
CpnCrunch,
1
@RMorrisey: Prawdopodobnie tylko potrzebuje trochę box-sizing: border-boxna divs. Tylko zgadnij, ponieważ nie dostarczyłeś dema pokazującego opisywane zachowanie. Mając na uwadze powyższe, -na rozwiązanie jest zazwyczaj lepiej . To bardzo stare pytanie, ale myślę, że starałem się unikać cokolwiek wspólnego z tabelami w tym pytaniu ze względu na zachowanie OP. display: table
thirtydot
65

Nowoczesne rozwiązanie wykorzystujące Flexbox:

.container {
    display: flex;
}
.container > div {
    border: 1px solid black;
    height: 10px;
}

.left {
   width: 100px;
}

.right {
    width: 100%;
    background-color:#ddd;
}
<div class="container">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/m5Xz2/100/

Panu Horsmalahti
źródło
4
wyświetl flex i szerokość 100% .. muszę pamiętać
dreamerkumar
10
jeśli korzystasz z Flex, dlaczego nie użyć flex: 1zamiast width: 100%?
Itai Bar-Haim
Dla nowych użytkowników Flexboksa : flex: 1jest skrótem od flex-grow: 1. Jest to atrybut kombinacji: flex: <grow> <shrink> <basis>.
tanius
1
Krótka uwaga, że ​​display: flex nie jest obsługiwany w IE <11, a bardzo błędny w 11.
Eric Shields,
1
@EricShields nie powinno to uniemożliwiać nikomu korzystania z Flexbox. W dzisiejszych czasach wiemy flexbugs, że.
Neurotransmitter
47

Kompatybilny z popularnymi współczesnymi przeglądarkami (IE 8+): http://jsfiddle.net/m5Xz2/3/

.lineContainer {
    display:table;
    border-collapse:collapse;
    width:100%;
}
.lineContainer div {
    display:table-cell;
    border:1px solid black;
    height:10px;
}
.left {
    width:100px;
}
 <div class="lineContainer">
    <div class="left">left</div>
    <div class="right">right</div>
</div>

Frosty Z
źródło
9
Argument przeciwko używaniu tabel nie ma nic wspólnego z jego charakterystyką prezentacji. Ma to związek z niemożliwymi do zarządzania znacznikami, myleniem stylu / dokumentu oraz niewłaściwą semantyką. Żaden z tych argumentów nie dotyczy display:table.
Rich Remer
Nie odpowiada to, jak inline-blockwypełnić resztę wiersza.
Neurotransmitter
1
@TranslucentCloud Zgadzam się, że moja odpowiedź nie odpowiada dokładnie na tytuł pytania, ale zapewnia sposób wypełnienia dostępnej szerokości za pomocą div, zgodnie z pytaniem zawartym w treści pytania.
Frosty Z
1
Bardzo podoba mi się to rozwiązanie. Nie musisz zmuszać się do używania dziwnych stylów, które wynikają z ukrytej logiki CSS (jak w przypadku ukrytego przepełnienia).
Chaoste,
4

Możesz użyć obliczeń (100% - 100px) na elemencie płynnym wraz z wyświetlaczem: blok wstawiany dla obu elementów.

Pamiętaj, że między tagami nie powinno być odstępu, w przeciwnym razie będziesz musiał wziąć to pod uwagę również w swoich kalkulacjach.

.left{
    display:inline-block;
    width:100px;
}
.right{
    display:inline-block;
    width:calc(100% - 100px);
}


<div class=“left”></div><div class=“right”></div>

Szybki przykład: http://jsfiddle.net/dw689mt4/1/

SuperIRis
źródło
1

Użyłem flex-grownieruchomości, aby osiągnąć ten cel. Będziesz musiał ustawić display: flexkontener nadrzędny, a następnie ustaw flex-grow: 1blok, który chcesz wypełnić pozostałą przestrzeń, lub tak flex: 1jak tanio wspomniany w komentarzach.

Vladislav Kovechenkov
źródło
0

Jeśli nie możesz używać overflow: hidden(bo nie chcesz overflow: hidden) lub jeśli nie lubisz haków / obejść CSS, możesz zamiast tego użyć JavaScript. Pamiętaj, że może nie działać tak dobrze, ponieważ jest JavaScript.

var parent = document.getElementsByClassName("lineContainer")[0];
var left = document.getElementsByClassName("left")[0];
var right = document.getElementsByClassName("right")[0];
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
window.onresize = function() {
  right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
}
.lineContainer {
  width: 100% border: 1px solid #000;
  font-size: 0px;
  /* You need to do this because inline block puts an invisible space between them and they won't fit on the same line */
}

.lineContainer div {
  height: 10px;
  display: inline-block;
}

.left {
  width: 100px;
  background: red
}

.right {
  background: blue
}
<div class="lineContainer">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/ys2eogxm/

Nick Manning
źródło