How to gradient fill an SVG from an external stylesheet? - html

I love external stylesheets and want to be able to style any SVG graphics via an external sheet. I can declare single colour stroke and fill for my SVG logo but I want a gradient fill. I've tried a view things but can't get it to work right. Can someone help me figure out how to make it work?
I'm not sure how to put a code snippet considering I'm discussing external code, not inline, so here's a link to the SVG logo in question and its matching external stylesheet.
Actual logo I'm trying to recreate in SVG (PNG):
SVG logo: http://www.cafenocturne.com/testpage/images/svg/CafeLogoSVG.svg
Stylesheet: http://www.cafenocturne.com/testpage/css/CafeLogoSVG.css
There are some commented-out notes to make sure I don't lose the gradient code I'm trying to implement so I apologize that the CSS file is a mess. Once I can get it to work right, I won't need to keep notes there.
So how do I achieve this?

add the gradient to your SVG file, and change the stop-color from CSS:
#color1 {
stop-color: red
}
#color2 {
stop-color: blue
}
<svg>
<linearGradient id="lg">
<stop id="color1" offset="0" />
<stop id="color2" offset="1" />
</linearGradient>
<circle cx="50" cy="50" r="45" fill="url(#lg)" />
</svg>
if you need more control of your gradients, you could specify gradients in a seperate file (say 'myGradients.svg')
<svg xmlns="http://www.w3.org/2000/svg">
<linearGradient id="g1">
<stop offset="0" stop-color="red"/>
<stop offset="1" stop-color="blue"/>
</linearGradient>
<linearGradient id="g2">
<stop offset="0" stop-color="green"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
</svg>
now in your css you can do
.logo {fill: url('myGradients.svg#g2');}
unfortunately this doesn't work in chrome :-(
alternatively you can have a copy of your gradient collection in your logo file or html, and still style it with css
.color1 {
stop-color: green
}
.color2 {
stop-color: yellow
}
#logo1 {
fill: url(#g1)
}
#logo2 {
fill: url(#g2)
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="0" height="0">
<linearGradient id="g1">
<stop offset="0" class="color1" />
<stop offset="1" class="color2" />
</linearGradient>
<radialGradient id="g2">
<stop offset="0" class="color1" />
<stop offset="1" class="color2" />
</radialGradient>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<circle id="logo1" cx="50" cy="50" r="45" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<circle id="logo2" cx="50" cy="50" r="45" />
</svg>

Related

In an SVG, can you reuse a common linearGradient but change the colors from CSS?

In an SVG, can you reuse a common linearGradient but change the colors from CSS?
I have the following HTML:
<svg viewBox="0 0 240 240" xmlns="http://www.w3.org/2000/svg" width="240" height="240">
<defs>
<linearGradient id="sharedGradient" class="grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="var(--color-top)" />
<stop offset="100%" stop-color="var(--color-bot)" />
</linearGradient>
</defs>
<g transform="translate(0, 0)">
<rect class="node" width="100" height="100" x="0" y="0"></rect>
</g>
<g transform="translate(120, 0)">
<rect class="node green" width="100" height="100" x="0" y="0"></rect>
</g>
</svg>
...and the following CSS:
.node {
fill: url(#sharedGradient) #00FF00;
}
#sharedGradient {
--color-top: #f12c06;
--color-bot: #faed34;
}
.green #sharedGradient {
--color-top: #00ff00;
--color-bot: #00dd00;
}
But I can't find a way to alter the color stops of the gradient without duplicating the whole tag in the SVG.
Like #Kaiido mentioned, the linearGradient just needs to be in the svg part that is being reused via <use href="..." />, then in Firefox that can be styled with css-variables. In chrome only the default values will be shown.
#svg1 {
stroke: url(#gradient);
}
#svg2 {
stroke: url(#gradient);
--color-top: blue;
--color-bot: red;
}
#svg3 {
stroke: url(#cantBeStyled); // but reused
--color-top: violet;
--color-bot: indigo;
}
<html>
<div>
<svg id="svg1">
<defs>
<linearGradient id="cantBeStyled" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="var(--color-top, green)" />
<stop offset="100%" stop-color="var(--color-bot, yellow)" />
</linearGradient>
</defs>
<g id="toReuse">
<linearGradient id="gradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="var(--color-top, green)" />
<stop offset="100%" stop-color="var(--color-bot, yellow)" />
</linearGradient>
<rect width="100" height="100" x="0" y="0" stroke-width="20"></rect>
</g>
</svg>
</div>
<div>CSS-variables work in Firefox, in chrome all gradients are green-yellow as defined as defaults in the svg</div>
<div>
can be styled via css variables
<svg id="svg2">
<use href="#toReuse"></use>
</svg>
</div><br /><br/><br/>
<div>
can't be styled
<svg id="svg3">
<use href="#toReuse"></use>
</svg>
</div>
</html>

