Инлайновые стили в background-image

Игралась с кодами, обнаружила удивительное: оказывается, внутри CSS-свойства background можно использовать другие CSS-свойства, например, box-shadow, outline, transform и даже ещё один background.

Очевидно, что мы не можем просто взять и засунуть одно CSS-свойство в другое: тени и трансформации должны применяться к элементу. В качестве фона мы можем использовать цвета, градиенты и картинки, но не только: ещё в качестве фона можно использовать SVG, причём не только в виде ссылки на внешний файл, — также код SVG-элемента можно вставить непосредственно в CSS, это делается вот такой конструкцией: background-image: url("data:image/svg+xml,...");.

SVG можно вставить в CSS прямо как есть, но такой код не будет работать в IE. Однако если его заэскейпить, код будет работать во всех браузерах включая IE9.

See the Pen (encoded svg) by yoksel (@yoksel) on CodePen.

И вот теперь если этому svg внутри background задать какие-нибудь стили в атрибуте style, они будут работать! Можно использовать обычные стили для HTML-элементов, то есть рамки (в том числе border-image), тени, фоны (включая CSS-градиенты) и даже трансформации!

Например, можно взять такой код:

<svg xmlns='http://www.w3.org/2000/svg'
    viewBox='0 0 100 100' width='50' height='50'
    style='transform: rotate(45deg) scale(.8,.8);
        transform-origin: 50% 50%;
        border-radius: 1rem;
        background: linear-gradient(darkviolet, turquoise);
        box-shadow: 0 0 7px 3px white inset;'>
        <circle r='30%' cx='50%' cy='50%' fill='gold'/>
</svg>

заэскейпить его и использовать как фон, при это все инлайновые стили сохранятся:

See the Pen (encoded svg with inline styles) by yoksel (@yoksel) on CodePen.

Жёлтый кружочек — это circle внутри svg, всё остальное — инлайновые стили: градиент, тень и трансформации.

На самом деле, чтобы воспользоваться инлайновыйми стилями, нужен только элемент svg, его содержимое не играет роли и может отсутствовать:

<svg xmlns='http://www.w3.org/2000/svg'
    viewBox='0 0 100 100' width='50' height='50'
    style='transform: rotate(45deg) scale(.8,.8);
        transform-origin: 50% 50%;
        border-radius: 1rem;
        background: linear-gradient(darkviolet, turquoise);
        box-shadow: 0 0 7px 3px white inset;'
        ><!-- тут ничего нет --></svg>

И всё равно всё будет работать:

See the Pen (encoded svg with inline styles) by yoksel (@yoksel) on CodePen.

Интересно, что такие стили работают во всех современных браузерах, но у каждого свои представления о том, как это должно выглядеть в итоге:

Chrome

Chrome

Тени, трансформации и градиенты работают, градиент поворачивается вместе с фигурой. Пустые места в углах плитки фона заполняются градиентом.

transform-origin по умолчанию находится в точке 0, 0.

Firefox

Firefox

Тени, трансформации и градиенты работают, но тень поворачивается вместе с фигурой, а градиент — нет.

transform-origin по умолчанию находится в точке 0, 0.

Safari

Safari

Тени, трансформации и градиенты работают, градиент поворачивается вместе с фигурой. Пустые места в углах плитки фона ничем не заполняются.

transform-origin по умолчанию находится в точке 0, 0.

IE11

IE11

Трансформации и градиенты работают, тени — нет. Градиент поворачивается вместе с фигурой. Пустые места в углах плитки фона не заполняются.

transform-origin по умолчанию находится в точке 50%, 50%.

В отличие от остальных браузеров, здесь не работает transform-origin, заданный в процентах, — при этом ломается весь фон. Также, если фигуре задать border, отобразится только он, а градиенты и тени пропадут.

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

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

Например, если делать паттерны с помощью градиентов, иногда хочется просто взять и повернуть плитку фона, например, на 45 градусов, чтобы получилась чешуя:

See the Pen [Chrome, Opera] SVG + CSS gradient + Box Shadow by yoksel (@yoksel) on CodePen.

(Нормально отображается только в Chrome и Opera)

Ещё один вариант чешуи:

See the Pen SVG + CSS gradient by yoksel (@yoksel) on CodePen.

(Chrome, Opera)

Или вот хочется сделать сложный фон из нескольких градиентов и повернуть всю группу сразу (в данном случае такой группой является полупрозрачный трёхцветный градиент):

See the Pen Animated pattern: SVG + CSS gradient by yoksel (@yoksel) on CodePen.

(Chrome, Opera)

Или, например, хочется изменить размер фона, но так, чтобы какие-то линии сохранили свой размер. box-shadow при ресайзе background-size именно так и работает:

See the Pen Animated pattern for HTML element without gradients by yoksel (@yoksel) on CodePen.

(Chrome, Opera, Firefox, Safari)

Ресайзится только плитка фона, размер теней не меняется. Из этого можно сделать, например, калейдоскопический паттерн:

See the Pen Animated pattern without gradients: + transform! by yoksel (@yoksel) on CodePen.

(Chrome, Opera, Firefox, Safari)

Используя border-image c градиентами можно делать совсем уж замысловатые штуки:

See the Pen Border-image inside background-image by yoksel (@yoksel) on CodePen.

(Chrome, Opera, Firefox, Safari)

Играться можно до бесконечности.

Я не знаю как это знание можно пристроить к делу, но меня так поразила эта находка, что я решила о ней рассказать. И я до сих пор под впечатлением от того, что в background-image можно использовать трансформации и border-image, хотя практической пользы в этом, наверное, никакой.

Если у вас есть идеи куда это можно применить, поделитесь.

Все мои эксперименты с инлайновыми стилями можно увидеть в этой коллекции (смотреть лучше в Хроме и Опере).

Ссылки по теме:
Data URI + SVG
Optimizing SVGs in data URIs
URL-encoder для SVG
Background tricks with SVG, Box shadows and CSS Gradients
Если вы нашли ошибку или неточность, вы можете отредактировать статью с помощью prose.io, а также можно написать мне в комментариях или в Twitter.
Система комментирования от Disqus