【问题标题】:How does border-image work with linear-gradient?边框图像如何与线性渐变一起使用?
【发布时间】:2019-11-16 18:05:27
【问题描述】:

我试图了解边界图像切片在渐变边框图像的情况下是如何工作的。在规范中,border-image-slice 的值可以是一个数字,

表示光栅图像的边缘偏移量和矢量图像的坐标值。对于矢量图像,数字与元素的大小有关,而不是与源图像的大小有关,因此在这些情况下,百分比通常更可取。

在来自 CSS-tricks articleexamples 中,边框图像设置如下:

border-image: repeating-linear-gradient(45deg, 
        #000, #000 1.5%, 
        transparent 1.5%, transparent 5%) 80;

因此,根据规范,80 是相对于 div 的大小(宽度:26em;高度:23em;)。但我还是不明白这是什么意思。当我更改 div 的宽度或高度时,边框图像不会改变其外观。但是当我更改边框图像切片或边框宽度时,外观会发生显着变化。所以看起来数字 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>

【问题讨论】:

  • TL;DR 切片应等于边框宽度以获得最佳渲染效果。在您的情况下 5em = 80px 所以我们使用 80 .. 将尝试做出详细的回答

标签: css border linear-gradients


【解决方案1】:

TL;DR

当使用渐变时,图像的大小就是元素的大小。 border-image-width 将定义我们将放置切片的 9 个区域(如果未定义,则使用 border-width)。 border-image-slice 将考虑初始图像来创建切片。无单位值被视为像素值,百分比值根据元素大小解析。

为了得到完美的结果,我们应该切片等于区域,为此我们需要在没有单元。使用百分比,计算的值应该相同。

在您的情况下,切片中的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-image-width,并使用了等于该边框宽度的切片。

请注意,切片中的50 在此处被视为像素,因为我们正在处理非矢量图像(渐变)。

数字表示图像中的像素(如果图像是光栅图像)或矢量坐标(如果图像是矢量图像)。 ref

让我们删除 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 个部分:

此属性指定从图像的顶部、右侧、底部和左侧边缘向内偏移,将其分为九个区域:四个角四个边缘和一个

ref

以下步骤可以更好地展示我们的示例是如何完成的:

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 个区域中。中间是空的,因为我们没有使用fill。在此示例中,我们不会注意到任何内容,因为切片适合区域。

现在让我们将切片缩减为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)。您可以清楚地注意到角落中的部分是如何简单缩放的,而边缘是如何扭曲的。

在每个角落,我们在50px 50px 区域内使用25px 25px 图像,例如在顶部边缘,我们在10px 50px 区域内使用60px 25px 图像。

您还可以为每一侧定义不同的值,如下所示:

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>

现在更清楚我们如何对图像进行切片,然后通过缩放将它们放在不同的区域中。同样清楚的是,最好的价值是让所有边的切片都等于border-width,在您的示例中就是这种情况,因为5em5x16px = 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>

【讨论】:

  • 非常感谢您提供如此详细的答案。我错误地认为渐变是矢量图像。你能告诉我,如果我们有一个矢量图像而不是梯度,那么数字 80 将是哪个单位(因为它应该是坐标)?
  • @Elistan ok 会尝试给你一个矢量图像的例子;)
【解决方案2】:

在下一个示例中,我使用 px 而不是 em,因为我认为更清晰。

这是用于边框图像的图像。

div{ width: 416px; height: 368px;
	background:repeating-linear-gradient(45deg, 
			#000, #000 1.5%, 
			transparent 1.5%, transparent 5%);
}
&lt;div&gt;&lt;/div&gt;

此图像将被切成 9 个正方形,类似于网格。

图片来自这篇文章:border-image-slice

如果border-image-slice 的值为 80,则表示偏移量为 80,即 C1、C2、C3 和 C4 的大小为 80/80。所有 C 切片都用于边界图像的角落。 E1,E2,E3 和 E4 用于绘制边缘。

如果您使用的是 208 或 50% 而不是 80,则边框图像将有角但没有边缘,因为边缘没有任何剩余。

接下来是一个演示,您可以在其中看到用于绘制边框图像的图像切片的演变。我将 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>

【讨论】:

    猜你喜欢
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 2021-11-17
    相关资源
    最近更新 更多