1

I'm just working with linear-gradient in css, btw the generated gradient effect isn't same as the designs. I have never faced this problem in any Android, iOS, React Native or HTML5 canvas yet, but only on css.

.gradient {
  background-image: linear-gradient(to right top, red, blue);
}

I have made a fiddle for showing the differences between css's linear-gradient and canvas's create createLinearGradient. Please check this fiddle link.

example

The upper is css gradient and lower is canvas one. As you can see the canvas's createLinearGradient working well as expected, but on the css the same-color-line(yellow line in above pic) isn't vertical of the gradient's direction, rather looks as the another diagonal of the element. Is there any reason why is it in css?

4
  • This explains things pretty well: developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient. It displays like this because you added the "top" value Commented Aug 28, 2019 at 9:15
  • @Sorix, really thanks, your link is so helpful to understand about the linear-gradient, btw I have to make the gradient as to top-right direction for any dynamic rectangle elements. Is there any solution of my case in css? Commented Aug 28, 2019 at 9:27
  • maybe use an angle instead of top or bottom. If I understand correctly, your gradient should always be at the same angle... like this: linear-gradient(45deg, red, blue); Commented Aug 28, 2019 at 9:34
  • updated my answer with an interactive Demo Commented Aug 28, 2019 at 10:15

2 Answers 2

2

This is by design. You can read more about here: https://drafts.csswg.org/css-images-3/#linear-gradients.

If the argument instead specifies a corner of the box such as to top left, the gradient line must be angled such that it points into the same quadrant as the specified corner, and is perpendicular to a line intersecting the two neighboring corners of the gradient box. This causes a color-stop at 50% to intersect the two neighboring corners.

Basically, when using such keywords you will have a kind of stretched gradient going from corners and you loss the perpendicular feature with the diagonal.

.child {
  position:relative;
  width: 100px;
  height: 100px;
  border: 1px solid red;
  background-image: linear-gradient(to top right, red 50%, blue 0);
}
.child.alt {
  width:200px;
}

.child:before {
  content:"";
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  background:linear-gradient(to top left,transparent calc(50% - 5px),green,transparent calc(50% + 5px) );
}
this one is good because it's a square
<div class="child"></div>
but not this one
<div class="child alt"></div>

If you want to have the second output you need to use explicit angle and find the one that will make your gradient line the same as you diagonal line and for this you need to consider the angle equal to arctang(width/height)

In your case it will be arctang(300/75) = arctang(4) = 75.69deg. Since you are using JS you can easily do this calculation.

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

var grd = ctx.createLinearGradient(0, 75, 300, 0);
grd.addColorStop(0, "red");
grd.addColorStop(1, "blue");

ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 75);
.parent {
  width: 300px;
  height: 300px;
  align-items: center;
  justify-content: center;
  display: flex;
  flex-direction: column;
  background-color: #6EE2F5;
}
.child {
  width: 300px;
  height: 75px;
  border: 1px solid red;
  background-image: linear-gradient(75.69deg, red, blue);
}
#canvas {
  width: 300px;
  height: 75px;
  border: 1px solid green;
}
<div class="parent">
<div class="child"></div>
<canvas id="canvas" width=300 height=75/>
</div>

Here is an interactive Demo

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

function update() {
 var H = $('[name=h]').val();
 var W = $('[name=w]').val();
 $('.child').css('height',H);
 $('.child').css('width',W);
 $('canvas').attr("width", W);
 $('canvas').attr("height", H);
 var angle = Math.atan(W/H) 
 $('.child').css("--a", (angle * 180 / Math.PI)+"deg");

 var grd = ctx.createLinearGradient(0, H, W, 0);
 grd.addColorStop(0.4, "red");
 grd.addColorStop(0.6, "blue"); 
 ctx.fillStyle = grd;
 ctx.fillRect(0, 0, W, H);

}
$('input').change(update);
update();
.child {
  border: 1px solid;
  background-image: linear-gradient(var(--a), red 40%, blue 60%);
}
#canvas {
  border: 1px solid green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
W: <input type="number" name="w" step="1" value="300">
H: <input type="number" name="h" step="1" value="75">
<div class="child"></div>
<canvas id="canvas" width=300 height=75/>

Sign up to request clarification or add additional context in comments.

Comments

1

Just replace to right top to to right. If you set it to to right top there is a certain degree applied to linear-gradient() as it takes the bottom left as the starting point and extends up-to right top corner of the rectangle.

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

var grd = ctx.createLinearGradient(0, 75, 300, 0);
grd.addColorStop(0, "red");
grd.addColorStop(1, "blue");

ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 75);
.parent {
  width: 300px;
  height: 300px;
  align-items: center;
  justify-content: center;
  display: flex;
  flex-direction: column;
  background-color: #6EE2F5;
}

.child {
  width: 300px;
  height: 75px;
  border: 1px solid red;
  background-image: linear-gradient(to right, red, blue);
}

#canvas {
  width: 300px;
  height: 75px;
  border: 1px solid green;
}
<div class="parent">
  <div class="child"></div>
  <canvas id="canvas" width=300 height=75/>
</div>

9 Comments

Thanks for your answer, however is there any exact solution of my requirement (right-top diagonal)? I exactly need that.
But why would you need to use that keyword while requiring an alternative result? Is there any hackathon you are playing with? :)
I'm using that as a component on react project, so the element's size isn't fixed, will be change dynamically and the gradient should be work for any of rectangle.
as it takes the bottom left as the starting point and extends up-to right top corner of the rectangle. --> this isn't true, if it was this case then the OP should have the correct result
@TemaniAfif Can you update the answer then? I had to take this as reference: prnt.sc/oyk1hb if MDN is wrong or I am, please correct both of us with an edit.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.