Как сделать SVG адаптивным с помощью CSS

demosourse

SVG может быть встроен в веб-страницу множеством способов; однин из них - использование HTML5 тэга <svg>. Другие способы включают в себя встраивание SVG при помощи тэгов <img>, <object>, а так же, используя iframe, либо как фон при помощи CSS.

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

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

Как сделать SVG "резиновыми" при помощи CSS

Для того чтобы заставить SVG быть "резиновым", прежде всего необходимо удалить атрибуты height и width. Когда указаны точные значения высоты и ширины SVG никак не сможет автоматически растягиватся. Стоит, однако, оставить атрибут viewBox. После очистки свойств высоты и ширины SVG можно вставить на страницу одним из нескольких способов.

Встраивание SVG при помощи <img>

Когда SVG встроен как изображение при помощи тэга <img> высота и ширина, указанные в тэге используются браузером для контроля размеров SVG. Содержимое SVG затем располагается внутри окна просмотра в зависимости от значения viewBox, указанного в <svg>.

<img src="my_SVG_file.svg" alt="Image description." /><img src="my_SVG_file.svg" alt="Image description." />

Обычно браузеры достаточно функциональны для определения ширины и высоты SVG даже если не указывать ширину и высоту <img> элемента. Например, если вам нужно поместить img в div без указания высоты и ширины, Chrome и Firefox решат, что ширина img = 100%; SVG затем растягивается для заполнения содержащего div, и его высота соответствующе подгоняется для сохранения пропорций. Затем изменяется размер самого div-а, а img SVG подгоняется под него. Однако при работе с растровым изображением, например рисунком PNG это бы не проканало; в этом случае нам бы пришлось специально задавать ширину img в 100% при помощи CSS.

В Internet Explorer дела обстоят по-другому. Если не указывать ширину img, браузер решит, что высота равняется 150px, так этот размер указан в CSS спецификации как стандартный; стандартная ширина изображения равняется 300px. Затем SVG располагается внутри содержащего div так, что его высота равна 150px; хотя предполагается что ширина будет 100%; SVG принимает высоту всегда 150px независимо от того, насколько широким становится контейнер, что в результате приводит к широким белым пробелам с обеих сторон. Чтобы разобраться с этим вопросом в IE достаточно специально задавать ширину img в 100%. Эти результаты были получены в следствие тестов, проведенных в Internet Explorer 9 и 11.

Таким образом, для того чтобы сделать SVG “резиновым”, сначала необходимо удалить значения высоты и ширины, указанных в <svg>, а затем добавить одну строчку CSS для Internet Explorer:Таким образом, для того чтобы сделать SVG “резиновым”, сначала необходимо удалить значения высоты и ширины, указанных в <svg>, а затем добавить одну строчку CSS для Internet Explorer:

/* fix for IE */
img {
    width: 100%;
}

Обратите внимание, что если вы решите задать ширину и высоту тэгу <img> более чем 100%, то размер SVG будет расчитан как будто ширина и высота были заданы непосредственно <svg> элементу.

Встраивание SVG при помощи <object>

Встраивание SVG через <object>, во многом похоже на тот же самый процесс при работе с <img>.

<object type="image/svg+xml" data="my_SVG_file.svg">
    <!-- fallback here (<img> referencing a PNG version of the graphic, for example) -->
</object>

Так же, как и с тэгом img, Firefox и Chrome определяют ширину SVG-объекта в 100% и высота изменяется пропорционально увеличению ширины экрана. Если же object-у задать ширину и высоту, то SVG-графика поместится в отдельную область просмотра с заданными размерами.

В случае с Internet Explorer возникает та же проблема, о которой мы упоминали ранее, когда высота SVG по умолчанию равна 150px. Проблема также устраняется путем задания ширины в 100%:

/* fix for IE */
object {
    width: 100%;
}

Встраивание SVG при помощи <iframe>

<iframe> очень похож по своему функционированию и особенностях на <object>.

<iframe src="my_SVG_file.svg">
    <!-- fallback here (<img> referencing a PNG version of the graphic, for example) -->
</iframe>

Однако браузеры реагируют на данный способ по-разному. На сегодняшний день Chrome, Firefox и Internet Explorer выставляют вставленному в iframe SVG: 300px ширины и 150px высоты. В предыдущих случаях, когда IE использовал стандартную высоту 150px, он использовал ширину в 100%. Однако когда речь идёт об iframe все три браузера устанавливают высоту и ширину iframe’а в фиксированном размере 300px на 150px.

Применение width:100% растягивает iframe для заполнения ширины контейнера, однако высота не меняется – она по-прежнему равна 150px; даже когда контейнер и iframe уменьшаются до ширины меньшей, чем оригинальная ширина SVG, iframe по-прежнему поддерживает высотку в 150рх, приводя к появлению белых пробелов сверху и снизу SVG-изображения. Это происходит во всех трёх браузерах.

Единственный способ изменить высоту SVG – точно задать ее на iframe. Высота затем, конечно, вместе с шириной сформирует окно просмотра, внутри которого будет расположен SVG. Если вы хотите, чтобы SVG поместился внутри окна просмотра без всяких белых пробелов над/под или по сторонам, необходимо будет удостовериться в том, что заданные высота и ширина окна просмотра (iframe) соответствуют соотношению высоты и ширины SVG-изображения.

