That's just a browser problem: for such static graphics it shouldn't matter what the original image format is.
The browser will generate an internal bitmap for each decoded PNG image, and uses that for blitting/compositing. Any decent browser ought do the same for SVG icons as well (and just invalidate the bitmap when the SVG image size/rotation or page zooming changes). When compared to blitting, stroking and filling paths is expensive and so is PNG decoding.
Of course, SVG can be rotated and scaled and animated nicely, unlike PNG. That will obviously be slower if done every frame. But this isn't the case and shouldn't be the case for such static icons.
(Of course, the current state of affairs probably is as described on the demo page. But it doesn't need to be.)
That works for the sprite example, but it doesn't generalize to all SVGs.
The problem is SVG filters let you do some pretty cool compositing stuff, but you can't necessarily generalize those effects in a static image. For instance, you could blur elements on the page using an SVG blur filter overlayed over your html elements, but if you're just blitting from a static buffer (like with a PNG), it's going to be wrong, so now you're not just paying attention to if the SVG changes, you also have to pay attention to if anything underneath it or around it changed. It's not an impossible problem, but I think you could still call a browser decent if it doesn't bother with that sort of specialized optimization.
Considering the vast majority of our time behind the computer is spent with software that uses 2D graphics, it is kind of ridiculous that we still don't properly exploit our graphics hardware for vector graphics.
Luckily the hardware vendors are already working on fixing this. Here's an example of a particularly problematic scene rendered using NVIDIA's GPU-Accelerated Path Rendering, compared to Skia, Cairo, QT and Direct2D:
(On a sidenote, I guess this is why IE10 is often faster at rendering SVGs than the other browsers: it uses Direct2D, whereas Firefox and Chrome use Skia).
Using graphics hardware should be more energy-efficient, so maybe we will finally see a change because of mobile devices with HD screens.
Just to throw this in: my iOS project Ejecta[1] also does all the Vector drawing on the GPU using OpenGL ES2. It's not as advanced as NVidia's implementation (e.g. Ejecta computes all bezier points on the CPU and just draws on the GPU), but it's still much faster than what Apple is doing in CoreGraphics.
> (On a sidenote, I guess this is why IE10 is often faster at rendering SVGs than the other browsers: it uses Direct2D, whereas Firefox and Chrome use Skia).
I think Firefox on Windows uses Direct2D, at least for Canvas, not sure if for img tags.
Is Safari/native WebKit hooking straight up to Core Animation on OS X and iOS? I know when the Windows version was still around its WebKit was using Direct2D, even before IE did. I wonder what that would look like in the comparison.
The hard bit isn't the drawing of the vectors - it's the conversion from vectors to triangles (triangulation) it's non-trivial and can be slow for complex (and complexly filled shapes).
This is the big reason we had to write a pixmap caching layer for icons/Plasma themes/etc. in KDE.
GTK+ goes one better, and they compile an entire icon theme into a single mmap-able file with the data in a static GdkPixbuf format. Sadly I'm not sure how to map that to a QImage in general, otherwise I would have adapted that theme cache (where present) into KDE.
Sprites are a dirty hack that works around the fact that HTTP 1.0 only allows one asset to be returned per request. Using CSS background-images to represent content is semantically gross.
If you wanted to the same advantages with SVG, you shouldn't be using CSS sprites; you should take advantage of the fact that SVG is a text-based format and concatenate them all together. Then, you can use some really simple JavaScript to insert each child SVG into the correct place in the DOM.
The ideal way to handle this would look like this:
<img src = "icons.svg#map" />
where map.svg was the original file on the developer's machine. A grunt task could concatenate all the SVGs in a particular folder together and give them IDs according to their file names. In the client's browser, a JS prollyfill would iterate over all the img tags where src ends in a hash and replaces them with the child SVG of that ID.
Just as the prevalence of $$ inspired querySelectorAll, an SVG-optimized spriting system could inspire browser vendors to properly handle hashes in src attributes. and the need for the prollyfill (or the ugliness of CSS spriting) would fade over time.
How would you make HTTP better? How could you get it to send multiple files per request, because, while a little weird in some ways. HTTP is really quite well designed, there isn't really a good way to send multiple files with one request, unless you want to mage HTTP kinda hacky.
Sorry, I've had to write an HTTP compliant server recently, and I don't think there's any good way to send multiple files without completely redesigning the protocol, and even doing that, I don't think there's a good way to do it. Plus, keeping requests atomic makes more sense than bungling then together.
I know the main point of your comment wasn't too make HTTP better, just that sprites are, in your opinion, a bad hack, but your implying that HTTP is bad. Also, and this is just nitpicking, everyone uses 1.1, which has persistent connections in the spec, which help negate some if the computing cost for sending multiple files.
Updating scrollTop is a pretty slow way to scroll on some browsers. Have you tried animating `transform`? That gets you hardware acceleration on webkit at least
Additionally, jQuery is not known for its performance, especially regarding animations.
For me, on Chrome Canary, the animation "chugs" every 20-30 frames (from 60 fps to a frame that takes 200ms). It's almost entirely in rendering, and it's immediately following a jQuery callback. It only happens when scrolling down. I'd like to see this done with a very simplistic requestAnimationFrame tweener to compare the same type of animation against something that is doing nothing else but computing a new scrollTop and setting it. I have a strong feeling, in Chrome at least, that the problem here is jQuery, not SVG perf.
Additionally, for other browsers, I'd like to see this tested with icon fonts.
Adding #container {-webkit-transform: translateZ(0);} puts the whole div as a texture onto the GPU as a composited layer. This improves scrolling massively, but interestingly SVG still has a little bit more jank than the PNG version.
See http://jankfree.org
It probably would also help if this were done as pure inline SVG instead of CSS background images. It doesn't surprise me that adding a ton of SVG background images to the page would cause some browsers to behave badly.
There are icons in the SVG sprite set which consist of numerous clip paths, which could be the root cause of the performance issue. If you load the sprite in Chrome (http://adrianosmond.com/images/sprite.svg) and inspect the element immediately above the facebook logo you will see an example of this. That aforementioned icon could possibly have been created using a single line path and gradient fill (I've not edited SVG files for a while).
You cannot have a gradient following a curve. At least not yet. You could probably use some filter trickery and thus create a fill where a gradient follows the path but I bet that's much worse than a few dozen paths.
What's strange is that scrolling SVG can be quite smooth in browsers, at least in Chrome. The map library Leaflet, or instance, makes a point of panning the map with -webkit-transform: translate3d() and it animates very smoothly. I wonder why scrolling the whole window like this is worse?
SVG is scalable, if you have a vector-graphic that is a clear advantage. For pixel-graphics PNG is better. A downside is, that the Internet Explorer supports SVG only with the coming version 9 (before with plugin). Mobile browsers may also have limited support for SVG.
I would say PNG simply for the fact it seems to be a more accepted format than SVG.
Just as an aside Firefox has a bug which means it blurs SVGs that are being displayed at a different background-size than 100% 100% (or equivalent in other units), if the width and height set in the SVG is smaller than the size at which it is displayed as a background image. This happens because Firefox apparently (only for background images) renders the SVG at it's size settings and then scales it for use in the page.
This is the same type of issue as discussed in the example - it's a bug in the browser not a problem with SVGs in general.
I'm not sure if this is surprising. Even the proprietary Macromedia Flash showed us in the late 90s that vector graphics are more computationally expensive than raster equivalents.
SVG is nice because it gives us additional flexibility -- it's resolution independent (so you don't need to redraw your image by hand when higher-DPI displays come out) and allows for animation[0]. But if you don't need those things (and you probably don't for your sprites) then they'll just slow you down.
Is it not feasible to load a vector graphic into a raster equivalent on first load? Startup time would, predictably, be slower, but just moving something around the screen would then be equivalent. (Obviously, some actions could trigger a redraw of the vectors, but I would think this would actually be a limited set of interactions.)
Those things shouldn't slow you down at all if you aren't using them: this is a browser optimization issue. The browser knows that the SVG has not changed in any way, and can with absolute accuracy discern that it can simple blit the pre-rendered raster.
Browsers have not optimized SVG at all, painfully clear when the simplest retained dynamic SVG graphic is magnitudes slower than building entirely new framebuffers from scratch for every frame, ala canvas. It is trivial to see that the former should see dramatic optimizations that make it a significant winner, but in actual practice that just hasn't happened.
So it's a classic chicken/egg thing. No browser maker does anything to optimize SVG because few use it. Few use it because it's so unoptimized.
The findings of this post remain the same in either case, and is completely correct, but it shouldn't be this way. It isn't right that this test favors PNG.
This is not true or at least it is more complicated than you suggest.
The computationally complex bit is triangulating the image. If you can do that the graphics card will have an easier time drawing the vectors than it will shuffling all those textures around. In fact you could send all your vectors in one draw call.
What we need is browsers caching SVGs as geometry not pixels.
I will note that Flash also had some really terrible redraw logic; if you had a largely static image with something animating in the upper left and lower right corners, the dirty rectangle would cover the whole thing.
I know EaselJS library has capability to cache the bitmap representation of SVG, so if you do not change stroke settings, paths, etc. it works really fast. When you change, you need to update the cache manually. This works for HTML5 Canvas, but they also have DOMElement class which is still experimental so YMMV. Or maybe there is some other lib. that does specifically for DOM.
Huh. Interesting. Activity Monitor gives me some weird numbers for Safari's performance as I watch this on my
dual i5 Macbook Air.
When scrolling the PNGs up and down, Safari oscillates between 64 to 94% CPU usage.
When scrolling the SVGs up and down, it goes between 36-54% CPU. Very very strange. I wonder if it has something to do with the fact that the SVG is dropping about a zillion frames.
Are you looking at just the Safari process or also the Safari Web Content process and the parts of the work Safari offloads to WindowServer and whatnot?
So this is an interesting case for animation, but turn off the javascript and try real-world (manual) scrolling -- both pngs and svg perform about the same for me in Chrome (osx).
I'm not sure there's much of a takeaway here unless you're trying to animate the page scrolling of a full page of sprites (i.e., the example proves itself, but not much else).
What is it? What shoud I see? What does it demonstrate?
I followed the link which opens an html/css/js editor in which I cannot do anything. After some search I saw a white page with a list of icon a radio button switching from png to svg and some text about framerate where I do not see any animation or any difference between the two!
I'd be interested to see you icon-fonts perform in the test. (knowing that it is not really the same thing as you only have monochrome icons in fonts, unless you layer them)
[+] [-] yason|12 years ago|reply
The browser will generate an internal bitmap for each decoded PNG image, and uses that for blitting/compositing. Any decent browser ought do the same for SVG icons as well (and just invalidate the bitmap when the SVG image size/rotation or page zooming changes). When compared to blitting, stroking and filling paths is expensive and so is PNG decoding.
Of course, SVG can be rotated and scaled and animated nicely, unlike PNG. That will obviously be slower if done every frame. But this isn't the case and shouldn't be the case for such static icons.
(Of course, the current state of affairs probably is as described on the demo page. But it doesn't need to be.)
[+] [-] overgard|12 years ago|reply
The problem is SVG filters let you do some pretty cool compositing stuff, but you can't necessarily generalize those effects in a static image. For instance, you could blur elements on the page using an SVG blur filter overlayed over your html elements, but if you're just blitting from a static buffer (like with a PNG), it's going to be wrong, so now you're not just paying attention to if the SVG changes, you also have to pay attention to if anything underneath it or around it changed. It's not an impossible problem, but I think you could still call a browser decent if it doesn't bother with that sort of specialized optimization.
See: http://www.w3.org/TR/SVG/filters.html#AccessingBackgroundIma...
[+] [-] sageikosa|12 years ago|reply
[+] [-] sambeau|12 years ago|reply
[+] [-] Nekorosu|12 years ago|reply
[+] [-] vanderZwan|12 years ago|reply
Luckily the hardware vendors are already working on fixing this. Here's an example of a particularly problematic scene rendered using NVIDIA's GPU-Accelerated Path Rendering, compared to Skia, Cairo, QT and Direct2D:
https://www.youtube.com/watch?feature=player_detailpage&v=zI...
NVidia: ~220 fps
Skia: 6 fps
Cairo: 29 fps
QT: 0.3 fps
Direct2D: 48 fps
(On a sidenote, I guess this is why IE10 is often faster at rendering SVGs than the other browsers: it uses Direct2D, whereas Firefox and Chrome use Skia).
Using graphics hardware should be more energy-efficient, so maybe we will finally see a change because of mobile devices with HD screens.
[+] [-] phoboslab|12 years ago|reply
[1] http://impactjs.com/ejecta
[+] [-] azakai|12 years ago|reply
I think Firefox on Windows uses Direct2D, at least for Canvas, not sure if for img tags.
[+] [-] zw|12 years ago|reply
[+] [-] sambeau|12 years ago|reply
[+] [-] mpyne|12 years ago|reply
GTK+ goes one better, and they compile an entire icon theme into a single mmap-able file with the data in a static GdkPixbuf format. Sadly I'm not sure how to map that to a QImage in general, otherwise I would have adapted that theme cache (where present) into KDE.
[+] [-] bsimpson|12 years ago|reply
If you wanted to the same advantages with SVG, you shouldn't be using CSS sprites; you should take advantage of the fact that SVG is a text-based format and concatenate them all together. Then, you can use some really simple JavaScript to insert each child SVG into the correct place in the DOM.
The ideal way to handle this would look like this:
where map.svg was the original file on the developer's machine. A grunt task could concatenate all the SVGs in a particular folder together and give them IDs according to their file names. In the client's browser, a JS prollyfill would iterate over all the img tags where src ends in a hash and replaces them with the child SVG of that ID.Just as the prevalence of $$ inspired querySelectorAll, an SVG-optimized spriting system could inspire browser vendors to properly handle hashes in src attributes. and the need for the prollyfill (or the ugliness of CSS spriting) would fade over time.
[+] [-] dkuntz2|12 years ago|reply
Sorry, I've had to write an HTTP compliant server recently, and I don't think there's any good way to send multiple files without completely redesigning the protocol, and even doing that, I don't think there's a good way to do it. Plus, keeping requests atomic makes more sense than bungling then together.
I know the main point of your comment wasn't too make HTTP better, just that sprites are, in your opinion, a bad hack, but your implying that HTTP is bad. Also, and this is just nitpicking, everyone uses 1.1, which has persistent connections in the spec, which help negate some if the computing cost for sending multiple files.
[+] [-] tpenzer|12 years ago|reply
http://thepenzone.com/svg-image/
[+] [-] anondesign|12 years ago|reply
[+] [-] nickporter|12 years ago|reply
I can't believe nobody else mentioned this.
[+] [-] just2n|12 years ago|reply
For me, on Chrome Canary, the animation "chugs" every 20-30 frames (from 60 fps to a frame that takes 200ms). It's almost entirely in rendering, and it's immediately following a jQuery callback. It only happens when scrolling down. I'd like to see this done with a very simplistic requestAnimationFrame tweener to compare the same type of animation against something that is doing nothing else but computing a new scrollTop and setting it. I have a strong feeling, in Chrome at least, that the problem here is jQuery, not SVG perf.
Additionally, for other browsers, I'd like to see this tested with icon fonts.
[+] [-] kevingadd|12 years ago|reply
[+] [-] sahaskatta|12 years ago|reply
[+] [-] rbirkby|12 years ago|reply
[+] [-] rbirkby|12 years ago|reply
[+] [-] leptons|12 years ago|reply
[+] [-] gales|12 years ago|reply
[+] [-] ygra|12 years ago|reply
[+] [-] NelsonMinar|12 years ago|reply
[+] [-] kllrnohj|12 years ago|reply
Changing a translate3d does not repaint the content, it simply translates a GPU texture (damn near free)
Sadly desktop browsers haven't caught up to their mobile equivalents yet and still have brain dead scrolling.
[+] [-] twistedpair|12 years ago|reply
[+] [-] zopticity|12 years ago|reply
I would say PNG simply for the fact it seems to be a more accepted format than SVG.
[+] [-] sp332|12 years ago|reply
[+] [-] twistedpair|12 years ago|reply
Webkit acceleration is getting much better, and for those ancient IE browsers, check out RaphaelJs which translates them into MS approved VML.
[+] [-] ysvg|12 years ago|reply
See: http://hofmannsven.com/2013/laboratory/svg-stacking/
[+] [-] andy_ppp|12 years ago|reply
This is the same type of issue as discussed in the example - it's a bug in the browser not a problem with SVGs in general.
See the related bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=600207
[+] [-] cbhl|12 years ago|reply
SVG is nice because it gives us additional flexibility -- it's resolution independent (so you don't need to redraw your image by hand when higher-DPI displays come out) and allows for animation[0]. But if you don't need those things (and you probably don't for your sprites) then they'll just slow you down.
[0] http://en.wikipedia.org/wiki/SVG_animation
[+] [-] taeric|12 years ago|reply
[+] [-] corresation|12 years ago|reply
Browsers have not optimized SVG at all, painfully clear when the simplest retained dynamic SVG graphic is magnitudes slower than building entirely new framebuffers from scratch for every frame, ala canvas. It is trivial to see that the former should see dramatic optimizations that make it a significant winner, but in actual practice that just hasn't happened.
So it's a classic chicken/egg thing. No browser maker does anything to optimize SVG because few use it. Few use it because it's so unoptimized.
The findings of this post remain the same in either case, and is completely correct, but it shouldn't be this way. It isn't right that this test favors PNG.
[+] [-] sambeau|12 years ago|reply
The computationally complex bit is triangulating the image. If you can do that the graphics card will have an easier time drawing the vectors than it will shuffling all those textures around. In fact you could send all your vectors in one draw call.
What we need is browsers caching SVGs as geometry not pixels.
[+] [-] egypturnash|12 years ago|reply
[+] [-] babuskov|12 years ago|reply
[+] [-] egypturnash|12 years ago|reply
When scrolling the PNGs up and down, Safari oscillates between 64 to 94% CPU usage.
When scrolling the SVGs up and down, it goes between 36-54% CPU. Very very strange. I wonder if it has something to do with the fact that the SVG is dropping about a zillion frames.
[+] [-] bzbarsky|12 years ago|reply
[+] [-] bitsm|12 years ago|reply
I'm not sure there's much of a takeaway here unless you're trying to animate the page scrolling of a full page of sprites (i.e., the example proves itself, but not much else).
[+] [-] ernesth|12 years ago|reply
I followed the link which opens an html/css/js editor in which I cannot do anything. After some search I saw a white page with a list of icon a radio button switching from png to svg and some text about framerate where I do not see any animation or any difference between the two!
[+] [-] cies|12 years ago|reply
[+] [-] tome|12 years ago|reply
[+] [-] dochtman|12 years ago|reply
[+] [-] mnot|12 years ago|reply