基于矩形两个点创建CSS线性渐变

3

我正在尝试在Sketch中重新创建渐变工具。Sketch中的该工具使用两个带有不同颜色的点来定义渐变:

Sketch中渐变工具的外观示例

我希望输出结果是一个CSS线性渐变值。CSS线性渐变的构建方式为一个角度和x个彩色停止位置,每个停止位置包括一个颜色和一个百分比值: https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient

因此,我想将相对于应呈现渐变的矩形的两个点转换为CSS格式(带有正确百分比的两个参数)。

有什么想法可以解决这个问题吗?


请参阅 https://developer.mozilla.org/zh-CN/docs/Web/CSS/linear-gradient#Composition_of_a_linear_gradient。角度将保持不变,您可以沿着该角度移动线条而不改变渐变,因此将其移动到渐变线上并确定点的比较方式。 - Ry-
2个回答

8

没有通用的公式,但是您需要进行一些操作/计算,以找到梯度的程度以及渐变的background-size/background-position

让我们从一个简单的例子开始:

enter image description here

这里我们有一个渐变,角度为180度(或0度)。起点在顶部的50px处,终点在底部的100px处。考虑到这一点,我们会得到以下渐变:

.box {
  width: 200px;
  height: 100px;
  border: 1px solid;
  margin: 20px;
  background-image: linear-gradient(180deg, white, black);
  background-size: 100% calc(100% + 50px + 100px);
  background-position: 0 -50px;
  background-repeat: no-repeat;
}
<div class="box"></div>

正如您所看到的,总大小将是100%+ 150px,我们将有一个偏移量为-50px的位置。我们还可以考虑100px的偏移量,它将是100%+ 100px

.box {
  width:200px;
  height:100px;
  border:1px solid;
  margin:20px;
  background-image:linear-gradient(180deg,white,black);
  background-size:100% calc(100% + 50px + 100px);
  background-position:0 calc(100% + 100px);
  background-repeat:no-repeat;
}
<div class="box">

</div>

这是另一个例子:

enter image description here

在这种情况下,点是内部的,因此我们只需要调整梯度内部的颜色停止点:

.box {
  width: 200px;
  height: 100px;
  border: 1px solid;
  margin: 20px;
  background-image: linear-gradient(90deg, white 50px, black calc(100% - 50px));
}
<div class="box"></div>

这里是一个混合体,我们有一个外部点和一个内部点:

enter image description here

.box {
  width: 200px;
  height: 100px;
  border: 1px solid;
  margin: 20px;
  background-image: linear-gradient(90deg, white 50px, black);
  background-size: calc(100% + 100px) 100%;
  background-position: 0 0;
  background-repeat: no-repeat;
}
<div class="box"></div>


正方向的情况相对来说比较容易。我们只需找到梯度的大小、位置和渐变内颜色的停止点即可。

当涉及到其他角度值时,就会更加棘手。

这里是一个示例的插图:

enter image description here

你的渐变由橙色线条定义。第一步是根据文档绘制渐变线,该线将与你的线平行。绘制完成后,你将获得渐变的角度
之后,我们对你的线进行投影,你将获得颜色停止点。所需值用绿色显示。
我们的渐变将如下所示:
background-image:linear-gradient(Xdeg,white Apx,black calc(100% - Bpx));

在这种情况下,我考虑了一个例子,其中我们只有内部点,但如果橙色线的投影将导致外部点(如第一个示例),则可能会变得更加复杂,在这种情况下,我们需要考虑增加background-size的两个方向,这也有些棘手。

enter image description here

正如您所看到的,我们有一个点在梯度点之外,由距离B定义。我们建立了一个直角三角形来找到如何增加background-size

我们的渐变将如下所示:

background-image:linear-gradient(Xdeg,white Apx,black);
background-size:calc(100% + w) calc(100% + h);
background-position:0 0;

更新

如果您不想使用background-size/background-position,另一种方法是将渐变转换为使用内部点。当然,只有在点位于外部且想要找到最接近的内部点以获得相同的渐变效果时,此方法才有用。

让我们重新看一下第一个例子。在该示例中,我们在顶部的50px处有第一个点,逻辑上最接近的内部点是0px处的点(与其他点的逻辑相同)。因此,我们只需要找到新点的颜色并使用它们即可。

