Как заставить элемент inline-block заполнить оставшуюся часть строки?

186

Возможна ли такая вещь, используя CSS и два встроенных (или любых других) тега DIV вместо таблицы?

Версия таблицы такова (границы добавлены, чтобы вы могли видеть это):

<!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>

Он создает левый столбец с ФИКСИРОВАННОЙ ШИРИНОЙ (не в процентах по ширине) и правый столбец, который расширяется, заполняя оставшееся пространство в строке. Звучит довольно просто, правда? Кроме того, поскольку ничто не «плавает», высота родительского контейнера должным образом увеличивается, чтобы охватить высоту содержимого.

- НАЧАЛО RANT--
Я видел реализации «clear fix» и «holy grail» для многостолбцовых макетов с боковым столбцом фиксированной ширины, и они отстойные и сложные. Они изменяют порядок элементов, используют ширину в процентах или используют значения с плавающей запятой, отрицательные поля, а отношения между атрибутами «left», «right» и «margin» являются сложными. Кроме того, макеты чувствительны к субпикселям, поэтому добавление даже одного пикселя границ, отступов или полей нарушит весь макет и отправит перенос столбцов на следующую строку. Например, ошибки округления представляют собой проблему, даже если вы пытаетесь сделать что-то простое, например, поместить 4 элемента в линию с шириной каждого из них, равной 25%.
--END RANT--

Я пытался использовать "inline-block" и "white-space: nowrap;", но проблема в том, что я просто не могу получить 2-й элемент, чтобы заполнить оставшееся место в строке. Установка ширины на что-то вроде «width: 100% - (LeftColumWidth) px» будет работать в некоторых случаях, но выполнение вычисления в свойстве width на самом деле не поддерживается.

Triynko
источник
1
Я не думаю, что есть разумный способ сделать это, кроме как превратить это в display: table-*конструкцию, которая будет работать, но на самом деле не «более семантическая» (ужасный случай divсупа) и нарушает совместимость с IE6. Я лично буду придерживаться этого <table>, если кому-то не удастся придумать гениальную простую идею, которая работает без
Пекка,
51
Да. Я продолжаю сталкиваться со всеми этими аргументами «избегать таблиц» с заре эры CSS, и они сформулированы так, чтобы вы звучали как некомпетентный ленивый дебил, если вы все еще используете таблицы для макетов. Быстро отправьте десятилетие, и это все еще идеалистическая несбыточная мечта. Дело в том, что семантика макета потока SUCK для фиксированных, но гибких макетов, таких как пользовательские интерфейсы и формы. Правда в том, что умные люди будут использовать таблицы там, где это удобно, потому что они исчерпали все возможные CSS-решения и поняли, что все они несовершенны и значительно сложнее, чем просто использование таблицы.
Трийнко
4
Поплавки? Покажите мне рабочий код, в котором элементы конца строки не переносятся непредсказуемо, а границы и поля не нарушают компоновку. Вот что с ними не так. Кроме того, правильно ли расширяется родительский контейнер автоматически, чтобы охватить плавающие элементы без хаков "clear fix"? Я так не думаю.
Трийнко
Если у вас есть хотя бы один неплавающий элемент в родительском контейнере, значит, очищать поплавки - это не «взлом», не так ли? Помните, что CSS имеет свои корни в печати - см. Css-tricks.com/containers-dont-clear-floats для хорошего обсуждения того, почему вы не получаете автоматическую очистку.
Чоулетт
3
@Triynko: Это то, что я сделал ранее: jsfiddle.net/thirtydot/qx32C - я думаю, что это поражает большинство ваших очков. Я услышу вашу критику того демо, которое я сделал, и постараюсь исправить это потом.
Тридцать четыре

Ответы:

169

Смотрите: 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>


Почему я заменить margin-left: 100pxс overflow: hiddenна .right?

РЕДАКТИРОВАТЬ: Вот два зеркала для вышеупомянутой (мертвой) ссылки:

