Еще раз про border-image — CSS-LIVE

Хотя свойство border-image уже поддерживают более 96% браузеров (с оговорками, но всё же), популярным пока его не назовешь. Пожалуй, поначалу оно кажется неоправданно сложным: объединяет в себе 5 отдельных свойств, каждое с несколькими значениями, да еще неочевидные правила взаимодействия с обычным border — легко запутаться. Даже многие неплохие руководства (типа статьи Дадли Стори, которую мы переводили в прошлом году) грешат тем, что даже после них ощущение сложности не проходит.

Есть мнение, что его сложность преувеличена, а возможности недооценены. Попробуем исправить это упущение.

0.

border-image = border + image

Название свойства состоит из двух слов: «рамка» и «картинка». Вокруг них всё и вертится. Интуитивно его действие можно представить в виде примерно такого алгоритма:

  1. Берем картинку.
  2. Вырезаем из этой картинки рамку.
  3. Заготавливаем «каркас» рамки по размерам нужного блока. Если надо, подгоняем ее толщину, положение краев и т.д.
  4. «Натягиваем» вырезанную часть картинки на этот «каркас».

В таком ракурсе мы его сейчас и рассмотрим.

1. Картинка:

border-image-source

В теории, картинка может быть чем угодно, что относится к типу CSS-значения «image» (описано в модуле значений изображения и замещаемого содержимого 3 уровня). Это может быть растровая картинка (отдельный файл или data uri) и SVG-картинка (отдельный файл, base64 или прямо SVG-код с минимально заэкранированными спецсимволами!). Или CSS-градиент. И даже любой элемент страницы — благодаря функции element(). Конечно, не всё из этого поддерживается во всех браузерах, но с растровыми картинками, SVG и градиентами давно почти везде нет проблем, а этого для типичных задач хватает с избытком.

С векторными картинками и градиентами есть пара нюансов:

  1. Не у каждой картинки есть конкретные размеры. Соответственно, не из каждой картинки можно вырезать рамку, задавая ей размеры в пикселях. С градиентами вообще лучше всегда работать в процентах.
  2. Градиент может быть только один. Неприятный сюрприз по сравнению с фонами: если фоны у нас множественные, благодаря чему можно собирать целые паттерны из нескольких слоёв разного размера и положения, то здесь нам фактически доступен лишь один такой слой. Так что паттерны из градиентов в
    border-image
    использовать нельзя.

Точнее, было нельзя до недавних пор. Несколько недель назад CSS-волшебница @yoksel открыла для нас новый секретный уровень CSS. Если задать для border-image SVG-картинку с инлайновыми стилями, внутри них может быть много чего интересного, включая паттерны из нескольких градиентов. Но будьте внимательны, такая магия требует мастерства и глубокого понимания происходящего! Иначе можно сломать мозг себе и браузеру.

Я не волшебник, только учусь, так что меня пока хватило только на такую небольшую вариацию:

See the Pen три градиента в border-image by Ilya Streltsyn (@SelenIT) on CodePen.

2. Вырезка рамки:

border-image-slice

Наша картинка разделяется на 9 «плиток». 8 внешних (4 угловых и 4 боковых) — по сути и есть рамка. А центральная «плитка» либо выбрасывается, либо (если задать ключевое слово fill) заполняет рамку изнутри, как фон.

«Линии разреза» задаются значениями свойства border-image-slice. Если присмотреться, оно очень похоже на обычный border-width! Те же 1–4 значения через пробел, тот же порядок (по часовой стрелке, верх-право-низ-лево), тот же смысл сокращенных записей (3 значения — верх, одинаковые бока и низ, 2 значения — верх-низ и бока, 1 значение — одинаковая толщина со всех 4 сторон). Только единицы измерения другие: либо проценты (от размеров картинки), либо безразмерные «единицы системы координат картинки». Для растровой картинки это ее «родные», исходные пиксели. Так что ни те, ни другие единицы никак не зависят от экрана, масштаба и т.п.

Не так интуитивно, когда суммарная толщина противоположных сторон рамки становится больше размера картинки. Тогда разные угловые «плитки» пересекутся — какая-то часть картинки окажется сразу на нескольких из них. Это легче представить как то, что исходной картинки у нас было 4 экземпляра, и из каждого щедро вырезали по углу. Плиток нулевого и отрицательного размера не бывает, поэтому при такой «нарезке» центральная «плитка» и пара боковых исчезают, остаются лишь угловые. В пределе, при border-image-slice:100% — странно, но это значение по умолчанию — этими оставшимися угловыми «плитками» станет вся картинка целиком.

