Wednesday, October 7th, 2009

View Source Tutorial: Fancy Web Page Using HTML5, CSS, and SVG

Category: HTML, SVG, Tutorial, View Source

I recently ran across a site that made my jaw drop when I realized it’s completely made with HTML5, CSS, and SVG. It’s the site for the GNU Emacs for Mac OS X release:


Who ever knew GNU Emacs could look so sexy? When I think of GNU Emacs I generally imagine Richard Stallman‘s beard rather than the fancy site shown above.


Wow, I’ve got to get that image out of my head :) Moving on.

Here is what is cool about this site: it’s completely using open web technologies to put things together. That’s not just a big image you’re seeing on the site.

Let’s crack this thing open with a View Source tutorial and see what makes it tick so you can apply similar techniques in your own work. View Source is a new series of tutorials where we look at open web technology ‘in the wild’ and break them down step by step so you can learn what they are doing.

First, this is an HTML 5 site with the HTML5 doctype:

  1. < !DOCTYPE html>

Much of the page uses directly embedded SVG into HTML5 to achieve it’s affects, and works in Firefox, Opera, and Webkit based browsers (Safari, Chrome, etc.).

If you do a view source on the page the first thing you will notice is all the text is truly plain text; much of the text on the page is directly in the markup, meaning that search engines will correctly extract this text and index it.

The nice gradient background is done with the following:


First, we define a rectangle to fill the background:

  1. <rect x="0" y="0"
  2.       width="100" height="100"
  3.       fill="url(#background_gradient_black)" />

Notice that we reference a gradient in there with fill="url(#background_gradient_black)". This is defined as follows:

  1. <lineargradient id="background_gradient_black"
  2.                x1="0%" y1="10" x2="0%" y2="90"
  3.                gradientUnits="userSpaceOnUse">
  4.   <stop offset="0%"   stop-color="#000" stop-opacity="1" />
  5.   <stop offset="45%"  stop-color="#444" stop-opacity="1" />
  6.   <stop offset="55%"  stop-color="#444" stop-opacity="1" />
  7.   <stop offset="100%" stop-color="#000" stop-opacity="1" />
  8. </lineargradient>

A few things; notice that we give this gradient an id (‘background_gradient_black’). We can then later use this gradient in other elements, which we do in the background rectangle. This is a sophisticated gradient; we are essentially giving it four different colors as it does it’s drawing (each of these is the ‘stops’ defined above).

To have our rectangle and gradient fill the whole page, everything is nested into an svg element with the following style block, snipped a bit for brevity:

  1. <svg style="width:100%; height:100%; position:fixed; top:0; left:0; z-index:1">

Basically, we have the SVG embedded in our HTML fill up the whole page and ‘pin it’ to the upper left of the page.

Let’s move on to the nice buttons on the page, which when hovered over get a nice blue background:

I really like how these were put together. First, we have a CSS style block in our directly embedded SVG as follows:

  1. a #button {
  2.   fill:url("#button_gradient");
  3.   stroke:grey;
  4. }
  5. a:hover #button {
  6.   fill:url("#active_button_gradient") !important;
  7.   stroke:blue;
  8. }

Our buttons are standard SVG rectangles with hyperlinks around them, hence the ‘a #button’. Each of the buttons on the page have the ID #button and have the style above applied to them (technically they should be using a CSS class instead, so this is a mistake in this example). The buttons have an SVG fill applied to each one, and when the mouse is hovered over the button we end up triggering the ‘a:hover #button’ style rule which changes the fill to a different gradient and changes the stroke outline to blue.

Let’s look at just one of the buttons to get a sense of what the SVG looks like:

  1. <g transform="translate(950,635)" class="small-button">
  2.   <a xlink:href="/about">
  3.     <rect x="2" y="2"
  4.          width="196" height="71"
  5.          rx="15" ry="15"
  6.          stroke-width="2px" id="button"/>
  8.     <text x="100" y="37"
  9.          transform="translate(0,10)"
  10.          font-size="25px" font-weight="bold"
  11.          text-anchor="middle">About</text>
  12.   </a>
  13. </g>

There’s a few things going on here. First we have the group element (‘g’), which acts pretty much just like grouping in Photoshop: you can group things together into a single unit as you work with them, style them, make them interactive, etc. The ‘transform’ attribute is a way to have a nice, simple way to draw things inside the group, and then ‘translate’ everything to where you want them on the page.

