SVG background applied to SVG shape stroke repeats instead of spreading - css

Let's say, I have a simple SVG: 1 circle, 1 linear gradient, apllied to its stroke.
I want gradient to spread along the stroke according to the stop-points: start from blue on the one end and finish on yellow color on another end.
But it somehow mirrors and repeats: blue color is in the middle and yellow on both ends of the circle.
What should I do to avoid repeating?
div {
width: 200px;
height: 200px;
}
svg {
width: 100%;
height: 100%;
}
<div>
<svg viewport="0 0 100 100" version="1.1">
<defs>
<linearGradient id="b7781eda-4425-42b1-a879-c912f4606b76">
<stop stop-color="#4158D0" offset="0%"></stop>
<stop stop-color="#C850C0" offset="46%"></stop>
<stop stop-color="#FFCC70" offset="100%"></stop>
</linearGradient>
</defs>
<circle r="92.5" cx="100" cy="100" fill="transparent" stroke="url(#b7781eda-4425-42b1-a879-c912f4606b76)" stroke-linecap="round" stroke-width="15" stroke-dasharray="581.1946409141117" stroke-dashoffset="58.119464091411174"></circle>
</svg>
</svg>
</div>

Related

How to crop an image width svg?

How to crop an image with path in this svg?
<svg width="1440" height="568" viewBox="0 0 1440 568" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0H1440V481.821L720 568L0 481.821V0Z" fill="url(#paint0_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="720" y1="607.026" x2="720" y2="35.2649" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="#0997FF" stop-opacity="0.56"/>
</linearGradient>
</defs>
</svg>
I want to set linearGradient of svg on an image and extra space in bottom of image be as same as background color of body(navy blue):
<div class="bg"></div>
.bg {
width: 100vw;
min-height: 500px;
background: url("../assets/images/mySvg.svg"),
url("../assets/images/myImage.jpg");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
What I have:
What I want:
Put the image into the SVG.
Combine the image and the gradient into an SVG group (<g>)
Then clip that group with an SVG <clipPath> defined using your original path.
Put the SVG inside the <div>
body {
background-color: linen;
}
.bg {
width: 100vw;
min-height: 500px;
}
<div class="bg">
<svg width="100%" viewBox="0 0 1440 568">
<defs>
<clipPath id="clip">
<path d="M0 0H1440V481.821L720 568L0 481.821V0Z"/>
</clipPath>
<linearGradient id="paint0_linear" x1="720" y1="607.026" x2="720" y2="35.2649" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="#0997FF" stop-opacity="0.56"/>
</linearGradient>
</defs>
<g clip-path="url(#clip)">
<image xlink:href="http://placekitten.com/1440/568" width="1440" height="568"/>
<rect width="1440" height="568" fill="url(#paint0_linear)"/>
</g>
</svg>
<p>More content here.</p>
</div>

use var to set offset position in SVG gradient

I am using a gradient to fill an svg path.
like this:
<svg viewBox="0 0 40 40">
<defs>
<linearGradient id="progress-gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="var(--offset-empty)" stopColor="var(--color-empty)" />
<stop offset="var(--offset-full)" stopColor="var(--color-full)" />
</linearGradient>
</defs>
<path d="..removed" fill="url(#progress-gradient)" />
</svg>
and I am styling it with css:
#progress-gradient {
--color-empty: #ffffff;
--color-full: #ff0000;
--offset-empty: 50%;
--offset-full: 100%;
}
I am trying to set the offsets dynamically to create a kind of progress within the SVG icon.
But this isn't working. Colors are working, but not offset.
Is there any other way I can dynamically set the offset positions with CSS?
many thanks

How to use less #variable for SVG inline style "stop-color"

I have two variables for colors in color.less
#color-example-1: red;
#color-example-2: yellow;
and an svg in example.html that looks something like this:
<svg viewBox="0 0 48 48">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
</style>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0" y1="24" x2="48" y2="24">
<stop offset="0" style="stop-color:#FFF33B"/>
<stop offset="1" style="stop-color:#E93E3A"/>
</linearGradient>
<circle class="st0" cx="24" cy="24" r="24"/>
</svg>
Is it possible to either replace the stop-color value with a #variable or (even better) define the whole linearGradient in the css file?
A desired result would be something like this:
css
.example-gradient {
background: linear-gradient(135deg, #color-example-1 0%,#color-example-2 100%);
}
html
<svg viewBox="0 0 48 48">
<circle class="example-gradient" cx="24" cy="24" r="24"/>
</svg>
You can't define the whole gradient in CSS. CSS gradients don't currently work on SVG elements. They might one day in the future. If they did, you would use something like the following:
circle {
fill: linear-gradient(to right, yellow, orange)
}
However all is not lost. You definitely can restyle the <stop> elements in the SVG gradient definition.
Note that the style="stop-color: ..." in the SVG gradient will override any CSS you define. So the first thing you need to do is remove it, or change it to a presentation attribute (stop-color="#abcdef").
.stop1 {
stop-color: blue;
}
.stop2 {
stop-color: yellow;
}
<svg viewBox="0 0 48 48">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
</style>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0" y1="24" x2="48" y2="24">
<stop offset="0" class="stop1" stop-color="#FFF33B"/>
<stop offset="1" class="stop2" stop-color="#E93E3A"/>
</linearGradient>
<circle class="st0" cx="24" cy="24" r="24"/>
</svg>
Note that I obviously haven't used LESS here, but it should work fine as long as your SVG is inlined in your HTML.

Circular arrows with gradient

I tried to make it with border but gradient makes it impossible. Maybe I can make four divs and make it like that?
CSS might not be the best way to create such shapes. You should use SVG instead.
We can use SVG's path element to create a pointing arrow like shape and fill it with gradient created with linearGradient.
Only one attribute d is used to define shapes in path element. This attribute itself contains a number of short commands and few parameters that are necessary for those commands to work.
Here is a detailed information about SVG paths:
body {
text-align: center;
background: #333;
margin: 20px;
}
<svg width="400" height="400" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="gradient">
<stop offset="0" stop-color="#212121"></stop>
<stop offset="1" stop-color="#a7a7a7"></stop>
</linearGradient>
<path id="arrow" x="0" y="0" d="M0,200
A200,200 0, 0, 1, 200,0
L225,25
L200,50
A150,150, 0, 0, 0 50,200
L25,175" fill="url(#gradient)" />
</defs>
<use xlink:href="#arrow" transform="translate(0,400) rotate(270)"></use>
<use xlink:href="#arrow" transform="translate(400,400) rotate(180)"></use>
<use xlink:href="#arrow" transform="translate(400,0) rotate(90)"></use>
<use xlink:href="#arrow"></use>
</svg>

SVG gradient using CSS

I'm trying to get a gradient applied to an SVG rect element.
Currently, I'm using the fill attribute. In my CSS file:
rect {
cursor: pointer;
shape-rendering: crispEdges;
fill: #a71a2e;
}
And the rect element has the correct fill color when viewed in the browser.
However, I'd like to know if I can apply a linear gradient to this element?
Just use in the CSS whatever you would use in a fill attribute.
Of course, this requires that you have defined the linear gradient somewhere in your SVG.
Here is a complete example:
rect {
cursor: pointer;
shape-rendering: crispEdges;
fill: url(#MyGradient);
}
<svg width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
rect{fill:url(#MyGradient)}
</style>
<defs>
<linearGradient id="MyGradient">
<stop offset="5%" stop-color="#F60" />
<stop offset="95%" stop-color="#FF6" />
</linearGradient>
</defs>
<rect width="100" height="50"/>
</svg>
2019 Answer
With brand new css properties you can have even more flexibility with variables aka custom properties
.shape {
width:500px;
height:200px;
}
.shape .gradient-bg {
fill: url(#header-shape-gradient) #fff;
}
#header-shape-gradient {
--color-stop: #f12c06;
--color-bot: #faed34;
}
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" class="shape">
<defs>
<linearGradient id="header-shape-gradient" x2="0.35" y2="1">
<stop offset="0%" stop-color="var(--color-stop)" />
<stop offset="30%" stop-color="var(--color-stop)" />
<stop offset="100%" stop-color="var(--color-bot)" />
</linearGradient>
</defs>
<g>
<polygon class="gradient-bg" points="0,0 100,0 0,66" />
</g>
</svg>
Just set a named variable for each stop in gradient and then customize as you like in css. You can even change their values dynamically with javascript, like:
document.querySelector('#header-shape-gradient').style.setProperty('--color-stop', "#f5f7f9");
Building on top of what Finesse wrote, here is a simpler way to target the svg and change it's gradient.
This is what you need to do:
Assign classes to each color stop defined in the gradient element.
Target the css and change the stop-color for each of those stops using plain classes.
Win!
Some benefits of using classes instead of :nth-child is that it'll not be affected if you reorder your stops. Also, it makes the intent of each class clear - you'll be left wondering whether you needed a blue color on the first child or the second one.
I've tested it on all Chrome, Firefox and IE11:
.main-stop {
stop-color: red;
}
.alt-stop {
stop-color: green;
}
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="gradient">
<stop class="main-stop" offset="0%" />
<stop class="alt-stop" offset="100%" />
</linearGradient>
<rect width="100" height="50" fill="url(#gradient)" />
</svg>
See an editable example here:
https://jsbin.com/gabuvisuhe/edit?html,css,output
Here is a solution where you can add a gradient and change its colours using only CSS:
// JS is not required for the solution. It's used only for the interactive demo.
const svg = document.querySelector('svg');
document.querySelector('#greenButton').addEventListener('click', () => svg.setAttribute('class', 'green'));
document.querySelector('#redButton').addEventListener('click', () => svg.setAttribute('class', 'red'));
svg.green stop:nth-child(1) {
stop-color: #60c50b;
}
svg.green stop:nth-child(2) {
stop-color: #139a26;
}
svg.red stop:nth-child(1) {
stop-color: #c84f31;
}
svg.red stop:nth-child(2) {
stop-color: #dA3448;
}
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="gradient">
<stop offset="0%" />
<stop offset="100%" />
</linearGradient>
<rect width="100" height="50" fill="url(#gradient)" />
</svg>
<br/>
<button id="greenButton">Green</button>
<button id="redButton">Red</button>
Thank you everyone,
for all your precise replys.
Using the svg in a shadow dom, I add the 3 linear gradients I need within the svg, inside a .
I place the css fill rule on the web component and the inheritance od fill does the job.
<svg viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<path
d="m258 0c-45 0-83 38-83 83 0 45 37 83 83 83 45 0 83-39 83-84 0-45-38-82-83-82zm-85 204c-13 0-24 10-24 23v48c0 13 11 23 24 23h23v119h-23c-13 0-24 11-24 24l-0 47c0 13 11 24 24 24h168c13 0 24-11 24-24l0-47c0-13-11-24-24-24h-21v-190c0-13-11-23-24-23h-123z"></path>
</svg>
<svg height="0" width="0">
<defs>
<linearGradient id="lgrad-p" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#4169e1"></stop><stop offset="99%" stop-color="#c44764"></stop></linearGradient>
<linearGradient id="lgrad-s" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#ef3c3a"></stop><stop offset="99%" stop-color="#6d5eb7"></stop></linearGradient>
<linearGradient id="lgrad-g" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#585f74"></stop><stop offset="99%" stop-color="#b6bbc8"></stop></linearGradient>
</defs>
</svg>
<div></div>
<style>
:first-child {
height:150px;
width:150px;
fill:url(#lgrad-p) blue;
}
div{
position:relative;
width:150px;
height:150px;
fill:url(#lgrad-s) red;
}
</style>
<script>
const shadow = document.querySelector('div').attachShadow({mode: 'open'});
shadow.innerHTML="<svg viewbox=\"0 0 512 512\">\
<path d=\"m258 0c-45 0-83 38-83 83 0 45 37 83 83 83 45 0 83-39 83-84 0-45-38-82-83-82zm-85 204c-13 0-24 10-24 23v48c0 13 11 23 24 23h23v119h-23c-13 0-24 11-24 24l-0 47c0 13 11 24 24 24h168c13 0 24-11 24-24l0-47c0-13-11-24-24-24h-21v-190c0-13-11-23-24-23h-123z\"></path>\
</svg>\
<svg height=\"0\">\
<defs>\
<linearGradient id=\"lgrad-s\" gradientTransform=\"rotate(75)\"><stop offset=\"45%\" stop-color=\"#ef3c3a\"></stop><stop offset=\"99%\" stop-color=\"#6d5eb7\"></stop></linearGradient>\
<linearGradient id=\"lgrad-g\" gradientTransform=\"rotate(75)\"><stop offset=\"45%\" stop-color=\"#585f74\"></stop><stop offset=\"99%\" stop-color=\"#b6bbc8\"></stop></linearGradient>\
</defs>\
</svg>\
";
</script>
The first one is normal SVG,
the second one is inside a shadow dom.
Here is how to set a linearGradient on a target element:
<style type="text/css">
path{fill:url('#MyGradient')}
</style>
<defs>
<linearGradient id="MyGradient">
<stop offset="0%" stop-color="#e4e4e3" ></stop>
<stop offset="80%" stop-color="#fff" ></stop>
</linearGradient>
</defs>

Resources