.box {
  width: 200px;
  height: 100px;
  border: 1px solid;
  margin: 20px;
}

.old {
  background-image: linear-gradient(180deg, white, black);
  background-size: 100% calc(100% + 50px + 100px);
  background-position: 0 -50px;
  background-repeat: no-repeat;
}
.new {
  background-image:linear-gradient(180deg,rgb(203, 203, 203),rgba(103, 103, 103));
}
<div class="box old"></div>
<div class="box new"></div>

在这个特定的例子中,计算很容易,因为初始渐变的大小是 250px,白色 (255,255,255) 和黑色 (0,0,0) 之间有 255 个值 (几乎是 250),所以我们从中减去了 50 来找到第一种颜色,并添加了 100 来找到最后一种颜色。
让我们用不同的颜色来考虑相同的渐变:紫色 (128,0,128) 和橙色 (255,165,0),渐变的大小是 250px,所以第一个偏移量 (50px) 是大小的20%,第二个偏移量 (100px) 是大小的40%。我们使用这些百分比来找到新的颜色。

对于红色,我们有128255,因此差值为127,其中的20%25.440%50.4),因此第一个点将具有153.4(128 + 25.4),而最后一个点将具有204.2(255-50.4)。我们对绿色蓝色做同样的计算,然后得到以下渐变:

.box {
  width: 200px;
  height: 100px;
  border: 1px solid;
  margin: 20px;
}

.old {
  background-image: linear-gradient(180deg, purple, orange);
  background-size: 100% calc(100% + 50px + 100px);
  background-position: 0 -50px;
  background-repeat: no-repeat;
}
.new {
  background-image:linear-gradient(180deg,rgb(153, 33, 102),rgba(204, 99, 51));
}
<div class="box old"></div>
<div class="box new"></div>


非常感谢您的深入回复!我没有考虑过改变背景大小。这是唯一的方法吗?不能仅使用线性渐变定义来完成吗? - carl lindth
@user3449608,正如你所看到的,它取决于情况。如果你的点在梯度区域内,那么可以使用;如果不是,你就必须调整大小或者采用另一种巧妙的方法,即找到最接近的内部点来使用,但这需要找到颜色[希望你明白我的意思,如果不明白,我可以在答案中加以说明]。 - Temani Afif
@user3449608,我已经添加了另一种方法来避免使用background-size ;) - Temani Afif

3
这是我解决问题的方式!
如果您查看我附加的GIF,可以看到其中显示了我在计算中使用的点。红线是矩形中心的梯度线,黑点是梯度线的起始和结束点。另外两个点(黑白)是用户可控制的点,用户可以任意拖动。两个红点是相对于每个用户控制点的线最接近的位置(垂直线点p1和p2)。
我获取垂直线点与梯度线起点和终点之间的距离。然后为了计算CSS线性渐变值所需的百分比值,我将两个距离相加,除以梯度线长度,并将该值乘以100。
ax = ((p1.x - gradientLine.point1.x) * (gradientLine.length / 2)) / (gradientLine.point2.x - gradientLine.point1.x);
ay = ((p1.y - gradientLine.point1.y) * (gradientLine.length / 2)) / (gradientLine.point2.y - gradientLine.point1.y);

percentValue = (((ax + ay) / line.length) * 100);

为了获取线性渐变值中第二个参数的值,我会做类似的操作,不同之处在于我会用计算出来的值减去100。
ax = ((p2.x - gradientLine.point2.x) * (gradientLine.length / 2)) / (gradientLine.point1.x - gradientLine.point2.x);
ay = ((p2.y - gradientLine.point2.y) * (gradientLine.length / 2)) / (gradientLine.point1.y - gradientLine.point2.y);
percentValue = 100 - ((((ax + ay) / gradientLine.length) * 100));

这样,我可以获得两个百分比值,并可以轻松构造我的CSS线性渐变值,其中包括两个用户控制点的角度加上我计算的两个百分比值:
background: linear-gradient([angle]deg, black [percentValue1]%, white [percentValue2]%)

gradient tool


是的,除了我不会对颜色值进行任何计算。 - carl lindth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接