Ширина и высота контейнера — независимые параметры, но иногда хотелось бы чтобы связь между ними была, к примеру, для сохранения пропорций контейнера при адаптивной верстке.
Прямой связи в CSS между width и height нет, и нет возможности задать aspect ratio контейнера вместо одного из параметров или использовать какую то функцию, потому часто прибегают к помощи js.
Для этого отслеживают изменение размеров контейнера или всего окна, пересчитывая высоту контейнера при каждом таком событии.
Если бы css функция attr поддерживалась свойствами width/height, то можно было бы попробовать читать ширину и высоту из одного и того же атрибута контейнера (как то так):
1 2 3 4 5 6 7 |
<div class="container" data-size="25%"></div> <style> .container { width: attr(data-size); height: attr(data-size); } </style> |
Но функция attr поддерживается только для css свойства content.
CSS хак, позволяющий установить зависимость между шириной и высотой контейнера
Нам повезло, что есть неожиданный эффект, который можно использовать для решения данной задачи.
Заключается он в том, что margin или padding вложенного контейнера, можно задать в %. Другой вопрос — в % от чего?
Рассмотрим пример HTML кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div class="container"></div> <style> .container { background-color: #fe0; width: 25%; } .container:after { content: ""; padding-top: 100%; display: block; } </style> |
Контейнер получает ширину в 25% от родителя, а высота определяется высотой всевдо-контейнера (в данном случае зависит от padding-top). Но от чего считать 100% padding-top, если высота .container не задана?
Данный хак работает на всех браузерах, даже таких древних как IE8. Так без каких либо скриптов, мы получаем контейнер, где высота меняется вслед за шириной.
Практика применения
Пример выше не содержит контента, потому на практике такой блок довольно бесполезен, рассмотрим пример, содержащий что либо внутри.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<div class="container"> <div class="content">TEXT</div> </div> <style> .container { background-color: #fe0; width: 25%; position: relative; } .container:after { content: ""; padding-top: 100%; display: block; } .content { position: absolute; transform: translate(-50%, -50%); top: 50%; left: 50%; } </style> |
Контент размещается внутри .content блока с абсолютным позиционированием. Для красоты я добавил центровку (для использования transform уже понадобится хотя бы IE9).
Можно растянуть .content блок по размеру .container, используя известный прием:
1 2 3 4 5 6 7 |
.content { position: absolute; top: 0; left: 0; bottom: 0; right: 0; } |
Остаётся лишь догадываться о том, как хак работает на самом деле, т.к. логика работы описанная в начале — это просто попытка хоть как то логически объяснить эффект.
Поддрежка aspect ratio с помощью CSS
В примерах я рассмотрел соотношение 1:1 — т.е. квадрат, но мы можем установить любое требуемое соотношение, меняя величину padding-top в .container:after.
1 2 3 4 5 |
// примеры padding-top: 50%; // 2:1 padding-top: 200%; // 1:2 padding-top: 33.33333%; // 3:1 padding-top: 300%; // 1:3 |
Т.е. хак позволяет универсально задать нужный нам aspect-ratio — соотношение width/height.
Использование размеров viewport для связывания ширины и высоты в CSS
Есть более простой и понятный трюк с использованием в качестве единиц измерения размеров viewport (vw или vh).
1 2 3 4 5 6 7 8 9 |
<div class="container"></div> <style> .container { background-color: #fe0; width: 25vw; height: 25vw; } </style> |
Эффект тот же, ширина и высота в примере привязаны к одному и тому же параметру — ширине устройства. Но область применения значительно сокращается, т.к. размер контейнера зависит не от родителя, а от размеров документа (viewport-а).
Единицы vw/vh поддерживаются начиная с IE9.