Inside the group we see a hyperlink element, just like HTML, but with the entire button inside of it hyperlinked to the ‘about’ page.

Next comes our button’s rectangle. The ‘rx’ and ‘ry’ properties are a way to get rounded corners (Look! Simple rounded corners in HTML!). We then overlay our text ‘About’ on top of the rectangle and make it centered. The CSS we saw above will then work with this button to add the nice gradient backgrounds and the mouse over behavior.

Moving on, check out the Emacs ‘signature’; the Apple logo, and the fancy Mac OS X. These are defined as SVG symbols that can be referenced and moved around the page. Each of them is essentially a symbol with an ID, filled with a bunch of gradients and path statements probably taken from a tool like Inkscape or grabbed from Wikimedia Commons.


Once they are defined elsewhere, they can be referenced using the use tag and each of their IDs (‘#mac-os-x’), have hyperlinks attached to them, and placed on the screen where necessary; finally the whole thing is grouped together with a G tag and translated right into the page where you want it to appear:

  1. <g transform="translate(100,0)">
  2.   <use x="250" y="0" width="500" height="500"
  3.       xlink:href="#mac-os-x" />
  5.   <a xlink:href="">
  6.     <use x="0" y="240" width="300" height="300"
  7.         xlink:href="#emacs" />
  8.   </a>
  10.   <a xlink:href="">
  11.     <use x="700" y="225" width="275" height="275"
  12.         xlink:href="#apple-shiny" />
  13.   </a>
  14. </g>

Next, a subtle shadow is placed on the large text at the top of the screen so it falls on the large X; here’s a screenshot where we zoom in to show the shadow:


This is achieved with an SVG filter. I’m not going to show the source for this, but you can find it by searching the example page for the the element with the ID “shadow”. The cool thing about this is since its just markup so you can learn from it and adapt it for your own needs (remember copyright of course). On the page we apply the shadow as follows using the filter attribute and reference it by name:

  1. <text x="600" y="120"
  2.       font-size="100px"
  3.       text-anchor="middle"
  4.       font-weight="bold"
  5.       fill="white"
  6.       filter="url(#shadow)">Emacs For Mac OS X</text>

Finally, we have the little Pure Emacs! label on the lower-left:


First, the star is just a symbol with an ID again, drawn with a bunch of paths either drawn by hand or grabbed from a clip art library or drawing tool. We use the <use> tags to reference this and orient its size and position. Then, we draw all of our text and group them together, rotating and scaling the entire thing at once to turn it to the side: transform="translate(80,80) rotate(-30) scale(.9)"

  1. <g transform="translate(100,550)">
  2.   <use x="0" y="0" width="150" height="150" xlink:href="#star" />
  3. </g>
  4. <g transform="translate(80,80) rotate(-30) scale(.9)">
  5.   <text x="0" y="-40" font-size="30px" font-weight="bold"
  6.           text-anchor="middle">Pure</text>
  7.   <text x="0" y="-15" font-size="30px" font-weight="bold"
  8.           text-anchor="middle">Emacs!</text>
  9.   <text x="0" y="+10" font-size="20px" font-weight="bold"
  10.            text-anchor="middle">No Extras!</text>
  11.   <text x="0" y="+30" font-size="18px" font-weight="bold"
  12.            text-anchor="middle">No Nonsense!</text>
  13. </g>

Two cool things about all of this; first, on Webkit based browsers all the text is selectable. Also, the page truly scales based on the monitor it’s on. If you are a full page on a 40″ monitor it will scale to the full size and remain legible and beautiful, as well as scale down on the iPhone. That’s cool.

I love this example because it shows a few things. First, that SVG is definitely not dead; this works on every browser but IE — that doesn’t sound like a dead technology to me. Second, this example is much better done with SVG than the Canvas tag. I’m a huge fan of the Canvas tag; in fact I originally liked it much better than SVG when it came out a few years ago. I used to be an SVG-skeptic as well, until I realized making a choice between the two was like being forced to choose as a programmer just Hashtables or Linked Lists; they both are needed. Finally, this sample is in a form that makes it easy for others to learn from this markup to adapt it to their own needs. Have fun!

Posted by Brad Neuberg at 6:30 am

3.5 rating from 42 votes


Comments feed TrackBack URI

The page looks spiffy in Firefox and Chrome, but a little less so in IE. The difference is night and day. These types of differences still make me a little wary of using SVG for commercial sites.

Comment by zgrossbart — October 7, 2009

You can try:

vim rocks!

Comment by totoloco — October 7, 2009

Why embed all svg in the actual html? In todays frontend development best practices we are encouraged to make sprites, set far future expire headers on images etc. Lets say a huge site were about to use svg, facebook for example. If the users where to download the same svg over and over again, wouldnt that increase their bandwidth dramaticly?

Is it possible with html5 to use “external svg” or is it recommended to embedd?

Comment by andriijas — October 7, 2009

Loving the 1990’s fallback page for IE… this is the way the web should be for non-embracing IE

Comment by RoryH — October 7, 2009

@andriijas, probably because if it only going to be used in one page, making multiple requests for different files is a lot slower.

Comment by reaktivo — October 7, 2009

Liking the new feature guys!

Comment by tj111 — October 7, 2009

@RoryH yeah on that emacs site yes but clearly you didnt read my message since i were refering to what if larger sites were to use svg…

Comment by andriijas — October 7, 2009

andriijas, the practical implications of embedding SVG directly in the page (or embedding data: URLs or whatever) depends entirely on your caching scheme. If you set cache headers for your dynamic pages the way you set them for static content (as in, your dynamic content is not updated constantly), then embedding has a performance benefit in that it produces fewer HTTP requests; if not, embedding has a higher cost in that it requires more information down the pipe on each load. Obviously this depends a lot on your content and your caching system generally, and grows more complex the more complex your system grows.

And… Ajaxian site owners, can you guys please find a better CAPTCHA system that doesn’t flag me as “spam” even when I answer the fucking question correctly? It asked me what the X in Ajax stands for, I put “xml” in the field, and my comment was flagged. Whatever heuristics are being used besides the field are obviously too zealous if a post with a correct response, no links and obviously parsable as something other than a stream of keywords and misspellings, from a registered user who doesn’t even have a URL in the profile field…. gets flagged.

I’ve had a lot of problems with this site’s usability, but most I’ve fixed with local CSS modifications; but I can’t fix this locally, and it happens pretty often.

Comment by eyelidlessness — October 7, 2009

@eyelidlessness well if you have a site with 10 pages and all of them uses the same svg elements to build up the site design id say its better to make the user download them only once and cache it in the users browsers to that when he loads the second page he only needs to download the html and the svg is taken from the cache.

Comment by andriijas — October 7, 2009

I agree with @andriijas how do you add a external svg. I know that on Safari you can use img element, but not on Firefox… So how I am supposed to do it?

Comment by jnbdz — October 7, 2009

@jnbdz what about these methodes:

You can even use object with parameters.

Comment by SilentLennie — October 7, 2009

You can simply use the OBJECT tag to embed external SVG if you don’t want it directly in your page.

Comment by Brad Neuberg — October 7, 2009

Hey Brad, thanks for the great new feature!
Could svgweb be used to render the svg content in an IE+flash environment, and if so, how would that work?

Comment by rdza — October 7, 2009

So you guys are saying there’s no way to make an external svg with some gradient and use as a css background on the body on multiple pages?

Or lets say i make a rounded corner box with a gradient background svg, do i really need to include it on all html pages using it instead of using it as css background?! :S

Comment by andriijas — October 8, 2009

@andriijas – there is a way to do this, use CSS background-image using a SVG file. While Opera and Firefox support this, unfortunately Firefox does not yet.

Comment by codedread — October 8, 2009

I’ve rambled a bit on this site about a month ago (although I’ve only published the entry today):

Did you meant “While Opera and Webkit support this”? ;-)

Comment by HelderMagalhaes — October 8, 2009

The way the fallback website is made is not the most optimal, The message “Usually there’s a nifty page here with a big download button. But you are using a browser which doesn’t support SVG and so you get the boring looking page.” is there in the code and can be read by anyone (screen readers, searc engine bots….)

Is there a way in the specification to define alternative content for browsers that do not support SVG? also tab navigation is not really usable (at least in Firefox).

Comment by joaquinWin — October 8, 2009

The site looks GREAT in Firefox. Unfortunately in my Opera 10 on Windows Vista browser, all I get is the gradient background and NOTHING else.

I realise it’s early days but will HTML5 be subject to the same old browser incompatibilities as previous versions I wonder…?

Comment by ginje — October 20, 2009

Leave a comment

You must be logged in to post a comment.