最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Creating a CSS linear gradient based on two points relative to a rectangle - Stack Overflow

programmeradmin2浏览0评论

I am trying to recreate the gradient tool in Sketch. The tool in Sketch is using two points with different colors to define a gradient:

I want the output to be in the form of a CSS linear gradient value. The way a CSS linear gradient is constructed is an angle and x number of color stops with a color and a percentage defined:

So I want to convert two points relative to the rectangle in which the gradient should be rendered to the CSS format (two parameters with the correct percentage).

Any ideas on how to approach this problem?

I am trying to recreate the gradient tool in Sketch. The tool in Sketch is using two points with different colors to define a gradient:

I want the output to be in the form of a CSS linear gradient value. The way a CSS linear gradient is constructed is an angle and x number of color stops with a color and a percentage defined: https://developer.mozilla/en-US/docs/Web/CSS/linear-gradient

So I want to convert two points relative to the rectangle in which the gradient should be rendered to the CSS format (two parameters with the correct percentage).

Any ideas on how to approach this problem?

Share Improve this question edited Feb 22, 2019 at 14:55 Temani Afif 275k28 gold badges365 silver badges486 bronze badges asked Aug 16, 2018 at 16:09 carl lindthcarl lindth 1211 silver badge7 bronze badges 1
  • See developer.mozilla/en-US/docs/Web/CSS/…. The angle will be the same, and you can move the line along that angle without changing the gradient, so move it to the gradient line and figure out how the points pare. – Ry- Commented Aug 16, 2018 at 16:19
Add a ment  | 

2 Answers 2

Reset to default 8

There is no generic formula but you have to do some manipulation/calculation in order to find the degree of the gradient and also background-size/background-position of the gradient.

Let's start with an easy example:

Here we have a gradient with 180deg (or 0deg). The starting point is 50px on the top and the end point is 100px on the bottom. Considering this, we will have the below gradient:

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

As you can see, the total size will be 100% + 150px and we will have an offset of -50px for the position. We can also have an offset considering the 100px and it will be 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>

Here is another example:

In this case, the points are inside so we simply need to adjust color stops inside the gradient:

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

Here is mix where we have an outside and inside point:

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


As you can see, it's somehow easy when it es to perpendicular direction. We simply need to find the size of gradient, its position and the color stops inside the gradient.

Of course, it's more tricky when it es to other values of angle.

Here is an illustration of one example:

You gradient is defined by the orange line. The first step is to draw the line of the gradient according to the documentation, this line will be parallel to your line. After drawing this line, you will have the angle of the gradient.

After that, we do a projection of your line and you will have your color stops. The needed values are shown with a green color.

Our gradient will look like this:

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

In this case, I considered an example where we only have inside points but it can bee more plex if the projection of the orange line will lead to outside points (like the first example) and in this case we need to consider increasing the background-size on both directions and this is also a bit tricky.

As you can see we have a point outside defined by the distance B from the gradient point. We have build a rectangle triangle in order to find how to increase the background-size.

Our gradient will look like this:

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

Update

Another approach in case you don't want to play with background-size/background-position is to convert the gradient to use inside points. Of course, this approach is useful only when the points are outside and the idea is to find the closest inside points that will allow us to obtain the same gradient.

Let's retake the first example. In that example we have the first point at 50px on the top and logically the closest inside point is the one at 0px (same logic with the other point). So we simply need to find what is color of the new points and use them.

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

In this particular example, the calculation is easy because the size of the initial gradient was 250px and between the white (255,255,255) and the black(0,0,0) we have 255 values (almost 250) so we have somehow removed 50 to find the first color and added 100 to find the last one.

Let's take the same gradient but with different colors: purple (128,0,128) and orange (255,165,0). the size of the gradient is 250px so the first offset (50px) is 20% of the size and the second offset (100px) is 40% of the size. We use those percentage to find the new colors.

For the red we have 128 and 255 so the difference is 127 and 20% of it is 25.4 (and 40% is 50.4) thus the first point will have 153.4 (128 + 25.4) and the last point will have 204.2 (255 - 50.4). We do the same calculation for the green and blue and we obtain the following gradient:

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

This was the way I solved it!

If you look at the GIF I have attached which illustrates the points I am using in my calculations. The red line is the gradient line in the center of the rectangle and the black points are the start and end points of the gradient line. The two other points (black and white) is the user controlled points that the user can drag around any way he likes. The two red dots are the closest position on the line relative to each user controlled point (perpendicular line points, p1 and p2).

I get the distance between the perpendicular line points and the gradient line start and end points. And then to calculate the percent value needed for the CSS linear-gradient value, I add the two distances, dived them by the gradient line length and multiply the value by 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);

To get the value for the second parameter in the linear-gradient value I just do kind of the same thing, except I subtract 100 with the calculate value.

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));

This way I get two percent values and can easily construct my CSS linear-gradient value consisting off the angle of the two user controlled points plus the two percent values I calculate:

background: linear-gradient([angle]deg, black [percentValue1]%, white [percentValue2]%)

发布评论

评论列表(0)

  1. 暂无评论