Лучше увидеть и «пощупать» это вживую:

See the Pen LROoRZ by Ilya Streltsyn (@SelenIT) on CodePen.

3. Тонкая настройка:

border-image-width и border-image-outset

Художественные эффекты, включая рисованные рамки, часто требуют настройки с точностью до пикселя. У border-image целых две «степени свободы» для этого.

Итоговая толщина рамки:

border-image-width

С помощью border-image-width можно регулировать окончательную толщину рисованной рамки, совсем как с border-width — толщину обычной. Можно указывать толщину сторон рамки в обычных единицах длины (px, em, vh…), и эти стороны отмасштабируются до указанного значения (составляющие ее «плитки» сожмутся или растянутся поперек, угловые плитки масштабируются по обеим осям независимо). Но у него бывают еще три типа значений:

  • безразмерные коэффициенты — за единицу берется толщина соответствующей стороны обычного border-width.
  • проценты. Да-да, проценты для рамки! Чисто визуальной, но всё же. Считаются от общего размера рамки (с учетом того, что она может выступать за края блока, см. ниже).
  • ключевое слово auto — используется исходный размер соответствующих «плиток», т.е. соответствующее значение из border-image-slice.

Значение по умолчанию — как раз безразмерное 1: рисованная рамка масштабируется до толщины, заданной обычному border-у.

Иногда, если нужно просто «залить рамку текстурой», это логично. Но часто удобнее задавать border и border-image-width по отдельности. Если же не указать ни того, ни другого, рамка не появится вообще (ее толщина будет нулевой).

Удобное значение auto: сколько пикселей «вырезали» из картинки, такую толщину рамки и получили, ничего не искажается. Есть нюанс: border-image-width считается в обычных CSS-пикселях, а border-image-slice — в исходных пикселях картинки. Поэтому на Retina-экранах при auto растровая картинка может «мылить». Чтобы сделать рамку двойной четкости из картинки двойного размера, придется явно указывать для

border-image-width половины значений border-image-slice (т.е. вдвое уменьшать исходные «плитки»).

И еще один важный нюанс: максимальный размер рамки у нас фиксирован, так что сумма противоположных сторон всегда втискивается в этот предел. Если сумма размеров «плиток» для противоположных сторон рамки оказывается больше, они пропорционально ужимаются, чтобы вписаться хотя бы впритык:

See the Pen Автомасштабирование border-image до размеров контейнера by Ilya Streltsyn (@SelenIT) on CodePen.

Примечание: работа над этим примером заставила меня осознать беспощадный факт, что составляющие border-image не анимируются. Выручил JS. Зато как минимум в Firefox внутри SVG-картинок в border-image работают SMIL-анимации!

Вынос рамки за габариты блока:

border-image-outset

Это уже интереснее: рисованная рамка может выступать за края блока наружу, на внешние отступы и даже на соседние элементы! Редкая в CSS возможность (еще разве что тени да позиционированные псевдоэлементы так умеют). Бывает полезно для вычурных дизайнерских виньеток с веточками/лучиками/тентаклями/любыми др. выступающими деталями. Или для «хвостиков» от «балунов» прямой речи, которыми любят оформлять отзывы и комментарии. Причем выступает она чисто визуально, на блочную модель это не влияет (габариты блока по-прежнему считаются по краям обычного

border-а).

По механизму border-image-outset похож на margin. Только наоборот: положительные значения — сдвиг наружу. Кроме обычных единиц длины, тоже можно указывать безразмерные множители для border-width. А вот проценты почему-то нельзя. Сдвигать края внутрь, к сожалению, тоже нельзя (отрицательные значения запрещены), но обычно и не нужно. По умолчанию значение

0 — без сдвига, край рамки совпадает с краем блока.

Эти два свойства отлично работают вместе, если надо точно состыковать с контентом дизайнерскую рамку типа такой:

See the Pen GjxVmp by Ilya Streltsyn (@SelenIT) on CodePen.

Или уголки нестандартной формы с тенью:

See the Pen
SVG as border-image for arbitrary corner shapes with shadow by Ilya Streltsyn (@SelenIT)

on CodePen.

А заодно обеспечить им по-настоящему изящную деградацию.

4. «Натяжка» рамки на «каркас»:

border-image-repeat

