CSS-live.ru

Разбираемся с border-image из CSS3

Перевод статьи CSS3 Border-Image Explained с сайта demosthenes.info, c разрешения автора — Дадли Стори.

Одно из самых мощных новых свойств CSS, border-image, которое к тому же ещё и имеет шикарную поддержку, за исключением (а теперь все вместе!) IE10 и более ранних версий. Но, к сожалению, также является одним из самых непонятных и сложных для понимания свойств.

283x340xborder-image-slices.png.pagespeed.ic.t1Izk-Rh7r

Объяснение того, как работает border-image, возможно, лучше всего проиллюстрировать картинкой. Во-первых, давайте разберём любую рамку на составляющие: представим золочёную раму для картины, которая разделена на девять «плиток» двумя горизонтальными и двумя вертикальными линиями. На рисунке выше я пометил вертикальные разделительные линии, как V1и V2, а горизонтальные, как H1и H2.

2015-04-04_0047

Вместо того, чтобы позволить вам задать отдельное изображение для каждой части границы, border-image настаивает, чтобы вы создали одно изображение, в котором все части находятся на своих местах, а затем порезали это изображение при помощи CSS-значений, которые привязываются к позиции этих линий.

Представим, что мы играем в Морской бой и обозначим каждую «плитку», созданную нашими разделительными линиями. К верхнему левому углу мы могли бы обратиться как A1, к правой средней части B3, и т.д. (Средняя часть — B2 — будет проигнорирована CSS, после того, как мы определим фрагменты для нашего изображения рамки.) Места размещения фрагментов предопределяют роли для наших «плиток». A3 всегда займет место изображения верхнего правого угла для нашей рамки; C2 будет использоваться для нижнего края, и т.д.

Давайте рассмотрим боковые стороны и верх нашей рамки, поскольку они находятся в довольно специфичных, притом изменчивых, условиях. Когда мы применяем рамку к  HTML-элементу, мы не знаем, какой величины будет бокс. После того, как эти условия применятся к рамке, угловые «плитки» не будут затронуты изменениями размера, но боковые стороны, а также верх и низ определённо изменятся. Нам надо решить, как должны вести себя «плитки», которые там будут размещены: будут ли они повторяться или вытягиваться, если бокс станет больше? Это решение относится к дизайну нашей рамки и поэтому и нам придется обозначить наш выбор при написании CSS.

frame-diagram.png.pagespeed.ce.QpHiyGwLn_

Наконец, давайте подумаем о линиях, которыми созданы наши плитки: двух горизонтальных и двух вертикальных. Нам нужно сообщить CSS, где будут находиться эти воображаемые разделители, для того, чтобы он применил эту информацию для создания «плиток». Мы могли бы отсчитывать их положение либо в процентах либо в пикселях от углов. (Я бы сказал, что в большинстве случаев второе проще всего, кроме случая с SVG-картинками в качестве изображения рамки).

Заметьте, что шевроны на углах этой рамки означают, что фрагменты обязаны быть достаточно большими, чтобы включить те детали, которые увеличивают размер рамки и произведут эффект виньетки, как в настоящей раме, который на самом деле реалистичен для профессионально оформленной фотографии или картины. Я сделал внутреннюю часть рамки прозрачной, что означает, что background-color, который я указываю, будет просвечивать насквозь.

Способ, которым измеряется и вносится в объявление позиция разделителей, тоже странен: H2 отмеряется от низа изображения, H1 — от верха, V1— от левого края, а V2 — от правого. Они находятся в объявлении в таком порядке:

border-image: url(image) H1 V2 H2 V1

Как ни странно, когда значения вводятся в виде пикселов, за ними не следует суффикс «px», в отличие от почти всего остального в CSS.

Данное изображение под лицензией Creative Commons (снятое Энни Чартранд) вставлено на страницу при помощи этого кода

<img src="teracotta-statue.jpg" alt="Terracotta Statue" class="frame">

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

img.frame {

border-image: url('frame.png') 93 92 87 92;

background-color: #ffe;

}

(Заметьте, что этот код пока ещё не работает: есть ещё несколько вещей, которые нужно добавить).

Есть несколько вариантов того, как будут обрабатываться стороны. stretch именно так и работает, repeat будет повторять «плитки», чтобы уместить их в доступную область, round — это гибрид обоих значений, который старается использовать для сторон полные варианты плиток, но растягивая их там, где необходимо.

Важно отметить, что вы также должны предоставить раздельное объявление border-width, чтобы сообщить браузеру какой ширины каждая сторона, чтобы изображения могли в них вместиться. Большинство источников скажут вам, что размеры, используемые в border-width, должны в точности совпадать с теми, которые используются для позиции фрагментов, т.е.:

border-width: 93px 92px 87px 92px;

Но я обнаружил, что с единственным значением border-width рамка по сути масштабируется:

border-width: 60px;

