CSS: установка ширины / высоты в процентах минус пиксели

479

Я пытаюсь создать несколько CSS-классов многократного использования для большей согласованности и меньшего количества помех на моем сайте, и я застрял при попытке стандартизировать одну вещь, которую я часто использую.

У меня есть контейнер <div>, для которого я не хочу устанавливать высоту (потому что он будет варьироваться в зависимости от того, где на сайте он находится), и внутри него есть заголовок <div>, а затем неупорядоченный список элементов, и все с CSS, примененным к их.

Это выглядит примерно так:

Виджет

Я хочу , чтобы неупорядоченный список , чтобы занять оставшуюся комнату в контейнере <div>, зная , что заголовок <div>является 18pxвысоким. Я просто не знаю, как указать высоту списка как «результат 100%минус 18px».

Я видел этот вопрос, заданный в паре других контекстов на SO, но я подумал, что стоит спросить еще раз для моего конкретного случая. Кто-нибудь есть какие-либо советы в этой ситуации?

MegaMatt
источник
6
Установить маржу? ___
Кеннитм
@KennyTM, я полагаю, вы предлагаете, чтобы я поместил верхнюю границу в мой неупорядоченный список, скажем, 17px. Но это просто толкает весь список вниз; это не заставляет это уменьшаться, чтобы остаться в контейнере. По сути, его текущая высота сохраняется, но она просто уменьшается на 17 пикселей. Это не решает мою проблему, но я думаю, что это шаг в правильном направлении, потому что я видел другие подходы онлайн, которые использовали эту технику.
MegaMatt
Я только что решил эту проблему в своем вопросе, который я разместил здесь. stackoverflow.com/a/10420387/340947
Стивен Лу
Возможный дубликат CSS Как установить высоту div 100% минус nPx
200_success

Ответы:

895

Я понимаю, что это старый пост, но, учитывая, что он не был предложен, стоит упомянуть, что если вы пишете для CSS3-совместимых браузеров, вы можете использовать calc:

height: calc(100% - 18px);

Стоит отметить, что не все браузеры в настоящее время поддерживают стандартную функцию CSS3 calc (), поэтому может потребоваться реализация специфических для браузера версий этой функции, например:

/* Firefox */
height: -moz-calc(100% - 18px);
/* WebKit */
height: -webkit-calc(100% - 18px);
/* Opera */
height: -o-calc(100% - 18px);
/* Standard */
height: calc(100% - 18px);
Леви Ботельо
источник
5
Да, это нормально на данный момент.
Леви Ботелхо
1
У меня работает в IE10 и Chrome 27. Вы, сэр, мой чертов герой!
BrainSlugs83
3
@LeviBotelho Мой плохой. Не было места вокруг оператора.
пользователь
20
Также, если вы используете Less, вам лучше скомпилировать файл, lessc --strict-math=onчтобы меньше вычислять выражение внутри calc- просто проблема, с которой я столкнулся и потратил много времени (по состоянию на Less 2.0.0)
Дмитрий Войцеховский,
34
Обратите внимание , что пробелы вокруг знака минус не являются дополнительными: 100%-18px, 100%- 18pxи 100% -18pxне работает в браузерах я тестировал с.
nisetama
71

Для немного другого подхода вы можете использовать что-то вроде этого в списке:

position: absolute;
top: 18px;
bottom: 0px;
width: 100%;

Это работает до тех пор, пока родительский контейнер имеет position: relative;

