Всем привет! Меня зовут Лихопой Кирилл и я - фронтенд-разработчик в компании idaproject. Сегодня я представляю вам перевод статьи о новой CSS-фиче, которую, я уверен, многие ждали. И это - object-view-box, которое позволит нам обрезать и масштабировать фотографии не прибегая к “костылям” в виде фонового изображения или доп. элементов.

Итак, знакомьтесь - object-view-box!

Мне всегда хотелось иметь нативное средство в CSS для обрезания и позиционирования изображения в любом направлении, которое мне нужно. Это было возможно с использованием дополнительных HTML-элементов и их комбинацией с различными CSS-свойствами, которые я покажу чуть позже.

В этой статье я познакомлю вас с новым CSS-свойством object-view-box , которое было предложено Jake Archibald еще год назад. Оно позволяет нам обрезать и изменять размер таких HTML-элементов, как <img> или <video>.

Проблема

В примере ниже у нас есть изображение, которое необходимо обрезать. Заметьте, что нам нужна определенная часть изображения.

Сейчас мы можем решить эту проблему одним из следующих способов

  • Использовать <img>, обернув его в дополнительный элемент

  • Использовать изображение как background-image и изменить его позиционирование и размер

Оборачивание в дополнительный элемент

Это достаточно распространенное решение данной проблемы. Посмотрим, как это выглядит:

  • Оборачиваем изображение в другой элемент (в нашем случае <figure>)

  • Добавляем position: relative и overflow: hidden

  • Добавим position: absolute для изображения и поиграемся со значениями позиционирования и размером, чтобы добиться желаемого результата.

<figure>
    <img src="img/brownies.jpg" alt="">
</figure>
figure {
	position: relative;
	width: 300px;
	aspect-ratio: 1;
	overflow: hidden;
	border-radius: 15px;
}
img {
position: absolute;
left: -23%:
top: 0;
right: 0;
bottom: 0;
width: 180%;
height: 100%;
object-fit: cover;
}

Установить изображение в качестве фона

Для этого решения мы используем <div> и установим наше изображение в качестве фона, затем изменим позиционирования и размер.

<div class="brownies"></div>
.brownies {
	width: 300px;
	aspect-ratio: 3/2;
	background-image: url("brownies.jpg");
	background-size: 700px auto;
	background-position: 77% 68%;
	background-repeat: no-repeat; 
}

Это работает как надо, но что, если мы хотим применить вышеуказанное к элементу <img> ? Именно в этом и заключается суть свойства object-view-box.

Представляем object-view-box

Я очень сильно обрадовался, когда увидел, что свойство object-view-box может быть добавлено в Chrome 104. Сейчас оно доступно в Chrome canary.

Согласно черновику CSS:

Свойство object-view-box указывает “область просмотра” для элемента, так же, как это делает аттрибут <svg viewbox>, позволяя увеличить или обрезать контент элемента.

Свойство принимает значение <basic-shape-rect> = <inset()> | <rect()> | <xywh()>. Для демонстрации, в этой статье мы сосредоточимся на использовании inset().

Давайте вернемся к нашей проблеме.

С object-view-box у нас есть возможность использовать inset , чтобы нарисовать прямоугольник через указание 4 сторон (top, right, bottom, left), а затему применить object-fit: cover, чтобы избежать искажения.

<img src="img/brownies.jpg" alt="">
img {
    aspect-ratio: 1;
    width: 300px;
    object-view-box: inset(25% 20% 15% 0%);
}

Как это вообще работает? Не переживайте, я все сейчас объясню. Давайте разбираться дальше!

Внутренний размер изображения

Внутренний размер изображения - это его дефолтные ширина и высота. Изображение в примере имеет внутренний размер 1194 x 1194 px.

img {
    aspect-ratio: 1;
    width: 300px;
}

С такими стилями визуальный размер изображения будет 300 x 300 px.

Наша цель - нарисовать прямоугольник на оригинальных размерах изображения. Для этого используем значение inset() .

Использование inset()

Значение inset() будет считаться от оригинальной высоты и ширины изображения. Это поможет нам нарисовать прямоугольник как бы внутри изображения и указать 4 стороны, как для свойств margin или padding .

Давайте вернемся к свойству object-view-box.

img {
    aspect-ratio: 1;
    width: 300px;
    object-view-box: inset(25% 20% 15% 0%);
}

В примере выше показано закулисье того, что изображено на картинке. Значения 25%,20%,15% и 0% отвечают за верх, право, низ и лево, соответственно.

Если изображение квадратное, обрезанный результат будет искажен.

Но мы можем легко исправить это с помощью свойства object-fit.

img {
    aspect-ratio: 1;
    width: 300px;
    object-view-box: inset(25% 20% 15% 0%);
    object-fit: cover;
}

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

Увеличение / уменьшение масштаба

Мы можем использовать inset , чтобы масштабировать наше изображение. Во время тестирования я выяснил, что transition и animation не работают с object-view-box.

Мы также может уменьшить масштаб с помощью отрицательного значения inset.

Пример

