Home > Enterprise >  How to continue gradient from svg with css?
How to continue gradient from svg with css?

Time:11-04

I have this svg:

enter image description here

I would like to have a HTML page where the top part is the SVG and the bottom part is a div of dynamic height that continues the gradient

Like this:

<svg>...</svg>
<div id="gradient-box" >Gradient box of dynamic height</div>

enter image description here

I know that one can create gradients with CSS with color, opacity and degree enter image description here

  1. Compute the slope and the angle of the gradient. Note that in the coordinate system 0deg points to the right, while 0deg in CSS points upwards. Both angle values run clockwise.

    const slope = (p2.y - p1.y) / (p2.x - p1.x)
    const angle = (Math.atan2(p2.y - p1.y, p2.x - p1.x) / Math.PI * 180   270) % 360;
    
  2. Compute the positions of 0% and 100% as defined in CSS as coordinates. As seen in the diagram, these points are selected in such a way that the opposing corners get a color value that exactly matches those at these two values. The line connecting the two points goes through the center of the box. I'll leave out the trigonometry involved and just give the results for the points q1 and q2.

    if (angle == 0) {
      q1.x = width / 2
      q1.y = height
      q2.x = width / 2
      q2.y = 0
    } else if (angle == 180) {
      q1.x = width / 2
      q1.y = 0
      q2.x = width / 2
      q2.y = height
    } else {
      q1.x = (width * slope - height) / (slope   1/slope) / 2
      q1.y = -(width - height / slope) / (slope   1/slope) / 2
      q2.x = width - (width * slope - height) / (slope   1/slope) / 2
      q2.y = height   (width - height / slope) / (slope   1/slope) / 2
    }
    
  3. Compute the two points pp1 and pp2 on the line that are nearest to p1 and p2. This is a bit more of math, instead of spelling it out, refer to other questions like this one.

    The percentage values belonging to pp1 and pp2 can be found as a proportion of the distance between the two CSS end points.

    const f1 = (pp1.x - q1.x) / (q2.x - q1.x) || (pp1.y - q1.y) / (q2.y - q1.y);
    const f2 = (pp2.x - q1.x) / (q2.x - q1.x) || (pp2.y - q1.y) / (q2.y - q1.y);
    
  4. Compute the relative position of each color stop between f1 and f2.

    const stops = [...gradient.querySelectorAll('stop')].map(stop => {
      const color = stop.getAttribute('stop-color');
      const opacity = stop.getAttribute('stop-opacity');
      const offset = parseFloat(stop.getAttribute('offset'));
      const fraction = offset * (f2 - f1)   f1
      return {color, opacity, fraction};
    });
    

Now, you can finally express the CSS function. The last hurdle to overcome is to convert the RGB color string plus the opacity value to rgba() notation. You can find apropriate libraries for that. I am going to assume color-string:

const stopStrs = stops.map(({color, opacity, fraction}) => {
  const rgbValue = colorString.get(color);
  const opacityValue = parseFloat(opacity);
  const rgba = colorString.to.rgb(rgbValue, opacityValue);
  return `${fraction * 100}% ${rgba}`
};
const gradientFunction = `linearGradient(${angle}deg, ${stopStrs.join(', ')})`;
  • Related