CSS & SVG

With the addition of CSS transitions and transforms, web developers can create interactive content with relatively simple markup. Understanding how to use these features with SVG, which has its own transform and animation systems, can be a little difficult.

For example, let’s take a look at a simple interactive element, which animates its color and rotation when moused over.

Note: The demos use features still under development. They should display fine in the latest versions of Safari, Firefox, Chrome, and Opera, but you may see some issues with IE9.

<svg xmlns="http://www.w3.org/2000/svg">
    <rect x="50" y="50" width="100" height="100"
     rx="20" ry="20" fill="blue">
        <animate attributeName="fill" to="green"
         begin="mouseover" dur="0.5s" fill="freeze" />
        <animate attributeName="fill" to="blue"
         begin="mouseout" dur="0.5s" fill="freeze" />
        <animateTransform attributeName="transform"
         type="rotate" from="0 100 100" to="30 100 100"
         begin="mouseover" end="mouseout" dur="0.5s"
         fill="freeze"/>
        <animateTransform attributeName="transform"
         type="rotate" from="30 100 100" to="0 100 100"
         begin="mouseout" end="mouseover" dur="0.5s"
         fill="freeze"/>
    </rect>
</svg>

The SVG markup involves four declarative animations, one for the mouseover fill animation to green, one for the mouseover rotation to 30 degrees about the point 100, 100, one for the mouseout fill animation to blue, and one for the mouseout rotation to 0 degrees about the point 100, 100. This type of SVG animation (SMIL) offers a large degree of customization, but in exchange the markup can become quite dense, especially in the case of a simple state animation.

CSS transitions and transforms give us another method of specifying the same animation. We can generate a similar effect using two styled divs.

#csscontainer {
    position: relative;
    width: 200px;
    height: 200px;
}
#cssrect {
    position: absolute;
    left: 50px;
    top: 50px;
    width: 100px;
    height: 100px;
    background-color: blue;
    border-radius: 20px;
    transition: all .5s ease-in-out;
}
#cssrect:hover {
    background-color: green;
    transform: rotate(30deg);
}
<div id="csscontainer">
    <div id="cssrect"></div>
</div>

In this example, the inner “rect” div has two different styled states, normal and hovered. The states differ only in background color and transform. Using the CSS transition property, we can tell browsers to animate between the two.

Can we use the same CSS styling in SVG? Well, almost. SVG already has some existing support for CSS. If we were to draft the following markup, most of it would already work.

rect {
    fill: blue;
    transition: all .5s ease-in-out;
}

rect:hover {
    fill: green;
    transform: rotate(30);
}
<svg xmlns="http://www.w3.org/2000/svg">
    <rect width="100" height="100" rx="20" ry="20" />
</svg>

The only missing piece is support for CSS transforms on SVG elements (transform: rotate(30)). We might not have to wait too long though. A couple of folks here at Adobe, together with Apple and the web community, are drafting a proposal to bring together CSS and SVG transforms. The proposal would allow you to choose whatever combination of transforms, CSS transitions, and SMIL animations best suits your needs.

Putting it all together, we have an example, demonstrating how different combinations of HTML, SVG, CSS & SMIL can create the same mouse over / click animations. (The svg/css example will only currently work in one of the nightly builds of webkit).

This entry was posted in Transforms and tagged , . Bookmark the permalink.

One Response to CSS & SVG

  1. The CSS and SVG example now works in the current release of Chrome :)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">