Ниже вы найдете ссылку на пример, который вы прямо сейчас можете протестировать в Chrome canary. Только убедитесь, что у вас включена опция “Experimental Web Platform features”.

Демо-версия

А вы ждали эту фичу для CSS?

Комментарии (12)


  1. BlackStar1991
    22.05.2022 20:37

    Сложно представить практическое применение данного свойства. Отдавать браузеру пользователя заведомо большее (неправильное) изображение, ганять больший объем трафика сетью, увеличивать скорость глобального потепления... что бы потом средствами CSS вырезать определенный кусок картинки, который будет на этапе показа жрать ресурсы видеокарты, что бы показать нужную область изображения


    1. neervel Автор
      22.05.2022 21:13

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


      1. BlackStar1991
        22.05.2022 22:13

        Вот, интересная мысль.... я готов копнуть даже глубже. Поскольку object-view-box допустим для тега video, то таким образом можно "обрезать" видео с ватермарками, не грузя его себе не сервер, а давая пользователю "видеть" только нужную часть видео, не нарушая чужую собственность на контент =) Просто скрой 10% бордюра с логотипом компании...


        1. sden77
          22.05.2022 22:41

          а что мешает это сделать, спрятав видеоплеер в контейнер нужного размера с overflow:hidden


          1. neervel Автор
            23.05.2022 07:07

            Как раз таки идея в том, чтобы делать это не с помощью доп. контейнера, а именно нативными средствами css


        1. neervel Автор
          23.05.2022 07:06

          Или такой вариант, да.

          Плюс в статье ещё идёт речь о других параметрах, кроме inset, так что там ещё больше возможностей


    1. sden77
      22.05.2022 22:39
      +1

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


      1. ivan386
        23.05.2022 10:53

        Лучше уж использовать CSS напрямую чем через Javascript.


    1. pae174
      23.05.2022 00:06

      Сложно представить практическое применение данного свойства.

      Альтернатива для CSS спрайтов.


  1. eps
    23.05.2022 01:48
    +1

    Согласно специцификации CSS:

    Согласно черновика спецификации CSS


    W3C это ещё не обсудил до конца, не стандартизировал и "новым CSS-свойством" эта штука ещё не является.


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


  1. sanchezzzhak
    23.05.2022 02:13

    Спасибо за статью и за вариант с абсолютом.

    Новые фишки всегда хорошо, но что мы будем делать с IOS, где применение новых фич CSS просто не будет работать, в силу того что Сафари = IOS Version.

    Статистика за май по IOS+Версия (на моем сайте)

    Без учета фильтра по OS - 886.282 уников по рекламе

    iOS 15.4 - 40045
    iOS 15.3 - 23128
    iOS 14.8 - 8299
    iOS 12.5 - 8113
    iOS 15.2 - 6143
    iOS 15.1 - 5963
    iOS 14.7 - 5527
    iOS 14.4 - 5380
    iOS 14.6 - 4740
    iOS 15.0 - 3299
    iOS 14.2 - 1215
    iOS 13.3 - 1102
    iOS 14.3 - 1124
    iOS 10.3 - 1315
    iOS 13.6 - 1037
    iOS 12.4 - 745
    iOS 14.0 - 615
    iOS 13.5 - 666 --- упс. просто число
    iOS 15.5 - 677 --- ласт версия
    iOS 14.5 - 474
    iOS 13.7 - 422
    iOS 14.1 - 514
    iOS 12.3 - 237
    iOS 13.4 - 199
    iOS 12.1 - 422
    iOS 13.1 - 234
    iOS 11.4 - 625
    iOS 5.1 - 275
    iOS 11.0 - 169
    iOS 12.2 - 457
    iOS 13.2 - 87
    iOS 7.0 - 443
    iOS 10.2 - 51
    iOS 9.1 - 61
    iOS 12.0 - 33
    iOS 11.2 - 63
    iOS 5.0 - 52
    iOS 11.1 - 22
    iOS 11.3 - 21
    iOS 13.0 - 19
    iOS 6.0 - 25
    iOS 10.1 - 5
    iOS 4.3 - 2
    iOS 9.3 - 5
    iOS 3.2 - 76
    iOS 9.0 - 11
    iOS 15.6 - 3
    iOS 7.1 - 2

    ----------------------------

    Total: 124178

    Лучше всего загружать картинки максимально допустимые, а дальше уменьшать там где это нужно. Можно например в nginx поставить модуль, который налету нам сделает картинки, нужного размера.

    nginx-module-image-filter
    # Поддержка формата WebP появилась в версии 1.11.6.


  1. NickKolok
    23.05.2022 15:54

    Выглядит явно избыточно. Очередной слой наворотов в браузеры. Очередной пакет полифиллов. Очередные тормоза. Брр!

    Хотя элементарных фоллбэков при блокировке сервака со статикой до сих пор нет (если есть - просветите). Грубо говоря,

    <script
            src="//cloudflare.com/jquery-6.6.6.js"
            src_if_failed="//rkn.gov.ru/jquery-6.6.6.js"
            integrity="..."
    >