Помните, что в виде запасного варианта вам также нужна обычная рамка на случай, если изображение для «плиток» не загружается или посетитель использует IE: я бы предложил взять рамку толщиной примерно как плитки и воспользоваться ее преобладающим цветом, возможно, с каким-нибудь малоиспользуемым border-style впридачу.

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

img.frame {
border-image: url('frame.png') 93 92 87 92 stretch stretch; border-color:#f4be52; border-style: inset; border-width: 60px; width: 500px; height: 333px;background-color: #ffe; }

Советы по дизайну

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

Восхитительно, что box-shadow продолжит работать так, как ожидалось. Конечно, тень отразит контур фигуры CSS-бокса, а не контур самой рамки; если внешняя сторона рамки неправильной формы, то вы могли бы создать реалистичную тень, используя настоящий CSS-фильтр падающей тени или подредактировав растровую картинку в таком редакторе, как PhotoShop.

Я бы также посоветовал использовать направляющие, инструмент «Выделение» и окно «Информация», чтобы измерять фрагменты. Мы делали похожую работу ранее – текст, огибающий фигуру и Семантические CSS3-спрайты (действительно, спецификации свойства clip  и border-image тесно связаны между собой). Ещё как вариант, можно использовать онлайн-инструмент Кевина Декера – «Генератор Border Image», чтобы создать CSS для вашей рамки.

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

11 комментариев

  1. Кстати, в ответ на вопрос о двух полезных дополнениях к этому свойству — border-image-outset и border-image-width, с помощью которых можно делать изящные, а не безобразно толстые, рамки на случай неподдержки/незагрузки border-image (пример), Дадли пообещал «сделать из этих двух новую статью». Так что у этой статьи, скорее всего, будет продолжение, следите за обновлениями!

    1. Очень крутой пример, спасибо. И автору за статью спасибо. После предоставленного SelenIT наглядного примера, прочитал статью еще пару раз и очень вдумчиво))

  2. Честно — статья не понравилось, на простое уходит много текста, на объяснение сложного — мало. ИМХО остановится имеет смысл, на свойстве border-image-slice, которое тут разжёвано недостаточно. Если писать тезисно, то, пожалуй, нужно указать что:
    1. Из 9 частей изображения на боковые кромки уходит 4 угловые части.
    2. Из изображения-рамки вырезается нужное количество пикселей и уходит на эти боковые рамки.
    3. На боковые грани уходит то, что осталось от боковых кромок.
    4. Ну и далее по-мелочи, как это соотносится с border-image-width, в каких случаях и каким образом происходит масштабирование, почему грани могут оказаться пустыми и так далее.
    В общем, рассуждения это хорошо, но сначала нужно внести ясность в то, как свойство работает, а потом уже говорить о тонкостях и нюансах. ИМХО.

    1. Вынужден признать, есть такое. Но материалов по этому свойству вообще маловато, отчего оно не так популярно, как могло бы быть при сегодняшнем уровне браузерной поддержки. Может, подскажете источник лучше, или попробовать самим написать? :)

      1. Напишите, пожалуйста, сами. Я долго разбирался в комментариях к одному ресурсу и более-менее разобрался, когда ухватил идею и немного с ней поэкспериментировал, но совсем не уверен, что понимаю все тонкости.
        ЗЫ: если интересно, то что понял, изложил в комментариях к справочнику https://webref.ru/css/border-image, там, конечно, несколько сумбурно, но потом я добавил туда пару ссылок с иллюстрациями в песочнице. если держать их открытыми и читать текст, то разобраться, наверное, можно, впрочем, для статьи текст всё равно не причёсанный.
        а разбирался я тут: http://html5book.ru/css3-borders/, использование авторской рамки-изображения на сторонних ресурсах согласовал, за что автору спасибо, ну и за объяснения :)

      2. Если ещё не написали, то, возможно, эта ссылка может служить неплохой иллюстрацией для Вашей будущей статьи, ну или окажется прототипом для Вашей собственной иллюстрации.

        http://border-image.com/

        1. Алексей, спасибо Вам огромнейшее!!! Вы не представляете, как мне помогла Ваша ссылка!!

    1. Я бы сказал, что правильнее всего делать основной каркас на гридах (к тому же все нужные для этого функции неплохо полифилятся Автопрефиксером на старую версию, которая работает в IE10+), но из остальных способов флексбоксы — «наименее неправильный». Только вариант с колонками по ссылке, на мой взгляд, неоптимальный: хотя ширина каждой колонки (30% и 70%) указана явно, при медленном коннекте получится, что левый сайдбар сначала будет на весь экран, а потом резко сожмется. Я бы сделал левую колонку фиксированной в процентах (width: 30%; flex: 0), а правую — на всё оставшееся место (flex: 1). Но это уже детали:)

      Для горизонтального меню флексбоксы идеальны, без вопросов.

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.