В ожидании aspect-ratio: «хаки» для пропорциональных боксов

  • Tutorial

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

padding-top/bottom в %

Соблюдения соотношения сторон без aspect-ratio можно было достичь задав боксу с нулевой высотой padding-top или padding‑bottom в %. Процентное соотношение рассчитывалось по формуле:

высота / ширину * 100%

Например:


1x1 aspect ratio = 1 / 1 * 100% = padding‑top: 100%
4x3 aspect ratio = 3 / 4 * 100% = padding‑top: 75%
16x9 aspect ratio = 9 / 16 * 100% = padding‑top: 56.25%

В некоторых случаях, проценты округляли до сотых:
3x2 aspect ratio = 2 / 3 * 100% = padding‑top: 66.67% (66.66666666666667%)

Видимо, людям не нравилось писать 16 значные значения свойства. Что приводит нас к

padding‑top/bottom + функция calc()

.aspect-ratio-box {
  padding-bottom: calc(100% / (327 / 120));
  height: 0;
}

И красиво, и немного намекает на то, что происходит, людям не знакомым с хаком.

Так как высота бокса была равной нулю, чтобы разместить в нем что-то (заголовок, например) нам было нужно использовать абсолютное позиционирование. Из-за чего он не был защищен от переполнения контентом.

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

Блок лендинга Loopstudio из frontendmentor.io
Блок лендинга Loopstudio из frontendmentor.io

Все проекты этого блока это по сути article с заголовком внутри. Изображения заданы через background‑image. Проекты также должны быть кликабельны. Мы можем обернуть все содержимое article в ссылку (в данном случае это не будет проблемой). Однако если проектам захотят добавить описание — у нас будет проблема с доступностью. Скринридер прочитает все что вложено в ссылку — и заголовок и описание. Решение есть и заключается в том, чтобы положить ссылку в заголовок и растянуть её область клика через псевдоэлемент. Но для этого нам нужно чтобы заголовки не были абсолютно cпозиционированы. А значит нужен другой вариант пропорционального бокса.

   

padding-top/bottom для ::before

Следующий способ заключался в том, чтобы задать внутренний отступ в % уже для псевдоэлемента со значением float: left; Вот так:

.aspect-ratio-box {
    display: flow-root;
/* Нужно чтобы контейнер не схлопывался. */
}

.aspect-ratio-box::before {
    content: "";
    float: left;
    padding-bottom: calc(100% / (327 / 120));
}

Для более широкой поддержки по сравнению с flow-root (т.е. для браузеров ~ до середины 2017 года), в качестве альтернативы, для контейнера вы могли использовать свойство column-count:

.aspect-ratio-box {
    column-count: 1;
/* Пуленепробиваемый clearfix */
}

.aspect-ratio-box::before {
    content: "";
    float: left;
    padding-bottom: calc(100% / (327 / 120));
}

Вариант с flexbox

display: flex; изменит направление потока документа с обычного, на горизонтальное слева направо:

.aspect-ratio-box {
  display: flex;
/* предусмотрительно оставленный комментарий о том, */
/* что свойство flex как и направление главной оси */
/* убирать и менять нельзя */
}

.aspect-ratio-box::before {
    content: "";
    padding-bottom: calc(100% / (327 / 120));
}

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

Что дальше? @supports not

Какой же способ использовать в работе? Мне кажется, мы можем начать использовать aspect‑ratio и подстраховаться директивой @supports с оператором not:

.aspect-ratio-box {
  aspect-ratio: 327 / 120;
}

@supports not (aspect-ratio: 1) {
/* если браузер НЕ поддерживает свойство, то */
/* применить стили внутри */
  .aspect-ratio-box {
    column-count: 1;
  }

  .aspect-ratio-box::before {
    content: "";
    float: left;
    padding-bottom: calc(100% / (327 / 120));
  }
}

Данный способ является самым надежным.

Если кому‑то работающему с вашим CSS понадобится как-то спозиционировать заголовок — они смогут сделать это с помощью флексбокса и внешних отступов со значением auto.
float просто перестанет работать. Таким образом, они ничего не заденут по случайности.

А со временем, когда поддержка будет более распространена — мы просто удалим правило.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 4

    0

    Какой жёлтый заголовок.


    На самом деле это не все варианты. Можно было бы рассмотреть способы с использованием canvas, svg в качестве распорок, способ с CSS Grid. Неплохо бы прояснить для начинающих, почему важно делать padding-распорку на внутреннем элементе, а не на самом элементе.


    Несмотря на широкую поддержку @supports я бы инвертировал правило, потому что браузеров, способных отобразить то, что внутри правила, больше, чем браузеров, поддерживающих @supports. Хотя при вашем способе нужно будет проще удалять/рефакторить код.

      0
      Неплохо бы прояснить для начинающих, почему важно делать padding-распорку на внутреннем элементе, а не на самом элементе.
      Что можно дополнить к тому что уже есть?

      В статье есть про
      Переполняемость контентом и проблема с доступностью в случае с ссылкой на всю карточку.
        0

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

      0
      Лично я использовал для распорки прозрачную картинку — браузеры сами сохраняют её пропорции при указании, например, только ширины.

      Only users with full accounts can post comments. Log in, please.