用于渐变边框图像的border-image-slice

时间:2019-07-06 13:02:38

标签: css border

我试图了解在渐变边框图像的情况下border-image-slice的工作方式。规范中写道,border-image-slice的值可以是一个数字,

  

表示光栅图像的边缘偏移量(像素)和矢量图像的坐标。对于矢量图像,数字是相对于元素的大小,而不是源图像的大小,因此在这种情况下,通常最好使用百分比。

examples中,来自CSS技巧article的边框图像设置如下:

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

因此,根据规范80是相对于div的大小(宽度:26em;高度:23em;)。但是我还是不明白这是什么意思。当我更改div的宽度或高度时,边框图像不会改变其外观。但是,当我更改border-image-slice或border宽度时,外观会发生很大变化。所以看起来数字80与5em的边框宽度之间存在相关性。 (数字40的边框看起来相同,边框宽度为2.5em,1em的边框宽度为16等)。

我的问题是,如何计算数字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 个答案:

答案 0 :(得分:1)

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

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

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

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

enter image description here

图片来自本文: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>

答案 1 :(得分:1)

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被视为像素。

  

数字表示图像中的像素(如果图像是光栅图像)或矢量坐标(如果图像是矢量图像)。 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个部分

  

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

enter image description here 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个区域中。中间一个是空的,因为我们没有使用填充。在此示例中,由于切片适合区域,因此我们什么也没注意到。

现在让我们将切片缩小为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>

现在,我们更加清楚如何对图像进行切片,然后通过缩放拉伸将它们放置在不同的区域中。显然,最好的值是使所有侧面的切片都等于边框宽度,在您的示例中就是这样,因为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>