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

Creating a CSS linear gradient based on two points relative to a rectangle

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

我希望输出采用 CSS 线性渐变值的形式。 CSS 线性渐变的构建方式是一个角度和 x 个颜色停止,颜色和百分比定义为:https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient

所以我想将相对于应该渲染渐变的矩形的两个点转换为CSS格式(两个参数具有正确的百分比)。

关于如何解决这个问题有什么想法吗?

没有通用公式,但您必须做一些 manipulation/calculation 才能找到梯度的度数以及梯度的 background-size/background-position

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

这里我们有一个 180deg(或 0deg)的渐变。起点在顶部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>

这是另一个例子:

在这种情况下,点在内部,因此我们只需调整渐变内部的色标即可:

.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>

这是我们有外点和内点的混合:

.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>


如您所见,在垂直方向上它在某种程度上很容易。我们只需要找到渐变的大小,它的位置和渐变内的颜色停止。

当然,当涉及到其他角度值时就比较棘手了。

这是一个示例的说明:

您的渐变由橙色线定义。第一步是根据the documentation绘制渐变线,这条线将与你的线平行。画完这条线,你就会得到渐变的角度

之后,我们会对您的线条进行投影,您将获得 色标 。所需的值以绿色显示。

我们的渐变看起来像这样:

background-image:linear-gradient(Xdeg,white Apx,black calc(100% - Bpx));

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

如您所见,我们有一个外部点,由距渐变点的距离 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% 的大小。我们使用这些百分比来查找新颜色。

对于 red 我们有 128255 所以区别是 12720%[=它的 163=] 是 25.4(而 40%50.4)因此第一个点将具有 153.4 (128 + 25.4),最后一个点将具有 204.2 (255 - 50.4)。我们对 greenblue 进行相同的计算,得到以下梯度:

.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>

我就是这样解决的!

如果您查看我附上的 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]%)