Перевод «Min and Max Width/Height in CSS» Ахмада Шадида.

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

В этой статье мы познакомимся с CSS-свойствами максимума и минимума для ширины и высоты, а также детально рассмотрим каждое из них и сценарии их использования.

Свойства ширины


Начать обсуждение хотелось бы со свойств, связанных с шириной. У нас есть min-width и max-width, и каждое из них крайне важно и полезно в определённых ситуациях.

Минимальная ширина (min-width)


Своство min-width предназначено для предотвращения уменьшения ширины элемента ниже заданного значения. Значением по умолчанию является auto, которое может доходить до 0.

Чтобы продемонстрировать его, давайте рассмотрим базовый пример:



Есть кнопка с текстом, размер которого может меняться от одного до нескольких слов. Чтобы быть уверенным, что эта кнопка будет иметь минимально допустимую ширину, даже если внутри будет только одно слово, нужно использовать min-width. Минимальную ширину задали равной 100px, поэтому даже если у кнопки будет очень короткое содержимое, как, например, только слово «Done» или только иконка, она всё равно будет достаточно большой, чтобы оставаться заметной. Это особенно важно, когда вы работаете с сайтами, переведёнными на разные языки

Рассмотрим пример с арабским языком в Twitter:



В примере выше кнопка содержит слово “??”, что на арабском значит «Готово». Из-за короткого содержимого ширина и самой кнопки стала слишком мала, поэтому я обозначил минимум, задав ей свойство min-width, что можно увидеть на изображении справа (в секции «After»).

Минимальная ширина и Padding


Хотя свойство min-width и допускает увеличение ширины кнопки при увеличении размера её содержимого, по бокам всё же следует задавать padding, чтобы гарантировать внутренний отступ от её границ. Разница приведена на рисунке ниже



Максимальная ширина (max-width)


Свойство max-width предназначено для предотвращения увеличения ширины элемента выше заданного значения. Значение по умолчанию – none.

Распространённый и простой пример использования max-width заключается в его применении к изображениям. Рассмотрим пример ниже:



Если к изображению применить свойство max-width: 100% оно останется в границах родительского элемента, даже при том, что его изначальный размер больше. Если же изображение изначально меньше родителя, данное свойство никак на него не повлияет.

Использование min-width и max-width




Если к элементу применяются оба свойства, какое из них переопределит значение другого? Другими словами, у какого свойства приоритет выше?

Если значение min-width больше, чем max-width, оно будет принято за ширину элемента. Рассмотрим следующий пример:

HTML

<div class="wrapper">
  <div class="sub"></div>
</div>

CSS

.sub {
  width: 100px;
  min-width: 50%;
  max-width: 100%;
}



Исходное значение width равно 100px и в дополнение к этому заданы значения свойств min-width и max-width. В результате ширина данного элемента не будет превышать 50% ширины родительского блока


Свойства высоты


В дополнение к свойствам минимальной и максимальной ширины, есть такие же свойства для высоты

Минимальная высота (min-height)


Свойство min-height предназначено для предотвращения уменьшения высоты элемента ниже заданного значения. Значением по умолчанию является auto, которое может доходить до 0.

Чтобы продемонстрировать его, давайте рассмотрим простой пример.

У нас есть секция с текстовым содержимым. Необходимо, чтобы она смотрелась красиво как с большим, так и с малым количеством текста



CSS

.sub {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  min-height: 100px;
  color: #fff;
  background: #3c78dB;
}

Минимальная высота задана 100px, а содержимое центрировано с помощью flexbox по горизонтали и вертикали. Что произойдёт, если содержимого станет больше? Например, будет целый абзац



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

Максимальная высота (max-height)


Свойство max-height предназначено для предотвращения увеличения высоты элемента больше заданного значения. Значением по умолчанию является none.

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



Примеры использования свойств


Рассмотрим некоторые распространённые и редкие сценарии использования свойств min-width, min-height, max-width, и max-height

Список тегов


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



Обладая такой гибкостью, тег будет хорошо выглядеть независимо от того, насколько коротким является его содержимое. Но что случится, если автор задал очень большое имя тега, а используемая им CMS (content management system) не имеет ограничений по количеству символов в теге? В этой ситуации также можно использовать max-width

CSS

.c-tag {
  display: inline-block;
  min-width: 100px;
  max-width: 250px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  /*Other styles*/
}

С помощью max-width можно ограничить максимальную ширину определённым значением. Однако, недостаточно применения только этого свойства. Содержимое, превышающее максимальную ширину, должно быть усечено.

https://codepen.io/shadeed/pen/320e42b7ad75c438a9e633417d737d16

Кнопки


Существуют разные сценарии использования свойств минимума и максимума для кнопок, поскольку и самих вариантов компонентов кнопок также немало. Рассмотрим следующий макет:



Обратите внимание, что ширина кнопки «Get» слишком мала. Если по какой-то причине у кнопки еще и не будет текста (а только иконка), всё может стать еще хуже. В этом случае установка минимальной ширины очень важна