Николас Галлер
источник
1
Спасибо чувак. родительский контейнер position: relative;меня сбил с толку.
Gthmb
Для тех, кто может задаться вопросом, как я: позиция должна быть absoluteв дочернем контейнере, это не может быть relative.
Грег
Продолжение (извините): Однако родительский элемент просто нуждается в позиционировании (может быть и absoluteслишком), и его также необходимо установить на 100% высоты.
Грег
1
К сожалению, он не работает на Safari iOS 8. (Протестировано нормально на стоковом браузере Android 4.1 и стандартном FF 34) :-(
Грег
Это может работать в некоторых случаях, но также может вызывать некоторые проблемы, поскольку абсолютно позиционированные элементы удаляются из обычного потока, см. Stackoverflow.com/a/12821537/4173303 .
Кристоф Вейс
26

Я использую Jquery для этого

function setSizes() {
   var containerHeight = $("#listContainer").height();
   $("#myList").height(containerHeight - 18);
}

затем я привязываю изменение размера окна, чтобы пересчитать его при каждом изменении размера окна браузера (если размер контейнера изменился с изменением размера окна)

$(window).resize(function() { setSizes(); });
puffpio
источник
12
@puffpio, конечно, JS - способ сделать это в каждом конкретном случае. Но, как я уже сказал, я пытаюсь сделать CSS универсальным, чтобы его можно было применять на нескольких страницах (которые, кстати, наследуют от главной страницы). Поэтому я бы предпочел не использовать JS. Но спасибо за ответ.
MegaMatt
7
Не помещайте свой стиль в JavaScript.
Грег
8
@greg, было бы полезно, если бы у CSS были еще несколько полезных функций. Некоторые вещи, за которые вы должны делать хаки, просто смешны.
Джонатан.
1
@puffpio Хорошее решение действительно. Но связывание событий в окне не является хорошим решением для меня. Если моя страница содержит 3-4 или более таких элементов, я должен обновить высоту и ширину каждого элемента в обработчике изменения размера окна. Это будет немного медленнее, чем решение CSS.
sachinjain024
1
«Не помещайте свой XYZ в JavaScript» - все равно, что сказать: «Не поддерживайте 80% рынка браузеров».
Beejor
16

Не определяйте высоту в процентах, просто установите top=0и bottom=0, вот так:

#div {
   top: 0; bottom: 0;
   position: absolute;
   width: 100%;
}
kaleazy
источник
Не могли бы вы объяснить, почему не установить высоту в процентах?
Шрикант Шарат
@ShrikantSharat Это часть спецификации визуального форматирования для абсолютно позиционированных элементов. Это решение использует преимущество возможности 5. «Высота» равна «Авто», «верх» и «низ» не являются «авто», тогда устанавливаются значения «авто» для «margin-top» и «margin-bottom» до 0 и решить для «высоты». Браузер может вычислить высоту элемента, потому что он знает, как далеко от вершины и низа его родителя он должен быть.
Росс Аллен
Кажется, это не работает, по крайней мере, в Firefox. Даже со всеми родительскими элементами, установленными в height:100%и display:block. В противном случае это было бы очень элегантное решение. Интересно, что margin:autoтакже не удается центрировать объект фиксированной ширины по вертикали, даже если он отлично работает по горизонтали.
Beejor
8

Предполагая высоту заголовка 17px

Список css:

height: 100%;
padding-top: 17px;

Заголовок css:

height: 17px;
float: left;
width: 100%;
ghoppe
источник
Да, это то, что я получал.
dclowd9901
1
Это не сработало так хорошо, как я надеялся. Мой неупорядоченный список запускается под заголовком div. Div заголовка занимает место в контейнере, поэтому добавление padding-top 17px в список просто толкает его вниз на 17px от того места, где оно уже есть на рисунке выше, а не на 17px от вершины div контейнера. Вот изображение того, что я получаю с помощью CSS, приведенного в ответе выше: i41.tinypic.com/mcuk1x.jpg . Тем не менее, я ценю эти усилия, и если вы думаете, что я что-то упускаю, пожалуйста, дайте мне знать. Кстати, у меня переполнение: auto также в неупорядоченном списке.
MegaMatt
2
Устранение неполадок было бы намного проще, если бы вы опубликовали реальный css, чтобы мы могли точно видеть, какие взаимодействия происходят. Еще одна вещь, которую вы можете попробовать - это отрицательная верхняя граница вашего ul. ul { margin-top: -17px; }
ghoppe
7
  1. Используйте отрицательные поля на элементе, который вы хотите, чтобы минус пиксели были отключены. (желаемый элемент)
  2. Делать overflow:hidden; на содержащий элемент
  3. Переключитесь overflow:auto;на нужный элемент.

Это сработало для меня!

desbest
источник
3
Для меня это сработало как прелесть (мне даже не нужно было менять переполнение). Отличное решение, спасибо!
Aaj
1
Просто восхитительно! Приятно было узнать о популярном решении «CSS calc», но это намного проще и имеет более широкую поддержку браузера. Отрицательные поля в идеальном!
Саймон Стейнбергер
Это очень элегантное и совместимое решение. Основным недостатком является то, что элемент должен быть фиксированной высоты. В противном случае вам нужно будет использовать JS или calc()центрировать его во время выполнения. Но во многих случаях это не должно быть проблемой. Следует также помнить, что использование множества отрицательных значений для полей, отступов и смещений может привести к путанице при дальнейшей отладке кода, поэтому постарайтесь не усложнять ситуацию.
Beejor
5

Попробуйте размер коробки. Для списка:

height: 100%;
/* Presuming 10px header height */
padding-top: 10px;
/* Firefox */
-moz-box-sizing: border-box;
/* WebKit */
-webkit-box-sizing: border-box;
/* Standard */
box-sizing: border-box;

Для заголовка:

position: absolute;
left: 0;
top: 0;
height: 10px;

Конечно, родительский контейнер должен иметь что-то вроде:

position: relative;
Светлый
источник
3

Еще один способ достижения той же цели: гибкие коробки . Сделайте контейнер гибким блоком столбца, и тогда вы будете иметь полную свободу, позволяя некоторым элементам иметь фиксированный размер (поведение по умолчанию) или заполнять / уменьшать пространство контейнера (с помощью flex-grow: 1 и flex- термоусадочные: 1).