Не существует “стандартного” способа создать элемент с конкретным соотношением высоты-ширины в CSS. Однако, несколько лет назад Тьерри Кобленц разместил статью на A List Apart, в которой описывается прием, который сегодня известен как Хак заполнения; хак, позволяющий создавать внутренние соотношения для видео и iframe-ов.

Идея padding hack’а заключается в использовании отношения внутренних отступов элемента к его ширине. Когда внутрение отступы установлены в процентном соотношении, проценты вычисляются относительно ширины элемента, даже если мы выставили только верхний внутренний отступ. Аналогичный прием можно использовать в случае с SVG, чтобы сделать элемент “резиновым”. Ниже описаны шаги для достижения нужного нам эффекта.

Пусть тестовый SVG выглядит вот так:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="194" height="186" viewBox="0 0 194 186">
    <!-- SVG content -->
</svg>

Padding hack – Шаг 1

Для того чтобы сделать SVG адаптивным, когда он встроен в iframe необходимо сделать то же самое, что мы делали ранее: убрать атрибуты height и width из <svg> элемента.

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186">
    <!-- SVG content -->
</svg>

Padding hack – Шаг 2

Далее, убедимся в том, что задали атрибут viewBox. В большинстве случаев SVG будет иметь указанный viewBox.

Нет необходимости специально задавайте preserveAspectRatio так как его стандартное значение (xMidYMid meet) является значением, которое нам вполне подходит. Поэтому нет необходимости задавть его, если только значение preserveAspectRatio не должно быть оличным от стандартного.

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186" preserveAspectRatio="xMidYMid meet">
    <!-- SVG content -->
</svg>

Padding hack – Шаг 3

Для того, чтобы padding hack сработал, SVG необходимо поместить в контейнер. Для этой цели нам подойдёт элемент div. Этот контейнер получит внутреннее соотношение при помощи padding hack’а (следующий шаг), и затем iframe будет автоматически масштабирован внутри контейнера.

<!-- wrap svg in a container -->
<div class="container">
    <iframe src="my_SVG_file.svg">
        <!-- fallback here -->
    </iframe>
</div>

Padding hack – Шаг 4

Далее, мы применяем несколько стилей к контейнеру соблюдая следующие правила:

.container {
    height: 0;
    width: width-value;
    padding-top: (svg height / svg width) * width-value;
    position: relative;
}

Итак, что конкретно делают вышеуказанные правила?

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

После того, как мы указали ширину контейнера – которая должна автоматически растягиваться, используя процентное значение, задаём значение верхнего внутреннего (или нижнего) отступа контейнера при помощи следующей формулы. Эта формула использует значения атрибутов <svg> height и width, которые мы убрали в Шаге 1) для указания значения заполнения, которое позволит внуреннему отступ контейнера соответствовать размерам svg.

В нашем логотипе ширина svg составляет 194px, а высота – 186рх. Я установил ширину контейнера на 50% чтобы он занимал половину доступного горизонтального пространства. Примененное к контейнеру заполнение равняется (186 / 194) * 50 = 48%. То есть, код для контейнера выглядит вот так:

.container {
    width: 50%;
    height: 0;
    padding-top: 48%;
    position: relative;
}

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

Чтобы «вытянуть» SVG обратно мы разместим iframe внутри контейнера. Тут вступает в игру position: relative, что помогает выставить правильную позицию для SVG.

Padding hack – Шаг 5

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

iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

Это всё, что необходимо для того чтобы сделать SVG адаптивным. iframe отображается в стандартной рамке, от которой по всей видимости вы захотите избавиться. Для этого достаточно добавить одно правило: border: none;

Встраивание SVG при помощи <svg>Встраивание SVG при помощи <svg>

SVG может быть встроен в HTML документ при помощи тега <svg>.

<!-- Note: the xmlns is not required in an HTML5 document -->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186">
    <!-- SVG content -->
</svg>

Ширина и высота встроенного окно просмотра svg будет такой же, какую вы задали непостредственно <svg> элементу. Когда атрибуты ширины и высоты убраны все браузеры будут воспринимать ширину равной 100% и растягивать SVG по горизонтали чтобы заполнить ширину контейнера.

В Chrome и Firefox высота SVG рассчитывается как раз так, как нам нужно. В этом случае адаптивность достигается без особых потерь.

В Internet Explorer (проверено на версиях 9 и 11) высота снова равна 150рх, а ширина 100%. Как и в предыдущих случаях, при изменении размера экрана, сверху и снизу SVG появится белое пространство. При использовании img было достаточно указать width: 100%; однако, выставив ширину в 100% самому svg такой же эффект не будет достигнут. В этом случае лучшим решением будет применение padding hack-а.

<div class="container">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186">
        <!-- SVG content -->
    </svg>
</div>

.container {
    width: 50%;
    height: 0;
    padding-top: 48%;
    position: relative;
}

svg {
    position: absolute;
    top: 0;
    left: 0;
}