Обнуление минимальной ширины для Flexbox


Значение по умолчанию у свойства min-width равняется auto, что вычисляется как ноль. Когда элемент является flex-элементом, значение min-width не становится нулём. Минимальный размер flex-элемента равняется размеру его содержимого.

Согласно CSSWG:
По умолчанию, flex-элементы не становятся меньше минимального размера, необходимого их содержимому (длина самого длинного слова или элемента с фиксированным размером). Чтобы изменить это, задайте свойство min-width или min-height.

Рассмотрим следующий пример:



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

CSS

.c-person__name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

Поскольку заголовок является флекс-элементом, решение состоит в том, чтобы сбросить значение min-width и заставить его стать нулём

CSS

.c-person__name {
  /*Other styles*/
  min-width: 0;
}

Вот как это должно выглядеть после исправления:



Из описания в CSSWG следует, что установка свойства overflow в значение, отличное от visible, может привести к тому, что значение min-width будет вычислено как ноль, что также решает нашу проблему без необходимости явно задавать min-width: 0.


Обнуление минимальной высоты для Flexbox


Хотя это менее распространённая проблема по сравнению с min-width, она всё же может встретиться. Проблема связана с flex-элементами, которые не могут быть короче своего содержимого. В результате значение min-height устанавливается равным размеру контента.

Рассмотрим следующий пример:



Текст, окрашенный в красный цвет, должен быть обрезан границами контейнера. Но поскольку данный элемент является flex-элементом, его min-height равняется высоте содержимого. Чтобы предотвратить это, мы должны сбросить значение минимальной высоты. Давайте посмотрим на HTML и CSS код:

HTML

<div class="c-panel">
  <h2 class="c-panel__title"><!-- Title --></h2>
  <div class="c-panel__body">
    <div class="c-panel__content"><!-- Content --></div>
  </div>
</div>

CSS

.c-panel {
  display: flex;
  flex-direction: column;
  height: 180px;
}
 
.c-panel__body {
  min-height: 0;
}
 
.c-panel__content {
  overflow-y: scroll;
  height: 100%;
}

Добавление элементу min-height: 0 сбросит значение свойства и оно начнёт работать так, как ожидается
Демо



Одновременное использование min-width и max-width


Порой бывают ситуации, когда у нас есть элемент с минимальной шириной, но в то же время, максимальная ширина не задана. Это может привести к тому, что элемент станет слишком широким, хотя такое поведение не задумывалось. Рассмотрим следующий пример:



Поскольку ширина определена в пикселях, нет уверенности, что описанное выше будет работать для мобильных. Чтобы решить эту проблему, мы можем использовать проценты вместо пикселей для свойств минимума и максимума. Рассмотрим пример ниже:

Я добавил следующий CSS-код для изображений:

CSS

img {
  min-width: 35%;
  max-width: 70%;
}





Контейнер для страницы


Один из наиболее полезных сценариев применения свойства max-width – для обёртки (или контейнера) страницы. Задав странице максимальную ширину, мы можем быть уверены, что пользователям будет удобно просматривать и читать содержимое



Ниже приведён пример центрированной обёртки, имеющей padding слева и справа

CSS

.wrapper {
  max-width: 1170px;
  padding-left: 16px;
  padding-right: 16px;
  margin-left: auto;
  margin-right: auto;
}

Максимальная ширина и единица измерения «ch»




Единица измерения ch равняется ширине символа 0 (ноль), используемого в шрифте текущего элемента. Используя её в свойстве max-width, мы можем регулировать количество символов в строке. Согласно этой статье с сайта Smashing Magazine, рекомендованная длина строки от 45 до 75 символов.

В предыдущем примере с элементом-обёрткой, мы могли извлечь пользу от использования этого символа, поскольку это элемент статьи

CSS

.wrapper {
  max-width: 70ch;
  /* Other styles */
}

Анимирование элемента с неизвестной высотой


Порой мы сталкиваемся с проблемой анимирования аккордеона или мобильного меню с неизвестной высотой содержимого. В этом случае применение max-height может быть хорошим решением.

Рассмотрим следующий пример:



Когда нажимается кнопка меню, само меню должно плавно появляться сверху вниз. Сделать это без JavaScript невозможно, если только у элемента не задана фиксированная высота (а это делать не рекомендуется). Тем не менее, это возможно с помощью max-height. Идея заключается в добавлении элементу очень большой высоты, например, max-height: 20rem, которая, не будет достигнута, после чего мы можем задать шаги анимации от max-height: 0, до max-height: 20rem

CSS

.c-nav {
  max-height: 0;
  overflow: hidden;
  transition: 0.3s linear;
}
 
.c-nav.is-active {
  max-height: 22rem;
}

Нажмите на гамбургера, чтобы увидеть анимацию в действии


Минимальная высота для верхней секции (hero)


Как видите, я не люблю задавать элементам фиксированную высоту. Я чувствую, что поступая так, иду против концепции, согласно которой компоненты в вебе должны быть гибкими. Добавление минимальной высоты для первой секции сайта (секция «hero») полезно в ситуациях, когда добавляется очень большое содержимое (такое бывает).