#wrap {        
  display:flex;
  flex-direction:column;
}
.extendOrShrink {
  flex-shrink:1;
  flex-grow:1;
  overflow:auto;
}

Смотрите https://jsfiddle.net/2Lmodwxk/ (попробуйте расширить или уменьшить окно, чтобы заметить эффект)

Примечание: вы также можете использовать сокращенное свойство:

   flex:1 1 auto;
tarulen
источник
Я полагаю, что это может быть лучшим ответом сегодня, потому что это означает, что не нужно указывать установленную высоту для заголовка div (18px в моем исходном вопросе), и это означает, что не нужно вычитать такие вещи, как padding и margin. Нет установленных пикселей, и все заботится о себе.
MegaMatt
2

Я попробовал некоторые другие ответы, и ни один из них не работал так, как я хотел. Наша ситуация была очень похожа, когда у нас был заголовок окна, а размер окна можно было изменять с помощью изображений в теле окна. Мы хотели заблокировать соотношение сторон для изменения размера без необходимости добавлять в расчеты, чтобы учесть фиксированный размер заголовка, и чтобы изображение по-прежнему заполняло тело окна.

Ниже я создал очень простой фрагмент, который показывает, что мы в итоге сделали, и, кажется, хорошо работает в нашей ситуации и должен быть совместим с большинством браузеров.

В нашем элементе окна мы добавили поле размером 20px, которое способствует позиционированию относительно других элементов на экране, но не влияет на «размер» окна. Затем заголовок окна позиционируется абсолютно (что удаляет его из потока других элементов, поэтому он не вызывает смещение других элементов, таких как неупорядоченный список), а его верхняя часть позиционируется на -20px, что размещает заголовок внутри поля окна. Наконец, наш элемент ul добавляется в окно, и высота может быть установлена ​​на 100%, что заставит его заполнить тело окна (исключая поле).

*,*:before,*:after
{
  box-sizing: border-box;
}

.window
{
  position: relative;
  top: 20px;
  left: 50px;
  margin-top: 20px;
  width: 150px;
  height: 150px;
}

.window-header
{
  position: absolute;
  top: -20px;
  height: 20px;
  border: 2px solid black;
  width: 100%;
}

ul
{
  border: 5px dashed gray;
  height: 100%;
}
<div class="window">
  <div class="window-header">Hey this is a header</div>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
  </ul>
</div>

Ти Джей Рокфеллер
источник
1

Спасибо, я решил мою с вашей помощью, немного подправив, так как я хочу, чтобы div 100% ширина 100% высоты (меньше высота нижней панели) и никакой прокрутки на теле (без рубки / скрытия полос прокрутки).

Для CSS:

 html{
  width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }
 body{
  position:relative;width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }
 div.adjusted{
  position:absolute;width:auto;height:auto;left:0px;right:0px;top:0px;bottom:36px;margin:0px;border:0px;padding:0px;
 }
 div.the_bottom_bar{
  width:100%;height:31px;margin:0px;border:0px;padding:0px;
}

Для HTML:

<body>
<div class="adjusted">
 // My elements that go on dynamic size area
 <div class="the_bottom_bar">
  // My elements that goes on bottom bar (fixed heigh of 31 pixels)
 </div>  
</div>  

Это сработало, о да, я поставил значение немного больше на div.adjoted для bottom, чем для высоты нижнего бара, в противном случае появляется вертикальная полоса прокрутки, я настроен на ближайшее значение.

Это различие заключается в том, что один из элементов в динамической области добавляет дополнительную нижнюю дыру, от которой я не знаю, как избавиться ... это видео-тег (HTML5), обратите внимание, я поставил этот видео-тег с этим CSS ( так что нет причин для того, чтобы сделать нижнюю яму, но это так):

 video{
  width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }

Объективно: иметь видео, которое занимает 100% браузера (и динамически изменяет размер при изменении размера браузера, но без изменения соотношения сторон), за исключением нижнего пространства, которое я использую для div с некоторыми текстами, кнопками и т. Д. (И валидаторами) W3C & CSS конечно).

РЕДАКТИРОВАТЬ: Я нашел причину, видео тег похож на текст, а не элемент блока, поэтому я исправил это с помощью этого CSS:

 video{
  display:block;width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }

Обратите внимание display:block;на тег видео.

Claudio
источник
0

Я не уверен, работает ли это в вашей конкретной ситуации, но я обнаружил, что заполнение внутреннего элемента div будет перемещать содержимое внутри элемента div, если содержащийся элемент div имеет фиксированный размер. Вам придется либо плавать, либо абсолютно позиционировать элемент заголовка, но в противном случае я не пробовал это для div с переменным размером.

dclowd9901
источник