SVG встроенный как фоновый рисунок при помощи CSS

Одним из популярных способов встраивания SVG является использование фонового рисунка:

.element {
    background-image: url(my_SVG_image.svg);
    /* other styles */
}

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

Делаем SVG адаптивными при помощи CSS медиа запросов

Тот факт, что графические элементы внутри SVG создаются при помощи XML, делает работу с SVG очень удобной. Так как SVG-контент состоит из XML тэгов, которые отображают графику мы можем выбирать отдельные элементы и применять к ним конкретные стили точно так же, как мы выбираем элементы HTML, используя CSS селекторы.

Элементы SVG обычно стилизуются при помощи презентационных атрибутов вроде fill, stroke, transform и других. Однако только подмножество всех презентационных атрибутов может быть задано при помощи CSS. Вы можете найти список задаваемых стилей, в спецификации стилей SVG. Список задаваемых при помощи свойств CSS атрибутов на данный момент не включает атрибуты x, y, width и height; однако эта четвёрка будет добавлена в список, и мы сможем задавать их при помощи CSS.

Некоторые из самых часто задаваемых свойств: fill, который работает подобно фоновому цвету; stroke, который схож с border; opacity, display, transform и некоторые другие.

Далее мы добавим медиа запросы внутрь тэга <style> внутри <svg>:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186">
    <style>
        /* CSS styles and media queries here */
    </style>
    <!-- SVG elements here -->
</svg>

Вот так вставляем логотип:

<img src="logo.svg" alt="Logo" />

Пора отметить, что размеры, указанные в медиа запросах, ссылаются на размеры окна просмотра SVG. В зависимости от способа, которым вы встраиваете SVG, окно просмотра может быть либо размера самого <svg> (для встроенных SVG), либо размера ссылаемого SVG элемента.

У каждого из элементов внутри SVG есть ID, который мы можем использовать в CSS:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186">
    <path id="curved_bg" fill="#195463" d="..."/>
    <g id="primary_content" fill="#ECECEC">
        <path id="icon" d="..."/>
        <path id="inner-circle" d="..."/>
        <path id="middle-circle" d="..."/>
    </g><!-- /primary content -->
    <g id="secondary_content" fill="#ECECEC">
        <path id="bottom-text" d="..."/>
        <path id="upper-text" d="..."/>
        <path id="outer-circle" d="..."/>
        <circle id="left-dot" cx="31.1" cy="91.5" r="3"/>
        <circle id="right-dot" cx="163.4" cy="91.5" r="3"/>
    </g><!-- end secondary content -->
</svg>

Используя <style> внутри SVG, мы создаём медиа запросы, которые изменят стили в зависимости от размера окна. SVG изменится как показано на изображениях ниже:

Мы будем использовать свойства CSS fill и opacity. Уменьшая размер окна, фон логотипа исчезнет, а цвет заполнения поменяется с белого на тёмно-синий. По мере того, как экран уменьшается, текстовая часть логотипа убирается, чтобы занимать меньше экранного пространства. И, наконец, круг, охватывающий иконку, убирается и на очень маленьких экранах остается только иконка якоря.

Вместе с медиа запосами, наш SVG файл будет выглядеь следующим образом:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186">
    <style>
        svg * {
            transition: fill .1s ease-out, opacity .1s ease-out;
        }
        @media all and (max-width: 250px) {
            #curved_bg {
                opacity: 0;
            }
            #secondary_content, #primary_content {
                fill: #195463;
            }
        }
        @media all and (max-width: 200px) {
            #secondary_content {
                opacity: 0;
            }
        }
        @media all and (max-width: 150px) {
            #inner-circle, #middle-circle {
                opacity: 0;
            }
        }
    </style>
    <path id="curved_bg" fill="#195463" d="..."/>
    <!-- ... -->
</svg>

Изменение логотипа в зависимости от размеров экрана - тоже адаптивность. Некоторые логотипы компаний могут занимать слишком много пространства на маленьких экранах, поэтому мы всё чаще видим, как множество логотипов адаптируются, путем избавления от текстовой части. Без SVG этого можно было бы достигнуть путем переключения PNG на экранах различных размеров. Однако такой подход не очень эффективен, ведь вам потребуется хранить на сервере множество картинок. В данном случае явно видны преимущества SVG: гибкость в использовании и прекрасное отображение на экранах.

В завершении

С выходом всё новых и новых версий Chrome и Firefox, увеличивается поддержка SVG, поэтому информация в данной статье в какой-то момент может стать не актуальна. Internet Explorer как всегда замедляет всю движуху, поэтому упомянутые фиксы будут актуальны долгое время.

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: http://tympanus.net/codrops/2014/08/19/making-svgs-responsive-with-css/
Перевел: Станислав Протасевич
Урок создан: 9 Сентября 2014
Просмотров: 41433
Правила перепечатки


5 последних уроков рубрики "CSS"

или авторизуйтесь, чтобы добавлять комментарии, оценивать уроки и сохранять их в личном кабинете
  • 11 Октября 2016 08:43
    VasRip
    Спасибо большое за статью.
^ Наверх ^