Рассмотрим следующий пример, где у нас есть секция «hero» с фиксировано заданной высотой. Вроде смотрится хорошо.



Однако, когда содержимое увеличивается, оно переполняет контейнер и выходит за рамки обёртки секции. Это плохо.



Чтобы заранее избежать этой проблемы, мы можем вместо height добавить min-height. Мы поступаем именно так, по крайней мере, для того, чтобы очистить нашу совесть. Даже при том, что это может быть причиной весьма странного отображения страницы, я считаю, что подобные ситуации должны быть предотвращены в первую очередь, в системе управления контентом (CMS). После этого проблема исправлена и страница выглядит хорошо:



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



Если задавать не фиксированную высоту, а лишь ограничивать минимальную с помощью min-height, описанная выше проблема не произойдёт вовсе.

Модальное окно


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

1 способ

.c-modal__body {
  width: 600px;
  max-width: 100%;
}

2 способ

.c-modal__body {
  width: 100%;
  max-width: 600px;
}

Что касается меня, я предпочитаю второй способ, так как мне нужно только определить max-width: 600px. Модальное окно – это элемент div, поэтому у него уже ширина задана = 100% от родителя, правильно?

Рассмотрим приведённый ниже пример с модальным окном. Обратите внимание, как ширина становится равной 100% от ширины родителя, если в области просмотра недостаточно свободного места




Минимальная высота и липкий footer


Когда содержимое страницы недостаточно большое, футер ожидаемо не прилипнет к нижней части. Давайте рассмотрим пример, который лучше продемонстрирует это:



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



Сначала я сделал элемент body flex-контейнером, после чего установил ему минимальную высоту 100% от области просмотра.

CSS

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
 
footer {
  margin-top: auto;
}

Рекомендую ознакомиться с этой статьёй о липких футерах.
Демо

Пропорциональные размеры элемента и max-width/height


Чтобы сделать пропорциональный контейнер, который масштабируется в зависимости от размера области просмотра, однажды был представлен хак с использованием padding. Сейчас мы можем имитировать похожее поведение, комбинируя единицы измерения области просмотра и максимальную ширину/высоту.

На основе материалов статьи Miriam Suzanne, я хочу объяснить, как это работает.



У нас есть изображение с размерами 644 x 1000 пикселей. Нам нужно сделать следующее:

  • Соотношение сторон: height / width (высоту поделить на ширину)
  • Ширина контейнера: может быть фиксированной или динамической (100%)
  • Задайте height, равный 100% ширины области просмотра, умноженной на соотношение сторон
  • Задайте max-height, равный ширине контейнера, умноженной на соотношение сторон
  • Задайте max-width, равное ширине контейнера

CSS

img {
  --ratio: 664 / 1000;
  --container-width: 30em;
  display: block;
  height: calc(100vw * var(--ratio));
  max-height: calc(var(--container-width) * var(--ratio));
  width: 100%;
  max-width: var(--container-width);
}




HTML/Body с высотой 100%


Что делать, если нам нужно, чтобы элемент body занимал 100% высоты области просмотра? Это распространённый вопрос как в веб-сообществе в целом, так и на сайте StackOverflow в частности.

Сначала нужно задать height: 100% элементу html. Это будет гарантировать, что корневой элемент имеет высоту 100%. Затем добавляем min-height для элемента body. Причина, по которой используется именно min-height в том, что это свойство позволяет высоте элемента body быть динамичной, и подстраиваться, каким бы большим не было содержимое

CSS

html {
  height: 100%;
}
 
body {
  min-height: 100%;
}

Демо

Примечания


Минимальная ширина и блочные элементы


Порой мы забываем, что элемент, к которому пытаемся применить min-width, является блочным. В итоге это может сбить с толку и никак не влиять на элемент. Убедитесь, что элемент не является блочным

CSS функции сравнения


При исследовании на StackOverflow основных проблем, с которыми сталкиваются разработчики, я наткнулся на этот вопрос, в котором автор спрашивает следующее:
Реально ли сделать что-то подобное? max-width: calc(max(500px, 100% - 80px)) или может вот такое max-width: max(500px, calc(100% - 80px)))
Желаемое поведение заключается в том, чтобы удерживать ширину элемента не более 500px. Если ширина области видимости недостаточна, чтобы вместить элемент, то ширина должна быть 100% – 80px.

Что касается решения, опубликованного в ответ на вопрос, я попробовал применить его и он работает в Chrome 79 и Safari 13.0.3. Хоть это и выходит за рамки статьи, я всё же приведу здесь решение:

CSS

.yourselector {
  max-width: calc(100% - 80px);
}
 
/* Update: I changed the max-width from 500px to 580px. Thanks @fvsch */
@media screen and (max-width: 580px) {
  .yourselector {
    max-width: 500px;
  }
}

Источники и материалы для дальнейшего изучения