Использование SVG с медиа-запросами

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

Также это можно реализовать с помощью медиа-запросов и SVG. Рассмотрим логотип вымышленной компании Hexagon Web Design & Development, представленный ниже:

Содержание

SVG-логотип и медиа-запрос

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

В чем разница между областью просмотра HTML-документа и SVG? Если SVG встроен, то их области просмотра совпадают.

Изображение SVG ведет себя так же, как и любой элемент HTML. Но если он связан с элементами object или img, то мы говорим об области просмотра именно SVG-документа.

Медиа-запросы применяются в обоих случаях. Но если SVG связан с object, iframe или img, тогда размеры области просмотра определяются этими элементами.

В качестве примера рассмотрим SVG- документ (сокращенный):

<svg version="1.1" id="HexagonLogo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 555 174" xml:space="preserve">
    <defs>
        <style type="text/css">
        /* здесь будет CSS */
        </style>    
    </defs>
    <g id="hex">
        <polygon id="hexagonbg" points="55.2,162 10,86.5 55.2,11 145.5,11 190.7,86.5 145.5,162  "/>
        <path id="letterH" fill="#FFFFFF" d="M58,35.5h33v35.2h18.4V35.5 h33.2v103.4h-33.2v-38.3H91v38.3H58V35.5z M77.5,126.5V87.3h45.6v39.2h4V47.9h-4v35.6H77.5V47.9h-4v78.6H77.5z"/>
    </g>

    <g id="word-mark">
        <g id="hexagon-word">
            ...
        </g>
        <g id="web-design-and-dev">
            ...
        </g>
    </g>
</svg>

В маленьких областях просмотра будет отображаться только буква Н в шестиугольнике:

@media (max-width: 20em) {
    [id=word-mark] {
        display: none;
    }
}

Теперь, если контейнер будет меньше или равен 20em, будет виден только значок логотипа:

Попробуйте установить ширину SVG-контейнера в HTML:

<object data="hexlogo.svg" type="image/svg+xml" style="width: 20em;"></object>

После этого SVG-изображение сохраняет свой размер, хотя часть логотипа скрыта. К сожалению, это является недостатком SVG.

Чтобы преодолеть его, нужно изменить атрибут viewBox SVG-документа для тех случаев, когда область просмотра меньше определенного размера. Это отличный пример использования matchMedia.

Атрибут viewBox определяет видимую область SVG-элемента. С его помощью можно задать, какая часть SVG-изображения заполнит область просмотра. Ниже приведен пример использования matchMedia и медиа-запроса для изменения значения viewBox:

var svg, originalViewBox, max20em, mq, updateViewBox;

svg = document.querySelector('svg');

/* Сохраняем исходное значение в переменной */
originalViewBox = svg.getAttribute('viewBox');

/* Определяем медиазапрос и объект медиазапроса */
mq  = matchMedia("(max-width: 20em)");

/* Определяем обработчик */
updateViewBox = function(){
    if (mq.matches) {
        /* Измените размеры viewBox, чтобы показать шестиугольник */
        svg.setAttribute('viewBox', "0 0 200 174");
    } else {
        svg.setAttribute('viewBox', originalViewBox);
    }
}

/* Запускаем при полной загрузке документа */
// браузеры WebKit/Blink
svg.onload = updateViewBox;

// Firefox и IE
svg.addEventListener('SVGLoad', updateViewBox, true);

/* Запускаем, если изменится область просмотра */
mq.addListener(updateViewBox);            

</script>

Примечание: браузеры по-разному обрабатывают событие SVGLoad. Метод addEventListener наиболее последовательно работал в Firefox. Чтобы добиться лучших результатов в Chrome и Safari используйте атрибут onload.

Microsoft Edge также лучше работает с onload, но только если использовать onload как атрибут тэга <svg>. Выглядит это так: <svg onload=»updateViewBox»>.

Теперь, если контейнер SVG будет иметь величину 20em или меньше, значение viewBox будет равно «0 0 200 174». Если величина контейнера превысит 20em, viewBox вернется к своему начальному значению.

При этом лучше встроить CSS и JavaScript в файл SVG. Пока CSS является внешним, событие SVGLoad сработает прежде, чем подключенный CSS будет загружен.

Использование медиа-запросов с background-size

Можно изменить размер области просмотра SVG, используя CSS-свойство background-size. Последние версии популярных браузеров поддерживают эту технику.

Начнем с SVG-документа:

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-20 -20 250 250" xml:space="preserve">
    <style type="text/css">
       circle {
            stroke: #000;
            stroke-width: 30;
            fill: #009688;
       }
       @media (width: 100px) {
            circle {
                fill: #673ab7;
            }
        }
        @media (width: 300px) {
            circle {
                fill: #ffc107;
            }
        }
    </style>
    </defs>
    <circle cx="100" cy="100" r="100" />
    <circle cx="100" cy="100" r="50" />
</svg>

Элементы circle получают новый цвет заливки при определенной ширине области просмотра. Если ширина области просмотра будет иметь значение 20px, цвет заливки будет бирюзовым. Если ширина будет 300px, заливка станет желтой.

Чтобы реализовать это, используем SVG в качестве фонового изображения и свойство background-size. В этом примере мы будем использовать изображение в качестве фона для body и элементов li:

body, li {
    background: url(../images/circles.svg);
}
body {
    background-color: #9c27b0;
    background-size: 300px auto;
}
li {
      background-size: 20px auto;
      background-repeat: no-repeat;
      background-position: left 3px;
      padding-left: 25px;
}

Данная публикация представляет собой перевод статьи «Using SVG with Media Queries» , подготовленной дружной командой проекта Интернет-технологии.ру