thirtydot
источник
60
Если вы называете себя веб-разработчиком, вам нужно нажать на эту ссылку. Я сделал, и я чувствовал себя подобно Жасмин в волшебной поездке ковра.
Крис Кричит
2
@ChrisShouts, это, вероятно, лучший способ описать это. Этот метод просто не имеет смысла, но опять же ... Прекрасный обходной путь для чего-то, что вы должны быть в состоянии явно сделать.
Mjvotaw
14
Переполнение скрыто не является решением. Предположим, вы не хотите скрывать переполнение правого контейнера. Это не позволяет размеру правильного контейнера заполнить оставшееся пространство в строке. Это пример двухлетнего вопроса, на который я до сих пор не обозначил ответ, потому что до сих пор нет удовлетворительного ответа.
Трийнко
3
Triynko: даже если вы используете 'overflow: hidden', обычно ничего не будет скрыто (по крайней мере, если у вас просто есть текст). Текст / элементы внутри div будут расположены так, чтобы они помещались внутри div (конечно, если у вас нет элемента, который больше, чем div).
CpnCrunch
1
@RMorrisey: Наверное, просто нужно немного box-sizing: border-boxна divс. Просто предположение, так как вы не предоставили демонстрацию, демонстрирующую поведение, которое вы описываете. При этом решение на display: tableоснове обычно лучше . Это очень старый вопрос, но я думаю, что из-за поведения OP я пытался избежать каких-либо действий с таблицами в этом вопросе.
тридцать пятого
65

Современное решение с использованием 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/

Пану Хорсмалахти
источник
4
изгиб и ширина дисплея 100% .. должен помнить
dreamerkumar
10
при использовании flex, почему бы не использовать flex: 1вместо width: 100%?
Итай Бар-Хаим
Для новичков в flexbox : flex: 1это сокращение от flex-grow: 1. Это атрибут сочетание: flex: <grow> <shrink> <basis>.
Таниус
1
Просто быстрое примечание, которое показывает: flex не поддерживается в IE <11, и очень глючит в 11.
Eric Shields
1
@EricShields это не должно мешать никому использовать Flexbox. В наше время flexbugsвы знаете.
Нейротрансмиттер
47

Совместим с обычными современными браузерами (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>

Морозный Z
источник
9
Аргумент против использования таблиц не имеет ничего общего с его характеристиками представления. Это связано с неуправляемой разметкой, путаницей стилей / документов и неправильной семантикой. Ни один из этих аргументов не относится к display:table.
Рич Ремер
Это не ответ, как inline-blockзаполнить оставшуюся часть строки.
Нейротрансмиттер
1
@TranslucentCloud Я согласен, что мой ответ не совсем соответствует названию вопроса, но он предоставляет способ заполнить доступную ширину, используя div, как указано в теле вопроса.
Морозный Z
1
Мне очень нравится это решение. Вам не нужно использовать некоторые странные стили, которые возникают из скрытой логики CSS (например, для скрытого переполнения).
Chaoste
4

Вы можете использовать calc (100% - 100px) для элемента жидкости вместе с display: inline-block для обоих элементов.

Имейте в виду, что между тегами не должно быть пробела, в противном случае вам придется учитывать это пространство и в калькуляторе.

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


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

Быстрый пример: http://jsfiddle.net/dw689mt4/1/

SuperIRis
источник
1

Я использовал flex-growсобственность для достижения этой цели. Вы должны будете установить display: flexродительский контейнер, затем вам нужно установить flex-grow: 1блок, который вы хотите заполнить оставшимся пространством, или так же, flex: 1как танус, упомянутый в комментариях.

Владислав Ковеченков
источник
0

Если вы не можете использовать overflow: hidden(потому что вы не хотите overflow: hidden) или вам не нравятся хаки / обходные пути CSS, вы можете вместо этого использовать JavaScript. Обратите внимание, что это может не сработать, потому что это 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/

Ник Мэннинг
источник