I'm attempting to move from font icons (icomoon.io) to SVG sprites. Is it possible to use SVG sprites without needing < svg > markup for each icon instance?
What I really liked about the font icons was that I didn't have to clutter my HTML with any additional elements to get the icon to display. I usually just targeted a simple class on whatever element I wanted the icon to display and then used pseudo selectors to display the icon, e.g.:
<h1 class="news">News</h1>
h1.user:before {
font-family: 'icons';
content: '\news';
}
That made a lot of sense to me, and all of my icons were easily managed almost completely in CSS. I rarely had to touch my HTML as long as my markup contained appropriate classes.
I've since switched my build system to Grunt and thought I'd give SVG sprites a try. Almost every1 article2 I3 can4 find5 on the subject says you need to add an additional SVG element to your markup wherever you want each instance to display, e.g.:
<h1>
<svg class="icon">
<use xlink:href="#icon-news">
</svg>
News
</h1>
That seems like a step backwards to me, at least in the management of markup. To me, an icon is usually presentation that should be separate from document structure. Are we doing it this way simply because of the state of SVG support in browsers?
Ideally, I'd love to be able to do something like this:
<h1 class="news">News</h1>
h1.news:before {
display: inline-block;
width: px;
height: px;
background: url(icons.svg#news) no-repeat;
}
This post seems to be closer to what I'm looking for, but I'm not sure of browser support and how to do it automatically in a build system like Grunt.
SVGs can be loaded as files exactly the same way as other images using <img> tags or CSS background, and can be used as sprites exactly the same way too. The only difference is that you have to specify the size you want it (because it's scalable, so the browser doesn't automatically know how big it is like it does with PNGs).
Depending on how you want to use the image, loading them this way may or may not be suitable as some SVG features aren't available, but it can be done.
Related
I have a number of different SVGs to include in my project (Angular 10).
Some of them are used multiple times with different sizes and fill colors etc.
I am trying to find a way to reference them in my html code and have access to via styling:
CSS:
.svg {
fill: red;
}
Referencing:
<svg>
<use></use>
</svg>
<object></object>
<img></img>
<embed></embed>
As yet, I have not been able to find a solution that allows me to reference them but also have the ability to access the fill property in the SVG itself as i can when adding inline.
Inline:
<svg>
<path>
</path>
</svg>
Adding them inline is going to be messy.
How is this usually handled?
Your help is appreciated!
You can't. CSS does not apply across document boundaries. If the CSS rules are in the HTML (or imported into the HTML via <link>) then it cannot affect the content of external files.
One solution people have used in the past is to use a bit of Javascript to inline SVG files at runtime.
Otherwise, you will need to put the CSS in the external SVG itself.
Please have a look at this Pen:
http://codepen.io/troywarr/pen/VYmbaa
What I'm doing here is:
defining an SVG symbol (<symbol>)
defining an SVG linear gradient (<linearGradient>)
using the <use> element to reference the SVG symbol I've created
in the CSS, defining two classes:
external, which references the linear gradient defined in this external .svg file (right click and view source)
internal, which references the linear gradient defined in the local HTML (which is, I believe, effectively identical to the one in the external file)
Because I've applied the internal class to the <svg> element at the bottom of the HTML example, the gradient is applied, rendering a blue gradient checkmark. That's what I'm after.
But, if you switch the internal class to external in the HTML example, the checkmark is no longer visible:
http://codepen.io/troywarr/pen/vEymKX
When I watch Chrome Inspector's "Network" tab, I don't see the browser trying to load the SVG file at all. Is there a problem with my syntax, or is something else going on here?
It at least looks like I'm doing this right, based on a few references I've found:
http://www.w3.org/TR/SVG/painting.html#SpecifyingPaint
http://www.w3.org/TR/SVG/linking.html#IRIReference
https://stackoverflow.com/a/7118142/167911
But, nothing I've tried so far has allowed me to reference a linear gradient defined in an external .svg file.
Thanks for any help!
After more research, it looks like this is a browser support issue. See:
https://code.google.com/p/chromium/issues/detail?id=109212
https://bugs.webkit.org/show_bug.cgi?id=105904
Sadly, I'd come across this question before posting mine, and had thought that surely, in 5-1/2 years, browser support would have caught up - but that doesn't appear to be the case.
As of 2015, apparently Firefox and Opera are the only two browsers to support this in any substantial way.
Back to the drawing board...
You can use svg4everybody with polyfill: true option, it will insert all external symbols instead of use tags. But it will cause the second svg loading.
So you can download svg using an ajax request and then insert it on the page hiding with the styles.
<script>var ajax=new XMLHttpRequest;ajax.open("GET","/img/svg-sprite.svg",!0),ajax.send(),ajax.onload=function(a){var b=document.createElement("div");b.classList.add("hidden"),b.innerHTML=ajax.responseText,document.body.insertBefore(b,document.body.childNodes[0])};</script>
In this case:
/img/svg-sprite.svg — is your svg path.
.hidden class styles:
.hidden {
position: absolute !important;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
}
And your code might look like this:
<svg><use xlink:href="#logo"></use></svg>
I defined CSS transition rules in my svg. It's something like:
#mark #bg {
transition: fill 200ms;
fill: #245575;
}
#mark:hover #bg {
fill: #ff5c26;
}
When I drag it into browser's blank page and test it, the transition works fine. But if I embed the svg into my website using <img src="images/mark.svg" alt="">, the transition doesn't work.
Did I miss something?
Images either via <img> tags of via the CSS background-image image property cannot be interactive and have other restrictions in order to maintain user's privacy and security.
If you ask yourself "could I do this if the image was a .png or a .gif?" then you'll be on the right lines. Browsers have deliberately chosen to keep to the same mental model for SVG files so that the capability of images is easy to understand.
If you want transitions to work you'll need to use an <object> or <iframe> tag or embed the SVG inline in the html document.
I'd like to create a Node.js app that allows users to combine a bunch of SVG icons into a custom web-font icon set. The only similar project I've found is this site which looks interesting but is pretty buggy.
Eventually I'd like this app to also output all the various cross-browser font files and the CSS to use these icons on a page using best practices. So the overal goal is to create an SVG icon framework.
But the first thing I want to get working is combining multiple SVG icons into a SVG font file. Must be possible if the above mentioned site is doing it but I'm having trouble finding any good info.
Could anyone point me in the right direction? Thanks!
Edit: I came across this service which looks very similar to my goal although I don't want to host the fonts and I'd like my service to be free (and possibly open-source as well).
Kind of late, but if anyone else will need it, i think this will do: https://github.com/sapegin/grunt-webfont
Like many of my big ideas, someone thought of it first :)
For anyone who may come across this, check out Keyamoon's font generator tool.
If you want to automate things there is an NPM package called svg-font-create.
Glyphter.com handles multi-path icons so that might be a good resource for you as well.
You may try svg-join for combine multiple SVG in one symbol collection.
This tool create two files for you.
The first is "svg-bundle.svg":
<svg ...>
<symbol id="svg1" ...>
<symbol id="svg2" ...>
</svg>
Every symbol is your separate SVG file.
The last one is "svg-bundle.css":
.svg_svg1,
.svg_svg2 {
width: 20px; // for example
height: 20px;
}
Now you may use it in your html:
<link rel="stylesheet" type="text/css" href="svg-bundle.css" />
...
<svg class="svg_svg1"><use xlink:href="svg-bundle.svg#svg1"></svg>
<svg class="svg_svg2"><use xlink:href="svg-bundle.svg#svg2"></svg>
I'm trying to wrap my head around CSS positioning guidelines. I'm trying to figure out how to make a sticky footer but have it stop being sticky when the main content area can no longer be condensed. An example of what I'm talking about can be found here http://ryanfait.com/sticky-footer/. Can someone explain to me why the footer stops being sticky and particularly what CSS properties cause this to occur? For me, as I look at the CSS it looks like the footer should just stay sticky to the bottom of the browser window always, but this isn't the case here. Why?
Thanks for the help.
Give this one a try.
http://www.cssstickyfooter.com/ (link no longer valid)
It is similar to Ryan's one but, from memory, I think I've had better luck with this (although both are very similar).
You have to declare the footer outside of the wrapper and give some height for footer and margin-top should -(footer-height)px
<div id="wrapper">
---
------
</div>
<div id="footer">
</div>
# wrapper {
width:100%;
height:100%;
}
#footer {
width:100%;
height:25px;
margin:-25px 0px 0px 0px;
background:#ccc;
}
Here's a brief summary of a layout I use fairly consistently as a basis for projects that require a sticky footer. Not sure where I initially got all the code from but it was pieced together over quite a while.
http://jsfiddle.net/biznuge/thbuf/8/
You should be able to see from the fiddle that you require a '#container' element which will wrap the whole of the page. this gives you 100% height (note the hacks for ie present in the css), and allows and child elements of this 'container' element to derive a height, or position relative to it.
Pitfalls of this method are:
You need to provide some padding/margin at the bottom of the '#main'
element so that the footer is displaced further than it naturally
would, so need to know at least a broad range of what your footer
height should be.
IE doesn't seem (<=IE8 not tested 9) to recognize browser resize
events if you only resize the bottom edge of the browser, so in
that particular case the stickiness would fail, until a horizontal
resize was also presented as an event.
if you want a fixed width to the layout you should place this
constraint not on the '#container' element, but on the '#page'
element, and perhaps introduce extra elements beneath '#footer' to
provide any width constraints there.
Good Luck!