SVG и медиа запросы

SVG и медиа запросы

От автора: одна из удивительных возможностей SVG позволяет делать изображения адаптивными. В данной статье мы поработаем с ней.

Посмотрим на следующий код:

Но когда в таком случае круг будет синим? В спецификации говорится, что значение min-width должно быть равно ширине экрана, но…

Какого экрана?

Какой из кодов выше нарисует синий круг в HTML (возможно обрезанный)? А также какое разрешение экрана нужно использовать? Будет ли это:

размер CSS документа;

атрибуты width/height/viewBox тега svg;

атрибуты width/height тега img;

размер CSS макета тега img.

Большинство браузеров скажут…

SVG масштабируется под размеры тега img, а CSS размеры img составляют видимую область в SVG. Таким образом, у первого img видимая ширина равна 50, а у второго – 100. То есть второе изображение img «подхватит» медиа запрос и станет синего цвета, а первое нет.

Для тега iframe видимой областью в SVG будет видимая область встраиваемого документа. Так в верхнем примере видимая ширина составляет 50 пикселей CSS, так как это ширина iframe.

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

А что скажет Firefox?

Firefox думает не совсем так. Этот браузер ведет себя точно так же с отдельными исключениями. Для тега img видимая область – это размер области рендеринга в пикселях устройства. Видимая область меняется в зависимости от плотности изображения. Первое изображение из демо будет зеленым на 1х экранах, и синим на 2х и выше. Тут возникает проблема, так как большинство ноутбуков и мобильных телефонов имеют плотность отображения больше 1.

Это похоже на баг, особенно когда Firefox не применяет ту же логику к iframe. Но тут стоит немного пожалеть Firefox, так как в спецификации ничего не говорится про масштабирование SVG в img, не говоря уже о том, как обрабатывать медиа запросы.

Я подал запрос на исправление ошибки в спецификации, надеюсь, ситуация прояснится. Но все становится еще сложнее, когда дело доходит до…

Рисование SVG в canvas

В canvas также можно рисовать теги img:

Но когда круг будет синим? В этот раз видимых областей немного больше. Будет ли это:

CSS размер окна;

атрибуты width/height/viewBox тега svg;

атрибуты width/height тега img;

размеры CSS макета тега img;

размеры canvas в пикселях;

размеры CSS макета тега canvas;

width/height заданные в drawImage;

width/height заданные в drawImage, умноженные на контекст 2D трансформаций.

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

Chrome

Chrome возьмет атрибуты width/height из SVG документа. То есть если документ SVG говорит, что ширина width=”50”, вы получите медиа запросы на видимую область в 50px. Если же вы хотите рисовать круг с помощью медиа запросов на видимую область шириной 100px, вам не повезло. Не важно, какого размера вы нарисуете круг на canvas, он будет отрисовываться с медиа запросами под ширину 50px.

Однако если в SVG задан viewBox, а не фиксированная ширина, Chrome возьмет ширину canvas в пикселях в качестве видимой области. Вы можете сказать, что это похоже на работу с инлайновым SVG, где видимая область совпадает со всем окном браузера, но разница в поведении с viewBox действительно странная. Chrome ведет себя хуже всех.

Safari

Как и Chrome, Safari использует размер из SVG документа, что означает, что данный браузер подвержен тем же недостаткам. Однако если в SVG используется viewBox, а не фиксированная ширина, браузер высчитывает ширину из viewBox. То есть viewBox=»50 50 200 200″ даст нам ширину 150. Лучше Chrome, но очень много ограничений.

Firefox

Firefox использует width/height из drawImage, умноженные на контекстные трансформации. То есть если вы рисуете SVG на canvas шириной 300 пикселей, видимая область будет в ширину 300px.

Браузер отражает странное поведение img, основанное на отрисованных пикселях. То есть вы получите те же несостыковки в плотности отображения, если умножите ширину и высоту canvas на devicePixelRatio (и обратно уменьшите с помощью CSS), что вам сделать потребуется, чтобы изображение не было мутным на экранах с высокой плотностью пикселей.

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

Microsoft Edge

Edge для определения видимой области использует размеры макета тега img. Если у img нет макета (display: none или отсутствует в дереве документа), тогда браузер берет атрибуты width/height. Если и их нет, Edge берет внутренние размеры img.

То есть вы можете рисовать SVG на холсте 1000х1000, но если у изображения задана ширина <img width=»100″>, то видимая область будет шириной в 100px.

Я считаю, это идеальное поведение. Так вы можете активировать медиа запросы для ширины вне зависимости от отрисовываемой ширины. Также такой подход хорошо соотносится с адаптивными изображениями. Когда вы рисуете <img srcset=»…» sizes=»…»> на canvas, все браузеры говорят, что нарисованное изображение должно быть отображением текущего тега img.

Вот и все!

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

Автор: Jake Archibald

Источник: //jakearchibald.com/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте: