7 июня 2022 г.

Особенности свойства height в %

Обычно свойство height, указанное в процентах, означает высоту относительно внешнего блока.

Однако, всё не так просто. Интересно, что для произвольного блочного элемента height в процентах работать не будет!

Чтобы лучше понимать ситуацию, рассмотрим пример.

Пример

Наша цель – получить вёрстку такого вида:

При этом блок с левой стрелкой должен быть отдельным элементом внутри контейнера.

Это удобно для интеграции с JavaScript, чтобы отлавливать на нём клики мыши.

То есть, HTML-код требуется такой:

<div class="container">
  <div class="toggler">
    <!-- стрелка влево при помощи CSS, ширина фиксирована -->
  </div>
  <div class="content">
    ...Текст...
  </div>
</div>

Как это реализовать? Подумайте перед тем, как читать дальше…

Придумали?.. Если да – продолжаем.

Есть разные варианты, но, возможно, вы решили сдвинуть .toggler влево, при помощи float:left (тем более что он фиксированной ширины) и увеличить до height: 100%, чтобы он занял всё пространство по вертикали.

Вы ещё не видите подвох? Смотрим внимательно, что будет происходить с height: 100%

Демо height:100% + float:left

CSS:

.container {
  border: 1px solid black;
}

.content {
  /* margin-left нужен, так как слева от содержимого будет стрелка */
  margin-left: 35px;
}

.toggler {
  /* Зададим размеры блока со стрелкой */
  height: 100%;
  width: 30px;
  float: left;

  background: #EEE url("arrow_left.png") center center no-repeat;
  border-right: #AAA 1px solid;
  cursor: pointer;
}

А теперь – посмотрим этот вариант в действии:

Как видно, блок со стрелкой вообще исчез! Куда же он подевался?

Ответ нам даст спецификация CSS 2.1 пункт 10.5.

«Если высота внешнего блока вычисляется по содержимому, то высота в % не работает, и заменяется на height:auto. Кроме случая, когда у элемента стоит position:absolute

В нашем случае высота .container как раз определяется по содержимому, поэтому для .toggler проценты не действуют, а размер вычисляется как при height:auto.

Какая же она – эта автоматическая высота? Вспоминаем, что обычно размеры float определяются по содержимому (10.3.5). А содержимого-то в .toggler нет, так что высота нулевая. Поэтому этот блок и не виден.

Если бы мы точно знали высоту внешнего блока и добавили её в CSS – это решило бы проблему.

Например:

/*+ no-beautify */
.container {
  height: 200px; /* теперь height в % внутри будет работать */
}

Результат:

…Но в данном случае этот путь неприемлем! Ведь мы не знаем, сколько будет текста и какой будет итоговая высота.

Поэтому решим задачу по-другому.

Правильно: height:100% + position:absolute

Проценты будут работать, если поставить .toggler свойство position: absolute и спозиционировать его в левом-верхнем углу .container (у которого сделать position:relative):

.container {
  position: relative;
  border: 1px solid black;
}

.content {
  margin-left: 35px;
}

.toggler {
  position: absolute;
  left: 0;
  top: 0;

  height: 100%;
  width: 30px;
  cursor: pointer;

  border-right: #AAA 1px solid;
  background: #EEE url("arrow_left.png") center center no-repeat;
}

Результат:

Проблема с height: 100%, проявляющаяся, когда у родительского элемента не установлен height, но указан min-height

Вам необходимо установить height: 1px для родителя, чтобы дочерний элемент смог занять всю высоту указанную в min-height.

.parent {
    min-height: 300px;
    height: 1px; /* Требуется, чтобы дочерний блок взял высоту 100% */
}

.child {
    height: 100%;
}

Итого

  • Свойство height, указанное в %, работает только если для внешнего блока указана высота.
  • Стандарт CSS 2.1 предоставляет обход этой проблемы, отдельно указывая, что проценты работают при position:absolute. На практике это часто выручает.
  • Если у родительского элемента не установлено height, а указано min-height, то, чтобы дочерний блок занял 100% высоты, нужно родителю поставить свойство height: 1px;
Карта учебника