NoneBorder -image-slice для градиентного изображения границы
Я пытаюсь понять, как работает border-image-slice в случае градиентного изображения границы. В спецификации написано, что значение для border-image-slice может быть числом, которое
Представляет смещение края в пикселях для растровых изображений и координаты для векторных изображений. Для векторных изображений число относится к размеру элемента, а не к размеру исходного изображения, поэтому в этих случаях обычно предпочтительны проценты.
В примерах из статьи CSS-трюки изображение границы устанавливается следующим образом:
border-image: repeating-linear-gradient(45deg,
#000, #000 1.5%,
transparent 1.5%, transparent 5%) 80;
Таким образом, в соответствии со спецификацией 80 относится к размеру div (ширина: 26em; высота: 23em;). Но я до сих пор не понимаю, что это значит. Когда я изменяю ширину или высоту div, изображение границы не меняет свой внешний вид. Но когда я изменяю border-image-slice или ширину границы, внешний вид значительно меняется. Таким образом, кажется, что есть корреляция между числом 80 и шириной границы 5em. (граница выглядит одинаково для числа 40 и ширины границы 2.5em, 16 для 1em и т. д.).
У меня вопрос, как рассчитывается число 80, означающее, что такое процесс нарезки для данного div и градиента? (Эскиз был бы очень признателен) И кажется, что 80 не в px, em или%, потому что когда я добавляю эти единицы, внешний вид меняется.
Полный код здесь:
div {
box-sizing: border-box;
position: relative;
border: solid 5em #000;
border-image: repeating-linear-gradient(45deg,
#000, #000 1.5%,
transparent 1.5%, transparent 5%) 80;
padding: 2em;
width: 26em; height: 23em;
background: linear-gradient(to right bottom,
#e18728, #4472b9);
background-size: 50% 50%;
}
<div></div>
2 ответа
TL;DR
При использовании градиента размер изображения равен размеру элемента. border-width-image
определит 9 областей, где мы будем размещать срезы (если не определены, border-width
используется). border-image-slice
рассмотрим исходное изображение для создания срезов. Значение без единиц измерения рассматривается как значение пикселя, а процентное значение сопоставляется с размером элемента.
Чтобы получить идеальный результат, мы должны иметь срезы, равные регионам, и для этого нам нужно иметь border-slice-image
равно border-width-image
(или же border-width
) при использовании без устройства. Используя процент, вычисленное значение должно быть таким же.
В твоем случае 80
в срез означает 80px
и у вас есть граница 5em
который 5x16px = 80px
Давайте рассмотрим простой пример.
div {
width: 100px;
height: 100px;
display: inline-block;
border: 10px solid transparent;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) 50 fill;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
Выше я пытался создать два div с одинаковым выводом, используя разные методы (фон и граница). Обратите внимание, как во втором примере я использую ключевое слово fill
и я указал border-width-image
отличается от ширины границы и используется срез, равный этой ширине границы.
Обратите внимание, что 50
здесь срез рассматривается как пиксель, так как мы имеем дело с не векторным изображением (градиент).
Числа представляют пиксели в изображении (если изображение является растровым изображением) или векторные координаты (если изображение является векторным изображением). ссылка
Давайте удалим свойство fill:
div {
width: 100px;
height: 100px;
display: inline-block;
border: 10px solid transparent;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) 50;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
Ключевое слово fill, если оно присутствует, обеспечивает сохранение средней части изображения границы. (По умолчанию он отбрасывается, т. Е. Обрабатывается как пустой.) Ref
По умолчанию изображение границы отображается не по центру, а только по границе. Мы можем ясно видеть пример, который мы имеем 50px
на каждой стороне с нашей пользовательской границей, как определено border-image-width
И если мы не укажем border-image-width
значение по умолчанию 1
что значит
Числа представляют собой кратные соответствующих вычисленных
border-width
,
Так что либо мы явно указываем border-image-width
или мы просто используем border-width
в качестве ссылки. Только в большинстве случаев border-width
необходимо, так как в большинстве случаев мы хотим охватить только пограничную область, а не более.
Теперь срез разделит изображение на 9 частей
Это свойство определяет внутренние смещения от верхнего, правого, нижнего и левого краев изображения, разделяя его на девять областей: четыре угла, четыре края и середина
Вот шаги, которые лучше покажут, как это делается для нашего примера:
div {
width: 100px;
height: 100px;
border: solid 10px transparent;
display: inline-block;
position: relative;
}
div:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(green,green) left 0 top 50px/100% 1px no-repeat,
linear-gradient(green,green) left 0 bottom 50px/100% 1px no-repeat,
linear-gradient(green,green) top 0 left 50px/1px 100% no-repeat,
linear-gradient(green,green) top 0 right 50px/1px 100% no-repeat;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) 50;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
Левое изображение - это оригинальное изображение, которое мы делим на 9 частей, а затем помещаем каждое в 9 областей правого. Средний пустой, потому что мы не использовали заливку. В этом примере мы ничего не заметим, потому что срезы соответствуют регионам.
Теперь давайте уменьшим ломтик до 25
:
div {
width: 100px;
height: 100px;
border: solid 10px transparent;
display: inline-block;
position: relative;
}
div.box:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(blue,blue) left 0 top 25px/100% 1px no-repeat,
linear-gradient(blue,blue) left 0 bottom 25px/100% 1px no-repeat,
linear-gradient(blue,blue) top 0 left 25px/1px 100% no-repeat,
linear-gradient(blue,blue) top 0 right 25px/1px 100% no-repeat;
}
div.border:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(green, green) left 0 top 50px/100% 1px no-repeat,
linear-gradient(green, green) left 0 bottom 50px/100% 1px no-repeat,
linear-gradient(green, green) top 0 left 50px/1px 100% no-repeat,
linear-gradient(green, green) top 0 right 50px/1px 100% no-repeat;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) 25;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
Это немного сложно, но применяется та же логика. С левого изображения режем используя 25px
сформируйте каждую сторону, чтобы получить нашу 9 часть, которую мы поместим в правильную часть, где ширина границы все еще остается той же (50px
). Вы можете четко заметить, как детали в углах просто масштабируются, а края искривляются.
В каждом углу мы используем 25px 25px
изображение внутри 50px 50px
площадь и в верхнем крае, например, мы используем 60px 25px
изображение внутри 10px 50px
площадь.
Вы также можете определить разные значения для каждой стороны, чтобы иметь что-то вроде ниже:
div {
width: 100px;
height: 100px;
border: solid 10px transparent;
display: inline-block;
position: relative;
}
div.box:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(blue, blue) left 0 top 20px/100% 1px no-repeat,
linear-gradient(blue, blue) left 0 bottom 30px/100% 1px no-repeat,
linear-gradient(blue, blue) top 0 left 20px/1px 100% no-repeat,
linear-gradient(blue, blue) top 0 right 60px/1px 100% no-repeat;
}
div.border:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(green, green) left 0 top 50px/100% 1px no-repeat,
linear-gradient(green, green) left 0 bottom 50px/100% 1px no-repeat,
linear-gradient(green, green) top 0 left 50px/1px 100% no-repeat,
linear-gradient(green, green) top 0 right 50px/1px 100% no-repeat;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px);
border-image-slice: 20 60 20 30;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
Теперь стало понятнее, как мы нарезаем изображение, а затем помещаем их в другую область, масштабируя их растягивая. Также ясно, что наилучшим значением является наличие срезов во всех сторонах, равных ширине границы, что имеет место в вашем примере, так как 5em
является 5x16px = 80px
таким образом, кусок 80
Из спецификации мы также можем прочитать:
Области, заданные значениями border-image-slice, могут перекрываться. Однако если сумма правой и левой ширины равна или больше ширины изображения, изображения для верхнего и нижнего края и средней части будут пустыми, что будет иметь тот же эффект, как если бы непустое прозрачное изображение было указано для тех частей. Аналогично для верхних и нижних значений.
Если вы укажете левый и правый срез больше ширины изображения, то по логике вы не получите ничего для верхней / нижней / средней части:
div {
width: 100px;
height: 100px;
border: solid 10px transparent;
display: inline-block;
position: relative;
}
div.box:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(blue, blue) left 0 top 20px/100% 1px no-repeat,
linear-gradient(blue, blue) left 0 bottom 30px/100% 1px no-repeat,
linear-gradient(blue, blue) top 0 left 60px/1px 100% no-repeat,
linear-gradient(blue, blue) top 0 right 60px/1px 100% no-repeat;
}
div.border:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(green, green) left 0 top 50px/100% 1px no-repeat,
linear-gradient(green, green) left 0 bottom 50px/100% 1px no-repeat,
linear-gradient(green, green) top 0 left 50px/1px 100% no-repeat,
linear-gradient(green, green) top 0 right 50px/1px 100% no-repeat;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px);
border-image-slice: 20 60 20 60;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
Та же логика применима и к верху / низу.
Вот пример, где у нас будут только углы
div {
width: 100px;
height: 100px;
border: solid 10px transparent;
display: inline-block;
position: relative;
}
div.box:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(blue, blue) left 0 top 20px/100% 1px no-repeat,
linear-gradient(blue, blue) left 0 bottom 100px/100% 1px no-repeat,
linear-gradient(blue, blue) top 0 left 60px/1px 100% no-repeat,
linear-gradient(blue, blue) top 0 right 60px/1px 100% no-repeat;
}
div.border:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(green, green) left 0 top 50px/100% 1px no-repeat,
linear-gradient(green, green) left 0 bottom 50px/100% 1px no-repeat,
linear-gradient(green, green) top 0 left 50px/1px 100% no-repeat,
linear-gradient(green, green) top 0 right 50px/1px 100% no-repeat;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px);
border-image-slice: 20 60 100 60;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
Использование процентного значения также даст тот же результат. Нам просто нужно найти ссылку, и поскольку мы имеем дело с градиентом, размер градиента - это просто размер элемента. Ломтик 50
в нашем примере равно 41.666%
так как ширина / высота равна 100px 2 * 10px = 120px
div {
width: 100px;
height: 100px;
border: solid 10px transparent;
display: inline-block;
position: relative;
}
div:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background:
linear-gradient(blue, blue) left 0 top 50px/100% 1px no-repeat,
linear-gradient(blue, blue) left 0 bottom 50px/100% 1px no-repeat,
linear-gradient(blue, blue) top 0 left 50px/1px 100% no-repeat,
linear-gradient(blue, blue) top 0 right 50px/1px 100% no-repeat;
}
div.box {
background: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) border-box, red;
}
div.border {
border-image: repeating-linear-gradient(45deg, #000, #000 5px, transparent 5px, transparent 10px) 41.666%;
border-image-width: 50px;
background: red;
}
<div class="box"></div>
<div class="border"></div>
В следующем примере я использую px вместо em, потому что я думаю, что это понятнее.
Это изображение используется для изображения границы.
div{ width: 416px; height: 368px;
background:repeating-linear-gradient(45deg,
#000, #000 1.5%,
transparent 1.5%, transparent 5%);
}
<div></div>
Это изображение будет разрезано на 9 квадратов в виде сетки.
Изображение из этой статьи: border-image-slice
Если значение для border-image-slice
равно 80, это означает, что смещение равно 80, т. е. размер C1, C2, C3 и C4 равен 80/80. Все срезы C используются для углов изображения границы. E1,E2,E3 и E4 используются для рисования краев.
Если вместо 80 вы используете 208 или 50%, изображение границы получит углы, но не края, потому что для краев ничего не осталось.
Далее идет демонстрация, где вы можете увидеть эволюцию срезов на изображении, используемом для рисования границы изображения. Я изменил ширину div на 300, потому что я хотел видеть как div с изображением границы, так и изображение, используемое для границы один рядом с другим. В этом случае края изображения границы исчезают при border-image-slice:150;
itr.addEventListener("input",()=>{
let v = itr.value;
border.style.borderImageSlice = v;
itrspan.innerHTML = v;
let d = `M${v},0v300M${300-v},300v-300M0,${v}h300M300,${300-v}h-300`
thePath.setAttributeNS(null,"d",d)
})
div{display:inline-block;}
#border {
box-sizing: border-box;
position: relative;
border: solid 5em #000;
border-image: repeating-linear-gradient(45deg,
#000, #000 1.5%,
transparent 1.5%, transparent 5%);
border-image-slice:80;
padding: 2em;
width: 300px; height: 300px;
}
#image{
width: 300px; height: 300px;
background: repeating-linear-gradient(45deg,
#000, #000 1.5%,
transparent 1.5%, transparent 5%);}
input{width:300px;}
<input id="itr" type="range" min="0" max="300" value="80" ><span id="itrspan">80</span>
<br>
<div id="border"></div>
<svg id="image" viewBox="0 0 300 300">
<path id="thePath" fill="none" stroke="red" d="M80,0v300M220,300v-300M0,80h300M300,220h-300" />
</svg>