边界图像如何与线性渐变一起工作? [英] How does border-image work with linear-gradient?

查看:43
本文介绍了边界图像如何与线性渐变一起工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

在CSS技巧的 参考

下面的步骤将更好地说明我们的示例是如何完成的:

  div {宽度:100px;高度:100px;边框:实心10px透明;显示:inline-block;职位:相对}div:之前{内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(绿色,绿色)左0顶部50px/100%1px不重复,线性渐变(绿色,绿色)左0底部50px/100%1px不重复,线性渐变(绿色,绿色)顶部0左50px/1px 100%不重复,线性渐变(绿色,绿色)顶部0右50px/1px 100%不重复;}div.box {背景:repeating-linear-gradient(45deg,#000,#000 5px,透明5px,透明10px)边框,红色;}div.border {border-image:重复线性渐变(45deg,#000,#000 5px,透明5px,透明10px)50;border-image-width:50px;背景:红色;}  

 < div class ="box"></div>< div class ="border"></div>  

左图是原始图像,我们将其分为9个部分,然后将每个图像放置在右图的9个区域中.中间一个是空的,因为我们没有使用 fill .在此示例中,由于切片适合区域,因此我们什么也没注意到.

现在让我们将切片减少为 25 :

  div {宽度:100px;高度:100px;边框:实心10px透明;显示:inline-block;职位:相对}div.box:之前{内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:linear-gradient(blue,blue)left 0 top 25px/100%1px no-repeat,线性渐变(蓝色,蓝色)向左0底部25px/100%1px不重复,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:{之前内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(绿色,绿色)向左0顶部50px/100%1px不重复,线性渐变(绿色,绿色)左0底部50px/100%1px不重复,线性渐变(绿色,绿色)顶部0左50px/1px 100%不重复,线性渐变(绿色,绿色)顶部0右50px/1px 100%不重复;}div.box {背景:repeating-linear-gradient(45deg,#000,#000 5px,透明5px,透明10px)边框,红色;}div.border {border-image:重复线性渐变(45deg,#000,#000 5px,透明5px,透明10px)25;border-image-width:50px;背景:红色;}  

 < div class ="box"></div>< div class ="border"></div>  

这有点棘手,但适用相同的逻辑.从左侧的图像中,我们分别使用 25px 进行切割,以得到我们将放置在右侧的9个部分,其中边框宽度仍然相同( 50px ).您可以清楚地注意到角落中的零件是如何简单缩放和边缘变形的.

在每个角落,我们在 50px 50px 区域内使用 25px 25px 图像,例如,在上边缘,我们使用 60px 25px 10px 50px 区域内的code>图片.

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

  div {宽度:100px;高度:100px;边框:实心10px透明;显示:inline-block;职位:相对}div.box:之前{内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(蓝色,蓝色)左0顶部20px/100%1px不重复,线性渐变(蓝色,蓝色)左0底部30px/100%1px不重复,线性渐变(蓝色,蓝色)顶部0左20px/1px 100%不重复,linear-gradient(blue,blue)top 0 right 60px/1px 100%no-repeat;}div.border:{之前内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(绿色,绿色)向左0顶部50px/100%1px不重复,线性渐变(绿色,绿色)左0底部50px/100%1px不重复,线性渐变(绿色,绿色)顶部0左50px/1px 100%不重复,线性渐变(绿色,绿色)顶部0右50px/1px 100%不重复;}div.box {背景:repeating-linear-gradient(45deg,#000,#000 5px,透明5px,透明10px)边框,红色;}div.border {border-image:重复线性渐变(45deg,#000,#000 5px,透明5px,透明10px);border-image-slice:20 60 20 30;border-image-width:50px;背景:红色;}  

 < div class ="box"></div>< div class ="border"></div>  

现在更清楚的是我们如何对图像进行切片,然后通过缩放拉伸将它们放置在不同的区域中.同样很明显,最好的做法是使所有边上的切片都等于 border-width ,在您的示例中就是这种情况,因为 5em 5x16px= 80px ,因此是 80

的一部分

从规范中我们还可以阅读:

border-image-slice值给定的区域可能重叠.但是,如果左右宽度的总和等于或大于图像的宽度,则上下边缘和中间部分的图像为空,其效果与非空透明图像相同.为这些零件指定.类似地,用于顶部和底部值.

如果您指定的左切片和右切片大于图像宽度,那么从逻辑上讲,您不会在顶部/底部/中间部分放置任何内容:

  div {宽度:100px;高度:100px;边框:实心10px透明;显示:inline-block;职位:相对}div.box:之前{内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(蓝色,蓝色)左0顶部20px/100%1px不重复,线性渐变(蓝色,蓝色)左0底部30px/100%1px不重复,线性渐变(蓝色,蓝色)顶部0左60px/1px 100%不重复,linear-gradient(blue,blue)top 0 right 60px/1px 100%no-repeat;}div.border:{之前内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(绿色,绿色)向左0顶部50px/100%1px不重复,线性渐变(绿色,绿色)左0底部50px/100%1px不重复,线性渐变(绿色,绿色)顶部0左50px/1px 100%不重复,线性渐变(绿色,绿色)顶部0右50px/1px 100%不重复;}div.box {背景:repeating-linear-gradient(45deg,#000,#000 5px,透明5px,透明10px)边框,红色;}div.border {border-image:重复线性渐变(45deg,#000,#000 5px,透明5px,透明10px);border-image-slice:20 60 20 60;border-image-width:50px;背景:红色;}  

 < div class ="box"></div>< div class ="border"></div>  

相同的逻辑也适用于顶部/底部.

在这里是一个只有拐角的示例:

  div {宽度:100px;高度:100px;边框:实心10px透明;显示:inline-block;职位:相对}div.box:之前{内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(蓝色,蓝色)左0顶部20px/100%1px不重复,线性渐变(蓝色,蓝色)左0底部100px/100%1px不重复,线性渐变(蓝色,蓝色)顶部0左60px/1px 100%不重复,linear-gradient(blue,blue)top 0 right 60px/1px 100%no-repeat;}div.border:{之前内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(绿色,绿色)向左0顶部50px/100%1px不重复,线性渐变(绿色,绿色)左0底部50px/100%1px不重复,线性渐变(绿色,绿色)顶部0左50px/1px 100%不重复,线性渐变(绿色,绿色)顶部0右50px/1px 100%不重复;}div.box {背景:repeating-linear-gradient(45deg,#000,#000 5px,透明5px,透明10px)边框,红色;}div.border {border-image:重复线性渐变(45deg,#000,#000 5px,透明5px,透明10px);border-image-slice:20 60 100 60;border-image-width:50px;背景:红色;}  

 < div class ="box"></div>< div class ="border"></div>  


使用百分比值也将得到相同的结果.我们只需要找到参考,并且由于我们正在处理渐变,渐变的大小就是元素的大小.在我们的示例中,切片 50 等于 41.666%,因为宽度/高度等于 100px 2 * 10px = 120px

  div {宽度:100px;高度:100px;边框:实心10px透明;显示:inline-block;职位:相对}div:之前{内容: "";位置:绝对;顶部:-10px;左:-10px;右:-10px;底部:-10px;背景:线性渐变(蓝色,蓝色)左0顶部50px/100%1px不重复,线性渐变(蓝色,蓝色)左0底部50px/100%1px不重复,线性渐变(蓝色,蓝色)顶部0左50px/1px 100%不重复,linear-gradient(blue,blue)top 0 right 50px/1px 100%no-repeat;}div.box {背景:repeating-linear-gradient(45deg,#000,#000 5px,透明5px,透明10px)边框,红色;}div.border {border-image:重复线性渐变(45deg,#000,#000 5px,透明5px,透明10px)41.666%;border-image-width:50px;背景:红色;}  

 < div class ="box"></div>< div class ="border"></div>  

I am trying to understand how border-image-slice works in the case of gradient border image. In spec it is written that a value for border-image-slice could be a number which

Represents an edge offset in pixels for raster images and coordinates for vector images. For vector images, the number is relative to the element's size, not the size of the source image, so percentages are generally preferable in these cases.

In the examples from CSS-tricks article a border-image is set like this:

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

So, according to the spec 80 is relative to the div's size (width: 26em; height: 23em;). But I still don't understand what does it mean. When I change div's width or height, the border image doesn't change its look. But when I change border-image-slice or border width, the look changes significantly. So it seems like there is a correlation between number 80 and the border width of 5em. (the border looks the same for number 40 and border width of 2.5em, 16 for 1em, etc.).

My question is how number 80 is calculated meaning what is the slicing process for a given div and the gradient? (A sketch would be greatly appreciated) And it seems like 80 is not in px, em or %, because when I add those units the look is changing.

The full code is here:

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

When using a gradient, the size of the image is the size of the element. The border-image-width will define the 9 regions where we will place the slices (if not defined, border-width is used). The border-image-slice will consider the initial image to create the slices. A unitless value is considered as a pixel value and a percentage value is resolved against the size of the element.

To have a perfect result we should have the slices equal to regions, and for this we need to have the border-image-slice equal to border-image-width (or border-width) when used without a unit. Using a percentage, the computed value should be the same.

In your case 80 in the slice means 80px and you have a border of 5em which is 5x16px = 80px.


Let's take an easy example.

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>

In the above I tried to create two divs with the same output using different techniques (background and border). Notice how in the second example I use the keyword fill and I specified a border-image-width different from the border width and used a slice equal to that border width.

Note that 50 in the slice is considered as pixels here since we're dealing with a non-vector image (a gradient).

Numbers represent pixels in the image (if the image is a raster image) or vector coordinates (if the image is a vector image). ref

Let's remove the fill keyword:

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>

The fill keyword, if present, causes the middle part of the border-image to be preserved. (By default it is discarded, i.e., treated as empty.) ref

By default, the border image is not painted in the middle but only in the border. We can clearly see from the example that we have 50px on each side, with our custom border likewise defined by border-image-width.

And if we don't specify border-image-width the default value is 1 which means:

Numbers represent multiples of the corresponding computed border-width.

So either we explicitely specify border-image-width or we simply use border-width as reference. In most cases only border-width is needed since in most cases we want to only cover the border area and not more.

Now the slice will split the image in 9 parts:

This property specifies inward offsets from the top, right, bottom, and left edges of the image, dividing it into nine regions: four corners, four edges and a middle

ref

Here are the steps that will better show how it's done for our example:

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>

The left image is the original one that we divide into 9 parts, then we put each one in the 9 regions of the right one. The middle one is empty because we didn't use fill. In this example we will notice nothing because the slices fit the regions.

Now let's reduce the slice to 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>

It's a bit tricky but the same logic applies. From the left image we cut using 25px from each side to get our 9 portions that we will put in the right one, where the border-width is still the same (50px). You can clearly notice how the parts in the corners are simply scaled and the edges are distorted.

In each corner we are using a 25px 25px image inside a 50px 50px area and in the top edge for example we are using a 60px 25px image inside a 10px 50px area.

You can also define different values for each side to have something like below:

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>

Now it's more clear how we slice the image then we put them in the different region by scaling stretching them. It's also clear that the best value is to have the slices in all the sides equal to the border-width which is the case in your example since 5em is 5x16px = 80px thus a slice of 80


From the specification we can also read:

The regions given by the border-image-slice values may overlap. However if the sum of the right and left widths is equal to or greater than the width of the image, the images for the top and bottom edge and the middle part are empty, which has the same effect as if a nonempty transparent image had been specified for those parts. Analogously for the top and bottom values.

If you specify a left and right slice bigger than the image width then logically you will get nothing to put on the top/bottom/middle part:

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>

The same logic applies to top/bottom too.

Here is an example where we will only have the corners:

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>


Using a percentage value will also give the same result. We simply need to find the reference and since we are dealing with a gradient, the size of the gradient is simply the size of the element. A slice of 50 in our example is equal to 41.666% since the width/height is equal to 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>

这篇关于边界图像如何与线性渐变一起工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