How to style SVG <linearGradient> with Tailwind CSS when using `fill="url(#a)"`?

I have seen #adamwathan's live streams & he does className="w-5 h-5 text-white" fill="currentColor" to style an SVG through Tailwind.
How can I do the same for linearGradient?
I have the following SVG:
import React from 'react'
export const LinearGradient = () => (
<svg className="w-5 h-5" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient x1="50%" y1="92.034%" x2="50%" y2="7.2%" id="a">
<stop offset="0%" />
<stop stopOpacity="0" offset="100%" />
</linearGradient>
</defs>
<circle
className="text-white"
stroke="currentColor"
fill="url(#a)"
cx="8.5"
cy="8.5"
r="6"
fillRule="evenodd"
fillOpacity=".8"
/>
</svg>
)
How do I style linearGradient in SVG that uses fill="url(#a)" perfectly? I can't change fill="currentColor" as it will lose reference to id="a".
The original SVG is at https://www.sketch.com/images/icons/mac/monochrome/17x17/circle.gradient.linear.svg
Any solutions?
You can also create variables from your tailwind.config.js that you can use in your SVG.
Here is an example of how to do it inside a Laravel 8 project.
tailwind.config.js
const colors = require('tailwindcss/colors');
module.exports = {
theme: {
colors: {
blue: {
300: colors.blue[300],
500: colors.blue[500],
},
...
resources/css/variables.css
:root {
--color-blue-300: theme('colors.blue.300');
--color-blue-500: theme('colors.blue.500');
}
resources/css/app.css
#import './variables.css';
#import 'tailwindcss/base';
...
resources/views/svg/my-svg.blade.php
...
<defs>
<linearGradient id="grad1" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:var(--color-blue-300);" />
<stop offset="100%" style="stop-color:var(--color-blue-500);" />
</linearGradient>
</defs>
...
<path style="fill: url(#grad1);" ...
Then, i'm using in another view (ex: my-layout.blade.php) #include("svg.my-svg").
Using this instead of <img src="my-svg.svg"... allow tailwind's classes to impact the svg.
If you really want to use <img>, a concept is to use controller to build your svg and return a view with response(..., 200)->header('Content-Type', 'image/svg+xml');. I did something like that where i set the color in the url <img src="my-svg.svg?fill=blue-500"... (and it work successfully with tinyMCE 6 which disallow the usage of svg)
To style the linearGradient colors you can use the stop-color attribute on the <stop> elements.
<link href="https://unpkg.com/tailwindcss#^2/dist/tailwind.min.css" rel="stylesheet">
<svg class="w-32 h-32 text-blue-500" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient x1="50%" y1="92.034%" x2="50%" y2="7.2%" id="a">
<stop offset="0%" stop-color="currentColor" />
<stop stop-opacity="0" offset="100%" stop-color="white" />
</linearGradient>
</defs>
<circle stroke="currentColor" fill="url(#a)" cx="8.5" cy="8.5" r="6" fill-rule="evenodd" fill-opacity=".8" />
</svg>

Cannot display linear gradient as a background image on a html page

<svg version="1.1" xmlns="http://w3.org/2000/svg">
<title> Background </title>
<text>
<LinearGradient id="g" x1="200%" x2="0%" y1="50%" y2="0%">
<stop style = "stop-color: green;" offset="0"/>
<stop style = "stop-color: white;" offset="1"/>
</LinearGradient>
</text>
<rect style = "fill: url(#g);" width = "100%" height = "100%"/>
</svg>
The output of this code is either broken image, or the Title "Background" and I do not see what's wrong with it.
You've two issues which affect standalone SVG only
the SVG namespace is incorrect so the file is not recognised as an SVG file. You're missing www from the namespace.
standalone SVG files are case sensitive so we need to write linearGradient
And this one is a bug even when you embed SVG in html.
you can't make a linearGradient the child of a <text> tag. We can use <defs> instead. In theory we could omit the <defs> tag, although I think Safari isn't keen on that.
which leaves us with this...
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<title> Background </title>
<defs>
<linearGradient id="g" x1="200%" x2="0%" y1="50%" y2="0%">
<stop style = "stop-color: green;" offset="0"/>
<stop style = "stop-color: white;" offset="1"/>
</linearGradient>
</defs>
<rect style = "fill: url(#g);" width = "100%" height = "100%"/>
</svg>
You should use defs for the gradient. You may also consider viewbox and width/height:
<svg version="1.1" xmlns="http://w3.org/2000/svg" viewBox="0 0 200 100" width="200">
<title> Background </title>
<defs>
<LinearGradient id="g" x1="200%" x2="0%" y1="50%" y2="0%">
<stop style = "stop-color: green;" offset="0"/>
<stop style = "stop-color: white;" offset="1"/>
</LinearGradient>
</defs>
<rect fill="url(#g)" x="0" y="0" width="200" height="100" />
</svg>

SVG - Filling Rectangle with Jet Colour Scheme

What is the correct way to fill an SVG rectangle with jet colour scheme? Using multiple stops in linearGradient does not seem to work.
Edit, I am trying to fill the a rectangle with one of the following colour gradient.
I edited the MDN code with a rainbow example
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Gradients -->
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="#d30000"/>
<stop offset="30%" stop-color="#ffff05"/>
<stop offset="50%" stop-color="#05ff05"/>
<stop offset="70%" stop-color="#05ffff"/>
<stop offset="100%" stop-color="#041ae0"/>
</linearGradient>
</defs>
<rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>
</svg>
in a fiddle: https://jsfiddle.net/9bmvr5hd/
The BbwrR gradient is the example used in Mozilla's SVG - Gradients documentation:
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="Gradient1">
<stop class="stop1" offset="25%"/>
<stop class="stop2" offset="50%"/>
<stop class="stop3" offset="75%"/>
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="25%" stop-color="blue"/>
<stop offset="50%" stop-color="black" stop-opacity="0"/>
<stop offset="75%" stop-color="red"/>
</linearGradient>
<style type="text/css"><![CDATA[
#rect1 { fill: url(#Gradient1); }
.stop1 { stop-color: blue; }
.stop2 { stop-color: black; stop-opacity: 0; }
.stop3 { stop-color: red; }
]]></style>
</defs>
<rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>
</svg>
I swapped the location of the red and blue and adjusted the offset percentages to try to make it look more like your image. You should be able to just change the colors and add/remove stops for the others.

CSS background image not positioning bottom

I'm having an odd issue happen when trying to position an SVG at the bottom of a div:
http://jsfiddle.net/GsPhA/2/
The svg source is listed below:
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad" x1="0" y1="0" x2="100%" y2="0">
<stop offset="0" stop-color="#FFF" />
<stop offset="0.1" stop-color="#FFF" />
<stop offset="0.5" stop-color="#B1B1B1" />
<stop offset="0.9" stop-color="#FFF" />
<stop offset="1" stop-color="#FFF" />
</linearGradient>
</defs>
<rect x="0" y="0" width="100%" height="1px" style="fill:url(#grad)" />
</svg>
How can I get the svg to appear below the text (like a border-bottom)?
I'm not entirely fussed about earlier browsers, if it requires CSS 3 properties I'm happy!
EDIT: If there is no better way than absolute positioning, I will just add another div below to provide the effect.
EDIT 2: I'm not sure what I need to do differently with SVG, but positioning bottom with PNG works just fine: http://jsfiddle.net/YXRQX/1/
Is there anything I need to specify in the SVG code so it works properly?
EDIT 3: Final working jsFiddle here: http://jsfiddle.net/GsPhA/4/ Thank you To Ryan for the pointer!
Done it! Thanks to Ryan's pointer, I've added the background-size css property to fix the size to 1px high:
.ucp-controls {
text-align: center;
margin-top: 10px;
padding-bottom: 2px;
margin-bottom: 5px;
color: #242424;
cursor: default;
background: url('http://priddle.serveblog.net/sums2/images/header/line.png') bottom no-repeat;
background-size: 100% 1px; // The key line; preserves the width but locks the height.
font-family: Arial;
}​
In the end, the SVG was resizing itself based on the size of the container it was being the background for.
As long as both are in the same container, the text should go above the SVG object like below:
<center>
<p>Sample Text Here</p>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad" x1="0" y1="0" x2="100%" y2="0">
<stop offset="0" stop-color="#FFF" />
<stop offset="0.1" stop-color="#FFF" />
<stop offset="0.5" stop-color="#B1B1B1" />
<stop offset="0.9" stop-color="#FFF" />
<stop offset="1" stop-color="#FFF" />
</linearGradient>
</defs>
<rect x="0" y="0" width="100%" height="1px" style="fill:url(#grad)" />
</svg>
</center>