Теперь, когда известны окончательные размеры рамки, пора замостить эту область «плитками». Это работа свойства border-image-repeat. Общий принцип — угловые «плитки» просто разносятся по углам, а боковые заполняют оставшееся между углами пространство, для чего с ними что-то делается. Варианты, что именно делать, такие:

  1. stretch (по умолчанию) — растянуть (или сжать) боковые «плитки» до заполнения оставшегося места, с искажением пропорций. Как будто рамка, которую мы вырезали из картинки, была резиновая, и мы приклеиваем ее к «каркасу» за углы.
  2. repeat — размножить «плитку» и замостить ей это пространство. Как фон c background-repeat: repeatbackground-position по центру стороны). Пропорции сохранятся, но аккуратных стыков с углами никто не гарантирует.
  3. round — размножить и исказить пропорции чуть-чуть — настолько, чтобы в нужное пространство влезло целое число копий «плитки». Тогда стыки с углами будут такими же аккуратными, как на исходной картинке.
  4. space — не искажать пропорции, а взять столько копий, сколько поместится, а оставшееся свободное место поровну «раскидать» вокруг них. Увы, работает пока только в IE11/Edge и Safari 9.1+ (но вот-вот начнет в Firefox 50+).

Можно задать разные значения для горизонтальных и вертикальных сторон (напр. stretch round) или одно значение для всех 4-х. Центральная плитка по каждому измерению ведет себя так, как соответствующие боковые (например, может размножаться по вертикали и растягиваться по горизонтали).

Особых сложностей тут не видно, поэтому ограничимся простейшим примером:

See the Pen PGarao by Ilya Streltsyn (@SelenIT) on CodePen.

На мой взгляд, самые полезные значения — stretch (для сплошных, «монолитных» рамок) и round (для повторяющихся орнаментов).

5. Итого

Сокращенная запись свойства border-image, по спецификации, записывается практически как наш алгоритм:

border-image: <‘border-image-source’> || <‘border-image-slice’> [ / <‘border-image-width’> | / <‘border-image-width’>? / <‘border-image-outset’> ]? || <‘border-image-repeat’>

т.е., в переводе на человеческий: что за картинка — пробел — как ее резать — слеш — какой толщины делать рамку — слеш — насколько выдвигать ее за края — пробел — как натягивать «плитки». Части border-image-width и border-image-outset необязательны. Что именно из них пропущено, определяется по количеству слешей перед оставшимся. Например, в border-image: url(img.png) 50 / 25px round значение 25px — это толщина рамки (до него один слеш), а в border-image: url(img. png) 50 / / 25px stretch — это выступ за края (до него два слеша). Но «что резать», «как резать» и «как растягивать» указывать нужно (первое — по стандарту, остальное — по здравому смыслу).

Cледующий пример — набросок своего рода «песочницы» для этого свойства. Пробуйте загружать или задавать кодом свои картинки и градиенты, менять значения и единицы, смотрите на результат и… копируйте итоговое значение. Надеюсь, из этого получится неплохое дополнение к старому доброму border-image.com:)

See the Pen Конструктор border-image by Ilya Streltsyn (@SelenIT) on CodePen.

И несколько слов о поддержке браузерами. С ней всё хорошо: полностью выпадает лишь IE10 и ниже. Без значения space для border-image-repeat, по-моему, жить можно.

Правда, на CanIUse есть загадочное примечание (про WebKit и Edge 13), которое чуть не сбило меня с толку: «Есть баг, что border-image неправильно перекрывает border-style». Каково же было мое удивление, когда я обнаружил, что все браузеры «перекрывают» компоненты обычного border-а по-разному! Safari в iOS 10 не рисует картинку при border-width: 0, Edge 14 — при border-style: none, Хром (включая Canary 56) — при обоих. А вот Firefox (и IE11, что интересно) рисуют картинку несмотря ни на что, хотя о баге в них не сказано!

После раскопок в спецификациях и консультаций с умными людьми я выяснил, что поведение FIrefox (и IE11) правильное. Это подтверждают официальные тесты к спецификации. По стандарту, составляющие обычного border не должны влиять на border-image чем-либо еще, кроме как через дефолтное значение border-image-width (причем его легко «отвязать», задав конкретное значение). Неразбериха возникла из-за двусмысленной фразы в спецификации, что «при нулевом border-width рамка считается отсутствующей» (без уточнения, идет ли речь только об обычной или о картиночной тоже), а также из-за проблем совместимости со старыми префикснутыми реализациями и гугловским календарем:). Ради совместимости с Хромом, видимо, сломали и Edge. Впрочем, «лекарство» — явно указать, например, border-style: solid и ненулевой border-width — элементарно. К тому же они наверняка всё равно понадобятся для изящной деградации.

