Перевод «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% от ширины родителя, если в области просмотра недостаточно свободного места
https://codepen.io/shadeed/pen/5dcb1c4c6773cc3a97a766c327c36443
Минимальная высота и липкий 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;
}
}
Источники и материалы для дальнейшего изучения
- Flex items and min-width:0 от Dominic McPhee
- CSS: Flex and “min-width” от Dominik Schöler
- Flexbugs от Philip Walton
Автор: Зварич Рома