И еще две хорошие новости и одна плохая. Хорошая №1 — border-image работает в Опере Мини! Так что его поддержка чуть ли не лучше, чем у border-radius). Хорошая №2 — на сегодня это единственный браузер, которому нужен префикс. И чуть ли не единственный случай, где это префикс -o-. Даже префикс -webkit- уже не актуален! А плохая новость в том, что Опера Мини поддерживает только сокращенное свойство целиком (нельзя задавать, скажем, border-image-slice и border-image-width по раздельности) и не понимает в border-image-repeat не только странного space, но и полезного round.

P.S. Это тоже может быть интересно:

Использование CSS :pseudo-elements для замены изображения в стиле списка спрайтом · GitHub

Использование CSS :pseudo-elements для замены изображения в стиле списка на Sprite

Этот файл содержит двунаправленный текст Unicode, который может быть интерпретирован или скомпилирован не так, как показано ниже. Для просмотра откройте файл в редакторе, который показывает скрытые символы Unicode. Узнайте больше о двунаправленных символах Unicode

Показать скрытые символы

<ул>
  • SEO
  • Система управления контентом
  • Интеграция с социальными сетями
  • Еще один элемент списка для выделения
  • Этот файл содержит двунаправленный текст Unicode, который может быть интерпретирован или скомпилирован не так, как показано ниже. Для просмотра откройте файл в редакторе, который показывает скрытые символы Unicode. Узнайте больше о двунаправленных символах Unicode

    Показать скрытые символы

    ли {
    стиль списка: нет;
    положение: относительное;
    отступ: 6px 0 0 20px;
    }
    ул ли: до {
    фон: прозрачный url(«sprite.png») прокрутка 0 0 без повтора;
    содержимое:»»;
    ширина: 16 пикселей;
    высота: 16 пикселей;
    позиция: абсолютная;
    слева: 0;
    сверху: 8 пикселей;
    }
    ul li:before { background-position: 0px -16px; }

    Content — Tailwind CSS

    ​Основное использование

    ​Настройка содержимого псевдоэлемента

    Используйте утилиты content-{value} вместе с до и после 9 0139 вариант модификаторов для установки содержимого псевдоэлементы ::before и ::after .

    По умолчанию content-none — единственная доступная предварительно настроенная утилита для работы с содержимым. И хотя вы можете добавить дополнительные утилиты, настроив свою тему, обычно имеет смысл просто использовать произвольное значение.

    Используйте нотацию с квадратными скобками для определения любого произвольного значения содержимого на лету.

    Более высокое разрешение означает больше, чем просто более качественное изображение. Благодаря дисплею Retina 6K Pro Display XDR дает вам почти на 40 процентов больше экранной площади, чем дисплей 5K.

     Более высокое разрешение означает больше, чем просто более качественное изображение. С сетчаткой
    Дисплей 6K, Pro Display XDR дает вам
    почти на 40 процентов больше площади экрана, чем у дисплея 5K.  Более высокое разрешение означает больше, чем просто более качественное изображение. С сетчаткой
    Дисплей 6K,  
    apple.com/pro-display-xdr/" target="_blank">Pro Display XDR дает вам
    почти на 40 процентов больше площади экрана, чем у дисплея 5K.  

    ​Ссылка на значение атрибута

    Эти утилиты для работы с контентом даже поддерживают функции CSS, такие как функция attr() , которую можно использовать для ссылки на значение, хранящееся в атрибуте:

     

    ​Использование пробелов и знаков подчеркивания

    Поскольку пробел обозначает конец класса в HTML, замените любые пробелы в произвольном значении на знак подчеркивания:

     

    Если вам нужно включить фактическое подчеркивание, вы можете сделать это, экранировав его обратной косой чертой:

     

    ​Условное применение

    ​Наведение курсора, фокус и другие состояния

    Tailwind позволяет вам условно применять служебные классы в различных состояниях, используя модификаторы вариантов. Например, используйте hover:before:content-['Hovering'] , чтобы применять утилиту before:content-['Hovering'] только при наведении.

     <дел>
      
    

    Полный список всех доступных модификаторов состояния см. в документации Hover, Focus и других состояний.

    ​Точки останова и медиа-запросы

    Вы также можете использовать модификаторы вариантов для целевых медиа-запросов, таких как чувствительные точки останова, темный режим, предпочтения с уменьшенным движением и т. д. Например, используйте md:before:content-['Desktop'] для применения утилиты before:content-['Desktop'] только на экранах среднего размера и выше.

     <дел>