SVG Tutorial

Must Watch!



MustWatch

Symbols Emoji SVGviewer SVG Viewer


Introduction

SVG is an XML language, similar to XHTML, which can be used to draw vector graphics, such as the ones shown to the right. It can be used to create an image either by specifying all the lines and shapes necessary, by modifying already existing raster images, or by a combination of both. The image and its components can also be transformed, composited together, or filtered to change their appearance completely. SVG came about in 1999 after several competing formats had been submitted to the W3C and failed to be fully ratified. SVG is supported by all major browsers. A downside is loading SVG can be slow. SVG does offer benefits, some of which include having a DOM interface available for it, and not requiring third-party extensions. Whether or not to use it often depends on your specific use case.

 Basic ingredients

HTML provides elements for defining headers, paragraphs, tables, and so on. In much the same way SVG provides elements for circles, rectangles, and simple and complex curves. A simple SVG document consists of nothing more than the <svg> root element and several basic shapes that build a graphic together. In addition there is the <g> element, which is used to group several basic shapes together. Starting from there, the SVG image can become arbitrarily complex. SVG supports gradients, rotations, filter effects, animations, interactivity with JavaScript, and so on. But all these extra features of the language rely on this relatively small set of elements to define the graphics area.

 Before you start

There are a number of drawing applications available such as Inkscape which are free and use SVG as their native file format. However, this tutorial will rely on the trusty XML or text editor (your choice). The idea is to teach the internals of SVG to those who want to understand it, and that is best done by dirtying your hands with a bit of markup. You should note your final goal though. Not all SVG viewers are equal and so there is a good chance that something written for one app will not display exactly the same in another, because they support different levels of the SVG specification or another specification that you are using along with SVG (that is, JavaScript or CSS). SVG is supported in all modern browsers and even a couple versions back in some cases. A fairly complete browser support table can be found on Can I use. Firefox has supported some SVG content since version 1.5, and that support level has been growing with each release since. Hopefully, along with the tutorial here, MDN can help developers keep up with the differences between Gecko and some of the other major implementations. Before starting you should have a basic understanding of XML or another markup language such as HTML. If you are not too familiar with XML, here are some guidelines to keep in mind: SVG elements and attributes should all be entered in the case shown here since XML is case-sensitive (unlike HTML). Attribute values in SVG must be placed inside quotes, even if they are numbers. SVG is a huge specification. This tutorial attempts to cover the basics. Once you are familiar you should be able to use the Element Reference and the Interface Reference to find out anything else you need to know.

 Flavors of SVG

Since becoming a recommendation in 2003, the most recent "full" SVG version is 1.1. It builds on top of SVG 1.0, but adds more modularization to ease implementation. The second edition of SVG 1.1 became a Recommendation in 2011. "Full" SVG 1.2 was meant to be the next major release of SVG. It was dropped for the upcoming SVG 2.0, which is under heavy development right now and follows a similar approach to CSS 3 in that it splits components into several loosely coupled specifications. Apart from the full SVG recommendations, the working group at the W3C introduced SVG Tiny and SVG Basic in 2003. These two profiles are aimed mainly at mobile devices. The first, SVG Tiny, should yield graphics primitives for small devices with low capabilities. SVG Basic offers many features of full SVG, but doesn't include the ones which are hard to implement or heavy to render (like animations). In 2008, SVG Tiny 1.2 became a W3C Recommendation. There were plans for an SVG Print specification, which would add support for multiple pages and enhanced color management. This work was discontinued.


Getting started

 A simple example

Let us dive straight in with a simple example. Take a look at the following code. <svg version="1.1" width="300" height="200" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="red" /> <circle cx="150" cy="100" r="80" fill="green" /> <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text> </svg> Copy the code and paste it in a file demo1.svg. Then open the file in Firefox. It will render as shown in the following screenshot. (Firefox users: click here) The rendering process involves the following: We start with the <svg> root element: a doctype declaration as known from (X)HTML should be left off because DTD based SVG validation leads to more problems than it solves before SVG 2, to identify the version of the SVG for other types of validation the version and baseProfile attributes should always be used instead. Both version and baseProfile attributes are deprecated in SVG 2. as an XML dialect, SVG must always bind the namespaces correctly (in the xmlns attribute). See the Namespaces Crash Course page for more info. The background is set to red by drawing a rectangle <rect> that covers the complete image area. A green circle <circle> with a radius of 80px is drawn atop the center of the red rectangle (center of circle offset 150px to the right, and 100px downward from the top left corner). The text "SVG" is drawn. The interior of each letter is filled in with white. The text is positioned by setting an anchor where we want the midpoint to be: in this case, the midpoint should correspond to the center of the green circle. Fine adjustments can be made to the font size and vertical position to ensure the final result is aesthetically pleasing.

 Basic properties of SVG files

The first important thing to notice is the order of rendering elements. The globally valid rule for SVG files is, that later elements are rendered atop previous elements. The further down an element is the more it will be visible. SVG files on the web can be displayed directly in the browser or embedded in HTML files via several methods: If the HTML is XHTML and is delivered as type application/xhtml+xml, the SVG can be directly embedded in the XML source. If the HTML is HTML5, and the browser is a conforming HTML5 browser, the SVG can also be directly embedded. However, there may be syntax changes necessary to conform to the HTML5 specification. The SVG file can be referenced with an object element: <object data="image.svg" type="image/svg+xml" /> Likewise an iframe element can be used: <iframe src="image.svg"></iframe> An img element can theoretically be used too. However, this technique doesn't work in Firefox before 4.0. Finally, SVG can be created dynamically with JavaScript and injected into the HTML DOM. With this method, replacement technologies can be implemented for browsers which normally can't process SVG. See this dedicated article which deals with the topic in-depth. How SVG handles sizes and units will be explained on the next page.

 SVG file types

SVG files come in two flavors. Normal SVG files are simple text files containing SVG markup. The recommended filename extension for these files is ".svg" (all lowercase). Due to the potentially massive size SVG files can reach when used for some applications (e.g., geographical applications), the SVG specification also allows for gzip-compressed SVG files. The recommended filename extension for these files is ".svgz" (all lowercase). Unfortunately, it is very problematic to get gzip-compressed SVG files to work reliably across all SVG capable user agents when served from a Microsoft IIS server, and Firefox cannot load gzip-compressed SVG from the local computer. Avoid gzip-compressed SVG except when you are publishing to a webserver that you know will serve it correctly (see below).

 A word on Webservers

Now that you have an idea of how to create basic SVG files, the next stage is to upload them to a Webserver. There are some gotchas at this stage though. For normal SVG files, servers should send the HTTP headers: Content-Type: image/svg+xml Vary: Accept-Encoding For gzip-compressed SVG files, servers should send the HTTP headers: Content-Type: image/svg+xml Content-Encoding: gzip Vary: Accept-Encoding You can check that your server is sending the correct HTTP headers with your SVG files by using the Network Monitor panel or a site such as websniffer.cc. Submit the URL of one of your SVG files and look at the HTTP response headers. If you find that your server is not sending the headers with the values given above, then you should contact your Web host. If you have problems convincing them to correctly configure their servers for SVG, there may be ways to do it yourself. See the server configuration page on the w3.org for a range of simple solutions. Server misconfiguration is a very common reason for SVG failing to load, so make sure you check yours. If your server is not configured to send the correct headers with the SVG files it serves, then Firefox will most likely show the markup of the files as text or encoded garbage, or even ask the viewer to choose an application to open them.


Positions

In this article, we examine how Scalable Vector Graphics (SVG) represents the positions and sizes of objects within a drawing context, including coordinate system and what a "pixel" measurement means in a scalable context.

The grid

For all elements, SVG uses a coordinate system or grid system similar to the one used by canvas (and by a whole lot of other computer drawing routines). That is, the top left corner of the document is considered to be the point (0,0), or point of origin. Positions are then measured in pixels from the top left corner, with the positive x direction being to the right, and the positive y direction being to the bottom. Note that this is slightly different than the way you're taught to graph as a kid (y axis is flipped). However, this is the same way elements in HTML are positioned (By default, LTR documents are considered not the RTL documents which position X from right-to-left).

Example:

The element <rect x="0" y="0" width="100" height="100" /> defines a rectangle from the upper left corner, that spans from there 100px to the right and to the bottom.

What are "pixels"?

In the most basic case one pixel in an SVG document maps to one pixel on the output device (a.k.a. the screen). But SVG wouldn't have the "Scalable" in its name, if there weren't several possibilities to change this behavior. Much like absolute and relative font sizes in CSS, SVG defines absolute units (ones with a dimensional identifier like "pt" or "cm") and so-called user units, that lack that identifier and are plain numbers. Without further specification, one user unit equals one screen unit. To explicitly change this behavior, there are several possibilities in SVG. We start with the svg root element: <svg width="100" height="100"> The above element defines a simple SVG canvas with 100x100px. One user unit equals one screen unit. <svg width="200" height="200" viewBox="0 0 100 100"> The whole SVG canvas here is 200px by 200px in size. However, the viewBox attribute defines the portion of that canvas to display. These 200x200 pixels display an area that starts at user unit (0,0) and spans 100x100 user units to the right and to the bottom. This effectively zooms in on the 100x100 unit area and enlarges the image to double size. The current mapping (for a single element or the whole image) of user units to screen units is called user coordinate system. Apart from scaling the coordinate system can also be rotated, skewed and flipped. The default user coordinate system maps one user pixel to one device pixel. (However, the device may decide, what it understands as one pixel.) Lengths in the SVG file with specific dimensions, like "in" or "cm", are then calculated in a way that makes them appear 1:1 in the resulting image. A quote from the SVG 1.1 specification illustrates this:
[...] suppose that the user agent can determine from its environment that "1px" corresponds to "0.2822222mm" (i.e., 90dpi). Then, for all processing of SVG content: [...] "1cm" equals "35.43307px" (and therefore 35.43307 user units)


Basic shapes

There are several basic shapes used for most SVG drawing. The purpose of these shapes is fairly obvious from their names. Some of the parameters that determine their position and size are given, but an element reference would probably contain more accurate and complete descriptions along with other properties that won't be covered in here. However, since they're used in most SVG documents, it's necessary to give them some sort of introduction. To insert a shape, you create an element in the document. Different elements correspond to different shapes and take different parameters to describe the size and position of those shapes. Some are slightly redundant in that they can be created by other shapes, but they're all there for your convenience and to keep your SVG documents as short and as readable as possible. All the basic shapes are shown in the following image. The code to generate that image looks something like this: <?xml version="1.0" standalone="no"?> <svg width="200" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg"> <rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/> <rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/> <circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/> <ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/> <line x1="10" x2="50" y1="110" y2="150" stroke="orange" stroke-width="5"/> <polyline points="60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145" stroke="orange" fill="transparent" stroke-width="5"/> <polygon points="50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180" stroke="green" fill="transparent" stroke-width="5"/> <path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/> </svg> Note: The stroke, stroke-width, and fill attributes are explained later in the tutorial.

Rectangle

The <rect> element draws a rectangle on the screen. There are 6 basic attributes that control the position and shape of the rectangles on screen. The one on the right has its rx and ry parameters set, giving it rounded corners. If they're not set, they default to 0. <rect x="10" y="10" width="30" height="30"/> <rect x="60" y="10" rx="10" ry="10" width="30" height="30"/> x The x position of the top left corner of the rectangle. y The y position of the top left corner of the rectangle. width The width of the rectangle height The height of the rectangle rx The x radius of the corners of the rectangle ry The y radius of the corners of the rectangle

Circle

The <circle> element draws a circle on the screen. It takes 3 basic parameters to determine the shape and size of the element. <circle cx="25" cy="75" r="20"/> r The radius of the circle. cx The x position of the center of the circle. cy The y position of the center of the circle.

Ellipse

An <ellipse> is a more general form of the <circle> element, where you can scale the x and y radius (commonly referred to as the semimajor and semiminor axes in maths) of the circle separately. <ellipse cx="75" cy="75" rx="20" ry="5"/> rx The x radius of the ellipse. ry The y radius of the ellipse. cx The x position of the center of the ellipse. cy The y position of the center of the ellipse.

Line

The <line> element takes the positions of two points as parameters and draws a straight line between them. <line x1="10" x2="50" y1="110" y2="150" stroke="black" stroke-width="5"/> x1 The x position of point 1. y1 The y position of point 1. x2 The x position of point 2. y2 The y position of point 2.

Polyline

A <polyline> is a group of connected straight lines. Since the list of points can get quite long, all the points are included in one attribute: <polyline points="60, 110 65, 120 70, 115 75, 130 80, 125 85, 140 90, 135 95, 150 100, 145"/> points A list of points. Each number must be separated by a space, comma, EOL, or a line feed character. Each point must contain two numbers: an x coordinate and a y coordinate. So, the list (0,0), (1,1), and (2,2) would be written as 0, 0 1, 1 2, 2.

Polygon

A <polygon> is similar to a <polyline>, in that it is composed of straight line segments connecting a list of points. For polygons though, the path automatically connects the last point with the first, creating a closed shape. Note: A rectangle is a type of polygon, so a polygon can be used to create a <rect/> element in cases where you need a little more flexibility. <polygon points="50, 160 55, 180 70, 180 60, 190 65, 205 50, 195 35, 205 40, 190 30, 180 45, 180"/> points A list of points, each number separated by a space, comma, EOL, or a line feed character. Each point must contain two numbers: an x coordinate and a y coordinate. So, the list (0,0), (1,1), and (2,2) would be written as 0, 0 1, 1 2, 2. The drawing then closes the path, so a final straight line would be drawn from (2,2) to (0,0).

Path

A <path> is the most general shape that can be used in SVG. Using a path element, you can draw rectangles (with or without rounded corners), circles, ellipses, polylines, and polygons. Basically any of the other types of shapes, bezier curves, quadratic curves, and many more. For this reason, the next section in this tutorial will be focused on paths. But for now, note that there is a single parameter used to control its shape. <path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/> d A list of points and other information about how to draw the path. See the Paths section for more information.


Paths

The <path> element is the most powerful element in the SVG library of basic shapes. It can be used to create lines, curves, arcs, and more. Paths create complex shapes by combining multiple straight lines or curved lines. Complex shapes composed only of straight lines can be created as <polyline>s. While <polyline>s and <path>s can create similar-looking shapes, <polyline>s require a lot of small straight lines to simulate curves, and don't scale well to larger sizes. A good understanding of paths is important when drawing SVGs. While creating complex paths using an XML editor or text editor is not recommended, understanding how they work will allow to identify and repair display issues in SVGs. The shape of a <path> element is defined by one parameter: d. (See more in basic shapes.) The d attribute contains a series of commands and parameters used by those commands. Each of the commands is instantiated (for example, creating a class, naming and locating it) by a specific letter. For instance, let's move to the x and y coordinates (10, 10). The "Move to" command is called with the letter M. When the parser runs into this letter, it knows it needs to move to a point. So, to move to (10,10) the command to use would be M 10 10. After that, the parser begins reading for the next command. All of the commands also come in two variants. An uppercase letter specifies absolute coordinates on the page, and a lowercase letter specifies relative coordinates (e.g., move 10px up and 7px to the left from the last point). Coordinates in the d parameter are always unitless and hence in the user coordinate system. Later, we will learn how paths can be transformed to suit other needs.

Line commands

There are five line commands for <path> nodes. The first command is the "Move To" or M, which was described above. It takes two parameters, a coordinate (x) and coordinate (y) to move to. If the cursor was already somewhere on the page, no line is drawn to connect the two positions. The "Move To" command appears at the beginning of paths to specify where the drawing should start. For example: M x y (or) m dx dy In the following example there's only a point at (10,10). Note, though, that it wouldn't show up if a path was just drawn normally. For example: <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"> <path d="M10 10"/> <!-- Points --> <circle cx="10" cy="10" r="2" fill="red"/> </svg> There are three commands that draw lines. The most generic is the "Line To" command, called with L. L takes two parameters—x and y coordinates—and draws a line from the current position to a new position. L x y (or) l dx dy There are two abbreviated forms for drawing horizontal and vertical lines. H draws a horizontal line, and V draws a vertical line. Both commands only take one parameter since they only move in one direction. H x (or) h dx V y (or) v dy An easy place to start is by drawing a shape. We will start with a rectangle (the same type that could be more easily made with a <rect> element). It's composed of horizontal and vertical lines only. <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> <path d="M 10 10 H 90 V 90 H 10 L 10 10"/> <!-- Points --> <circle cx="10" cy="10" r="2" fill="red"/> <circle cx="90" cy="90" r="2" fill="red"/> <circle cx="90" cy="10" r="2" fill="red"/> <circle cx="10" cy="90" r="2" fill="red"/> </svg> We can shorten the above path declaration a little bit by using the "Close Path" command, called with Z. This command draws a straight line from the current position back to the first point of the path. It is often placed at the end of a path node, although not always. There is no difference between the uppercase and lowercase command. Z (or) z So our path above could be shortened to: <path d="M 10 10 H 90 V 90 H 10 Z" fill="transparent" stroke="black"/> The relative forms of these commands can also be used to draw the same picture. Relative commands are called by using lowercase letters, and rather than moving the cursor to an exact coordinate, they move it relative to its last position. For instance, since our box is 80×80, the <path> element could have been written as: <path d="M 10 10 h 80 v 80 h -80 Z" fill="transparent" stroke="black"/> The path will move to point (10,10) and then move horizontally 80 points to the right, then 80 points down, then 80 points to the left, and then back to the start. In these examples, it would probably be simpler to use the <polygon> or <polyline> elements. However, paths are used so often in drawing SVG that developers may be more comfortable using them instead. There is no real performance penalty or bonus for using one or the other.

Curve commands

There are three different commands that can be used to create smooth curves. Two of those curves are Bézier curves, and the third is an "arc" or part of a circle. You might have already gained practical experience with Bézier curves using path tools in Inkscape, Illustrator or Photoshop. For a complete description of the math behind Bézier curves, go to a reference like the one on Wikipedia. There are an infinite number of Bézier curves, but only two simple ones are available in <path> elements: a cubic one, called with C, and a quadratic one, called with Q.

 Bézier Curves

The cubic curve, C, is the slightly more complex curve. Cubic Béziers take in two control points for each point. Therefore, to create a cubic Bézier, three sets of coordinates need to be specified. C x1 y1, x2 y2, x y (or) c dx1 dy1, dx2 dy2, dx dy The last set of coordinates here (x,y) specify where the line should end. The other two are control points. (x1,y1) is the control point for the start of the curve, and (x2,y2) is the control point for the end. The control points essentially describe the slope of the line starting at each point. The Bézier function then creates a smooth curve that transfers from the slope established at the beginning of the line, to the slope at the other end. Cubic Bézier Curves with grid <svg width="190" height="160" xmlns="http://www.w3.org/2000/svg"> <path d="M 10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/> <path d="M 70 10 C 70 20, 110 20, 110 10" stroke="black" fill="transparent"/> <path d="M 130 10 C 120 20, 180 20, 170 10" stroke="black" fill="transparent"/> <path d="M 10 60 C 20 80, 40 80, 50 60" stroke="black" fill="transparent"/> <path d="M 70 60 C 70 80, 110 80, 110 60" stroke="black" fill="transparent"/> <path d="M 130 60 C 120 80, 180 80, 170 60" stroke="black" fill="transparent"/> <path d="M 10 110 C 20 140, 40 140, 50 110" stroke="black" fill="transparent"/> <path d="M 70 110 C 70 140, 110 140, 110 110" stroke="black" fill="transparent"/> <path d="M 130 110 C 120 140, 180 140, 170 110" stroke="black" fill="transparent"/> </svg> The example above creates nine cubic Bézier curves. As the curves move toward the right, the control points become spread out horizontally. As the curves move downward, they become further separated from the end points. The thing to note here is that the curve starts in the direction of the first control point, and then bends so that it arrives along the direction of the second control point. Several Bézier curves can be stringed together to create extended, smooth shapes. Often, the control point on one side of a point will be a reflection of the control point used on the other side to keep the slope constant. In this case, a shortcut version of the cubic Bézier can be used, designated by the command S (or s). S x2 y2, x y (or) s dx2 dy2, dx dy S produces the same type of curve as earlier—but if it follows another S command or a C command, the first control point is assumed to be a reflection of the one used previously. If the S command doesn't follow another S or C command, then the current position of the cursor is used as the first control point. In this case the result is the same as what the Q command would have produced with the same parameters. An example of this syntax is shown below, and in the figure to the left the specified control points are shown in red, and the inferred control point in blue. <svg width="190" height="160" xmlns="http://www.w3.org/2000/svg"> <path d="M 10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" stroke="black" fill="transparent"/> </svg> The other type of Bézier curve, the quadratic curve called with Q, is actually a simpler curve than the cubic one. It requires one control point which determines the slope of the curve at both the start point and the end point. It takes two parameters: the control point and the end point of the curve. Note: The co-ordinate deltas for q are both relative to the previous point (that is, dx and dy are not relative to dx1 and dy1). Q x1 y1, x y (or) q dx1 dy1, dx dy Quadratic Bézier with grid <svg width="190" height="160" xmlns="http://www.w3.org/2000/svg"> <path d="M 10 80 Q 95 10 180 80" stroke="black" fill="transparent"/> </svg> As with the cubic Bézier curve, there is a shortcut for stringing together multiple quadratic Béziers, called with T. T x y (or) t dx dy This shortcut looks at the previous control point used and infers a new one from it. This means that after the first control point, fairly complex shapes can be made by specifying only end points. This only works if the previous command was a Q or a T command. If not, then the control point is assumed to be the same as the previous point, and only lines will be drawn. <svg width="190" height="160" xmlns="http://www.w3.org/2000/svg"> <path d="M 10 80 Q 52.5 10, 95 80 T 180 80" stroke="black" fill="transparent"/> </svg> Both curves produce similar results, although the cubic one allows greater freedom in exactly what the curve looks like. Deciding which curve to use is situational and depends on the amount of symmetry the line has.

 Arcs

The other type of curved line that can be created using SVG is the arc, called with the A command. Arcs are sections of circles or ellipses. For a given x-radius and y-radius, there are two ellipses that can connect any two points (as long as they're within the radius of the circle). Along either of those circles, there are two possible paths that can be taken to connect the points—so in any situation, there are four possible arcs available. Because of that, arcs require quite a few parameters: A rx ry x-axis-rotation large-arc-flag sweep-flag x y a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy At its start, the arc element takes in two parameters for the x-radius and y-radius. If needed, see <ellipse>s and how they behave. The final two parameters designate the x and y coordinates to end the stroke. Together, these four values define the basic structure of the arc. The third parameter describes the rotation of the arc. This is best explained with an example: SVGArcs_XAxisRotation_with_grid <svg width="320" height="320" xmlns="http://www.w3.org/2000/svg"> <path d="M 10 315 L 110 215 A 30 50 0 0 1 162.55 162.45 L 172.55 152.45 A 30 50 -45 0 1 215.1 109.9 L 315 10" stroke="black" fill="green" stroke-width="2" fill-opacity="0.5"/> </svg> The example shows a <path> element that goes diagonally across the page. At its center, two elliptical arcs have been cut out (x radius = 30, y radius = 50). In the first one, the x-axis-rotation has been left at 0, so the ellipse that the arc travels around (shown in gray) is oriented straight up and down. For the second arc, though, the x-axis-rotation is set to -45 degrees. This rotates the ellipse so that it is aligned with its minor axis along the path direction, as shown by the second ellipse in the example image. For the unrotated ellipse in the image above, there are only two different arcs and not four to choose from because the line drawn from the start and end of the arc goes through the center of the ellipse. In a slightly modified example the two ellipses that form the four different arcs can be seen: Show the 4 arcs on the Ellipse example <svg xmlns="http://www.w3.org/2000/svg" width="320" height="320"> <path d="M 10 315 L 110 215 A 36 60 0 0 1 150.71 170.29 L 172.55 152.45 A 30 50 -45 0 1 215.1 109.9 L 315 10" stroke="black" fill="green" stroke-width="2" fill-opacity="0.5"/> <circle cx="150.71" cy="170.29" r="2" fill="red"/> <circle cx="110" cy="215" r="2" fill="red"/> <ellipse cx="144.931" cy="229.512" rx="36" ry="60" fill="transparent" stroke="blue"/> <ellipse cx="115.779" cy="155.778" rx="36" ry="60" fill="transparent" stroke="blue"/> </svg> Notice that each of the blue ellipses are formed by two arcs, depending on traveling clockwise or counter-clockwise. Each ellipse has one short arc and one long arc. The two ellipses are just mirror images of each other. They are flipped along the line formed from the start→end points. If the start→end points are farther than the ellipse's x and y radius can reach, the ellipse's radii will be minimally expanded so it could reach the start→end points. The interactive codepen at the bottom of this page demonstrates this well. To determine if an ellipse's radii are large enough to require expanding, a system of equations would need to be solved, such as this on wolfram alpha. This computation is for the non-rotated ellipse with start→end (110, 215)→(150.71, 170.29). The solution, (x, y), is the center of the ellipse(s). The solution will be imaginary if the ellipse's radii are too small. This second computation is for the non-rotated ellipse with start→end (110, 215)→(162.55, 162.45). The solution has a small imaginary component because the ellipse was just barely expanded. The four different paths mentioned above are determined by the next two parameter flags. As mentioned earlier, there are still two possible ellipses for the path to travel around and two different possible paths on both ellipses, giving four possible paths. The first parameter is the large-arc-flag. It determines if the arc should be greater than or less than 180 degrees; in the end, this flag determines which direction the arc will travel around a given circle. The second parameter is the sweep-flag. It determines if the arc should begin moving at positive angles or negative ones, which essentially picks which of the two circles will be traveled around. The example below shows all four possible combinations, along with the two circles for each case. <svg width="325" height="325" xmlns="http://www.w3.org/2000/svg"> <path d="M 80 80 A 45 45, 0, 0, 0, 125 125 L 125 80 Z" fill="green"/> <path d="M 230 80 A 45 45, 0, 1, 0, 275 125 L 275 80 Z" fill="red"/> <path d="M 80 230 A 45 45, 0, 0, 1, 125 275 L 125 230 Z" fill="purple"/> <path d="M 230 230 A 45 45, 0, 1, 1, 275 275 L 275 230 Z" fill="blue"/> </svg> Arcs are an easy way to create pieces of circles or ellipses in drawings. For instance, a pie chart would require a different arc for each piece. If transitioning to SVG from <canvas>, arcs can be the hardest thing to learn, but are also much more powerful. Complete circles and ellipses are the only shapes that SVG arcs have trouble drawing. Because the start and end points for any path going around a circle are the same point, there are an infinite number of circles that could be chosen, and the actual path is undefined. It's possible to approximate them by making the start and end points of the path slightly askew, and then connecting them with another path segment. For example, it's possible to make a circle with an arc for each semi-circle. At that point, it's often easier to use a real <circle> or <ellipse> node instead. This interactive demo might help understand the concepts behind SVG arcs: http://codepen.io/lingtalfi/pen/yaLWJG (tested in chrome and firefox only, might not work in your browser)


Fills and Strokes

There are several ways to color shapes (including specifying attributes on the object) using inline CSS, an embedded CSS section, or an external CSS file. Most SVG you'll find around the web use inline CSS, but there are advantages and disadvantages associated with each type.

Fill and Stroke Attributes

 Painting

Basic coloring can be done by setting two attributes on the node: fill and stroke. Using fill sets the color inside the object and stroke sets the color of the line drawn around the object. You can use the same css color naming schemes that you use in HTML, whether that's color names (that is red), rgb values (that is rgb(255,0,0)), hex values, rgba values, etc. <rect x="10" y="10" width="100" height="100" stroke="blue" fill="purple" fill-opacity="0.5" stroke-opacity="0.8"/> In addition, you can specify the opacity of either the fill or stroke separately in SVG. These are controlled by the fill-opacity and stroke-opacity attributes. Note: In Firefox, rgba values are also allowed, and will give the same effect. But for compatibility with other viewers, it's often best to specify the fill/stroke opacity separately. If you specify both an rgba value and a fill/stroke opacity value, both will be applied.

 Stroke

In addition to its color properties, there are a few other attributes available to control the way a stroke is drawn on a line. <?xml version="1.0" standalone="no"?> <svg width="160" height="140" xmlns="http://www.w3.org/2000/svg" version="1.1"> <line x1="40" x2="120" y1="20" y2="20" stroke="black" stroke-width="20" stroke-linecap="butt"/> <line x1="40" x2="120" y1="60" y2="60" stroke="black" stroke-width="20" stroke-linecap="square"/> <line x1="40" x2="120" y1="100" y2="100" stroke="black" stroke-width="20" stroke-linecap="round"/> </svg> The stroke-width property defines the width of this stroke. Strokes are drawn centered around the path. In the example above, the path is shown in pink, and the stroke in black. The second attribute affecting strokes is the stroke-linecap property, demonstrated above. This controls the shape of the ends of lines. There are three possible values for stroke-linecap: butt closes the line off with a straight edge that's normal (at 90 degrees) to the direction of the stroke and crosses its end. square has essentially the same appearance, but stretches the stroke slightly beyond the actual path. The distance that the stroke goes beyond the path is half the stroke-width. round produces a rounded effect on the end of the stroke. The radius of this curve is also controlled by the stroke-width. Use stroke-linejoin to control how the joint between two line segments is drawn. <?xml version="1.0" standalone="no"?> <svg width="160" height="280" xmlns="http://www.w3.org/2000/svg" version="1.1"> <polyline points="40 60 80 20 120 60" stroke="black" stroke-width="20" stroke-linecap="butt" fill="none" stroke-linejoin="miter"/> <polyline points="40 140 80 100 120 140" stroke="black" stroke-width="20" stroke-linecap="round" fill="none" stroke-linejoin="round"/> <polyline points="40 220 80 180 120 220" stroke="black" stroke-width="20" stroke-linecap="square" fill="none" stroke-linejoin="bevel"/> </svg> Each of these polylines has two segments. The joint where the two meet is controlled by the stroke-linejoin attribute. There are three possible values for this attribute. miter extends the line slightly beyond its normal width to create a square corner where only one angle is used. round creates a rounded line segment. bevel creates a new angle to aid in the transition between the two segments. Finally, you can also use dashed line types on a stroke by specifying the stroke-dasharray attribute. <?xml version="1.0" standalone="no"?> <svg width="200" height="150" xmlns="http://www.w3.org/2000/svg" version="1.1"> <path d="M 10 75 Q 50 10 100 75 T 190 75" stroke="black" stroke-linecap="round" stroke-dasharray="5,10,5" fill="none"/> <path d="M 10 75 L 190 75" stroke="red" stroke-linecap="round" stroke-width="1" stroke-dasharray="5,5" fill="none"/> </svg> The stroke-dasharray attribute takes a series of comma-separated numbers as its argument. Note: Unlike <path> elements, these numbers must be comma-separated (whitespace is ignored). The first number specifies a distance for the filled area, and the second a distance for the unfilled area. So in the above example, the second path fills 5 pixel units, with 5 blank units until the next dash of 5 units. You can specify more numbers if you would like a more complicated dash pattern. The first example specifies three numbers, in which case the renderer loops the numbers twice to create an even pattern. So the first path renders 5 filled, 10 empty, 5 filled, and then loops back to create 5 empty, 10 filled, 5 empty. The pattern then repeats. There are additional stroke and fill properties available, including fill-rule, which specifies how to color in shapes that overlap themselves; stroke-miterlimit, which determines if a stroke should draw miters; and stroke-dashoffset, which specifies where to start a dasharray on a line.

Using CSS

In addition to setting attributes on objects, you can also use CSS to style fills and strokes. Not all attributes can be set via CSS. Attributes that deal with painting and filling are usually available, so fill, stroke, stroke-dasharray, etc... can all be set this way, in addition to the gradient and pattern versions of those shown below. Attributes like width, height, or <path> commands cannot be set through CSS. It's easiest just to test and find out what is available and what isn't. Note: The SVG specification decides strictly between attributes that are properties and other attributes. The former can be modified with CSS, the latter not. CSS can be inserted inline with the element via the style attribute: <rect x="10" height="180" y="10" width="180" style="stroke: black; fill: red;"/> Or it can be moved to a special style section that you include. Instead of shoving such a section into a <head> section like you do in HTML, though, it's included in an area called <defs>. <defs> stands for definitions, and it is here that you can create elements that don't appear in the SVG directly, but are used by other elements. <?xml version="1.0" standalone="no"?> <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1"> <defs> <style type="text/css"><![CDATA[ #MyRect { stroke: black; fill: red; } ]]></style> </defs> <rect x="10" height="180" y="10" width="180" id="MyRect"/> </svg> Moving styles to an area like this can make it easier to adjust properties on large groups of elements. You can also use things like the :hover pseudo class to create rollover effects: #MyRect:hover { stroke: black; fill: blue; } You can also specify an external stylesheet for your CSS rules through normal XML-stylesheet syntax: <?xml version="1.0" standalone="no"?> <?xml-stylesheet type="text/css" href="style.css"?> <svg width="200" height="150" xmlns="http://www.w3.org/2000/svg" version="1.1"> <rect height="10" width="10" id="MyRect"/> </svg> Where style.css looks something like: #MyRect { fill: red; stroke: black; }


Gradients in SVG

Perhaps more exciting than just fills and strokes is the fact that you can also create and apply gradients as either fills or strokes. There are two types of gradients: linear and radial. You must give the gradient an id attribute; otherwise it can't be referenced by other elements inside the file. Gradients are defined in a defs section as opposed to on a shape itself to promote reusability.

Linear Gradient

Linear gradients change along a straight line. To insert one, you create a <linearGradient> node inside the definitions section of your SVG file.

 Basic example

<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="Gradient1"> <stop class="stop1" offset="0%"/> <stop class="stop2" offset="50%"/> <stop class="stop3" offset="100%"/> </linearGradient> <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1"> <stop offset="0%" stop-color="red"/> <stop offset="50%" stop-color="black" stop-opacity="0"/> <stop offset="100%" stop-color="blue"/> </linearGradient> <style type="text/css"><![CDATA[ #rect1 { fill: url(#Gradient1); } .stop1 { stop-color: red; } .stop2 { stop-color: black; stop-opacity: 0; } .stop3 { stop-color: blue; } ]]></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> Above is an example of a linear gradient being applied to a <rect> element. Inside the linear gradient are several <stop> nodes. These nodes tell the gradient what color it should be at certain positions by specifying an offset attribute for the position, and a stop-color attribute. This can be assigned directly or through CSS. The two methods have been intermixed for the purposes of this example. For instance, this one tells the gradient to start at the color red, change to transparent-black in the middle, and end at the color blue. You can insert as many stop colors as you like to create a blend that's as beautiful or hideous as you need, but the offsets should always increase from 0% (or 0 if you want to drop the % sign) to 100% (or 1). Duplicate values will use the stop that is assigned furthest down the XML tree. Also, like with fill and stroke, you can specify a stop-opacity attribute to set the opacity at that position (again, in FF3 you can also use rgba values to do this). <stop offset="100%" stop-color="yellow" stop-opacity="0.5"/> To use a gradient, we have to reference it from an object's fill or stroke attributes. This is done the same way you reference elements in CSS, using a url. In this case, the url is just a reference to our gradient, which I've given the creative ID, "Gradient". To attach it, set the fill to url(#Gradient), and voila! Our object is now multicolored. You can do the same with stroke. The <linearGradient> element also takes several other attributes, which specify the size and appearance of the gradient. The orientation of the gradient is controlled by two points, designated by the attributes x1, x2, y1, and y2. These attributes define a line along which the gradient travels. The gradient defaults to a horizontal orientation, but it can be rotated by changing these. Gradient2 in the above example is designed to create a vertical gradient. <linearGradient x1="0" x2="0" y1="0" y2="1"> Note: You can also use the xlink:href attribute on gradients too. When it is used, attributes and stops from one gradient can be included on another. In the above example, you wouldn't have to recreate all the stops in Gradient2. <linearGradient> <stop offset="0%"/> <stop offset="50%"/> <stop offset="100%"/> </linearGradient> <linearGradient x1="0" x2="0" y1="0" y2="1" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient1"/> I've included the xlink namespace here directly on the node, although usually you would define it at the top of your document. More on that when we talk about images.

Radial Gradient

Radial gradients are similar to linear ones but draw a gradient that radiates out from a point. To create one you add a <radialGradient> element to the definitions section of your document.

 Basic example

<?xml version="1.0" standalone="no"?> <svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg"> <defs> <radialGradient id="RadialGradient1"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="blue"/> </radialGradient> <radialGradient id="RadialGradient2" cx="0.25" cy="0.25" r="0.25"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="blue"/> </radialGradient> </defs> <rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient1)"/> <rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient2)"/> </svg> The stops used here are the same as before, but now the object will be red in the center, and in all directions gradually change to blue at the edge. Like linear gradients, the <radialGradient> node can take several attributes to describe its position and orientation. However, unlike linear gradients, it's a bit more complex. The radial gradient is again defined by two points, which determine where its edges are. The first of these defines a circle around which the gradient ends. It requires a center point, designated by the cx and cy attributes, and a radius, r. Setting these three attributes will allow you to move the gradient around and change its size, as shown in the second rect above. The second point is called the focal point and is defined by the fx and fy attributes. While the first point described where the edges of the gradient were, the focal point describes where its middle is. This is easier to see with an example.

 Center and focal point

<?xml version="1.0" standalone="no"?> <svg width="120" height="120" version="1.1" xmlns="http://www.w3.org/2000/svg"> <defs> <radialGradient id="Gradient" cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="blue"/> </radialGradient> </defs> <rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#Gradient)" stroke="black" stroke-width="2"/> <circle cx="60" cy="60" r="50" fill="transparent" stroke="white" stroke-width="2"/> <circle cx="35" cy="35" r="2" fill="white" stroke="white"/> <circle cx="60" cy="60" r="2" fill="white" stroke="white"/> <text x="38" y="40" fill="white" font-family="sans-serif" font-size="10pt">(fx,fy)</text> <text x="63" y="63" fill="white" font-family="sans-serif" font-size="10pt">(cx,cy)</text> </svg> If the focal point is moved outside the circle described earlier, it's impossible for the gradient to be rendered correctly, so the spot will be assumed to be within the edge of the circle. If the focal point isn't given at all, it's assumed to be at the same place as the center point. Both linear and radial gradients also take a few other attributes to describe transformations they may undergo. The only other one I want to mention here is the spreadMethod attribute. This attribute controls what happens when the gradient reaches its end, but the object isn't filled yet. It can take on one of three values, "pad", "reflect", or "repeat". "Pad" is what you have seen so far. When the gradient reaches its end, the final offset color is used to fill the rest of the object. "reflect" causes the gradient to continue on, but reflected in reverse, starting with the color offset at 100% and moving back to the offset at 0%, and then back up again. "Repeat" also lets the gradient continue, but instead of going backwards, it just jumps back to the beginning and runs again.

 spreadMethod

<?xml version="1.0" standalone="no"?> <svg width="220" height="220" version="1.1" xmlns="http://www.w3.org/2000/svg"> <defs> <radialGradient id="GradientPad" cx="0.5" cy="0.5" r="0.4" fx="0.75" fy="0.75" spreadMethod="pad"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="blue"/> </radialGradient> <radialGradient id="GradientRepeat" cx="0.5" cy="0.5" r="0.4" fx="0.75" fy="0.75" spreadMethod="repeat"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="blue"/> </radialGradient> <radialGradient id="GradientReflect" cx="0.5" cy="0.5" r="0.4" fx="0.75" fy="0.75" spreadMethod="reflect"> <stop offset="0%" stop-color="red"/> <stop offset="100%" stop-color="blue"/> </radialGradient> </defs> <rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#GradientPad)"/> <rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#GradientRepeat)"/> <rect x="120" y="120" rx="15" ry="15" width="100" height="100" fill="url(#GradientReflect)"/> <text x="15" y="30" fill="white" font-family="sans-serif" font-size="12pt">Pad</text> <text x="15" y="140" fill="white" font-family="sans-serif" font-size="12pt">Repeat</text> <text x="125" y="140" fill="white" font-family="sans-serif" font-size="12pt">Reflect</text> </svg> Both gradients also have an attribute named gradientUnits, which describes the unit system you're going to use when you describe the size or orientation of the gradient. There are two possible values to use here: userSpaceOnUse or objectBoundingBox. objectBoundingBox is the default, so that's what has been shown so far. It essentially scales the gradient to the size of your object, so you only have to specify coordinates in values from zero to one, and they're scaled to the size of your object automatically for you. userSpaceOnUse essentially takes in absolute units. So you have to know where your object is, and place the gradient at the same place. The radialGradient above would be rewritten: <radialGradient cx="60" cy="60" r="50" fx="35" fy="35" gradientUnits="userSpaceOnUse"> You can also then apply another transformation to the gradient by using the gradientTransform attribute, but since we haven't introduced transforms yet, I'll leave that for later. There are some other caveats for dealing with gradientUnits="objectBoundingBox" when the object bounding box isn't square, but they're fairly complex and will have to wait for someone more in-the-know to explain them.


Patterns

Patterns

Patterns are arguably one of the more confusing fill types to use in SVG. They're also very powerful, so they're worth talking about and getting at least a fundamental grasp on. Like gradients, the <pattern> element should be put in the <defs> section of your SVG file. <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="Gradient1"> <stop offset="5%" stop-color="white"/> <stop offset="95%" stop-color="blue"/> </linearGradient> <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1"> <stop offset="5%" stop-color="red"/> <stop offset="95%" stop-color="orange"/> </linearGradient> <pattern id="Pattern" x="0" y="0" width=".25" height=".25"> <rect x="0" y="0" width="50" height="50" fill="skyblue"/> <rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)"/> <circle cx="25" cy="25" r="20" fill="url(#Gradient1)" fill-opacity="0.5"/> </pattern> </defs> <rect fill="url(#Pattern)" stroke="black" width="200" height="200"/> </svg> Inside the <pattern> element, you can include any of the other basic shapes you've included before, and each of them can be styled using any of the styles you've learned before, including gradients and opacity. Here, we've just drawn two rectangle elements inside the pattern (which overlap, and one of which is twice the size of the other and is used to fill in the entire pattern), and one circle. The confusing thing about patterns is defining a unit system and their size. In the example above, we've defined a width and height attribute on the pattern element to describe how far the pattern should go before it begins repeating itself again. There are also x and y attributes available if you want to offset the start point of this rectangle somewhere within your drawing. The reason they've been used here is described below. As with the gradientUnits attribute used above, patterns also have an attribute, patternUnits, which specifies the units that these attributes will take. It defaults to "objectBoundingBox" as it did above, so a value of 1 is scaled to the width/height of the object you're applying the pattern to. Since, in this case, we wanted the pattern to repeat 4 times horizontally and vertically, the height and width are set to 0.25. This means the pattern's width/height is only 0.25 of the total box size. Unlike gradients, patterns have a second attribute, patternContentUnits, which describes the units system used inside the pattern element, on the basic shapes themselves. This attribute defaults to "userSpaceOnUse", the opposite of the patternUnits attribute. What this means is that unless you specify one or both of these attributes (patternContentUnits and patternUnits), the shapes you draw inside your pattern are being drawn in a different coordinate system than the pattern element is using, which can make things a bit confusing when you're writing this by hand. To make this work in the example above, we had to consider the size of our box (200 pixels) and the fact that we wanted the pattern to repeat itself 4 times horizontally and vertically. This means that each pattern unit was a 50×50 square. The two rects and the circle inside the pattern were then sized to fit in a 50×50 box. Anything we had drawn outside that box wouldn't have been shown. The pattern also had to be offset by 10 pixels so that it would start in the upper-left corner of our box, so the x and y attributes of the pattern had to be adjusted to 10÷200 = 0.05. The caveat here is that if the object changes size, the pattern itself will scale to fit it, but the objects inside will not. So while we would still have 4 repeating units inside the pattern, the objects composing that pattern would remain the same size, and you end up with large areas of nothing in between them. By changing the patternContentUnits attribute, we can put all the elements into the same unit system: <pattern id="Pattern" width=".25" height=".25" patternContentUnits="objectBoundingBox"> <rect x="0" y="0" width=".25" height=".25" fill="skyblue"/> <rect x="0" y="0" width=".125" height=".125" fill="url(#Gradient2)"/> <circle cx=".125" cy=".125" r=".1" fill="url(#Gradient1)" fill-opacity="0.5"/> </pattern> Now, because the pattern content is in the same unit system as the pattern, we don't have to offset the box so that the pattern starts in the correct place, and if the object size was changed to a larger one, the pattern would automatically scale so that it had the same number of objects and repeats inside it. This contrasts with the "userSpaceOnUse" system, where if the object changes the size, the pattern would stay the same and just repeat itself more times to fill the box. As a slight aside, in Gecko circles seem to have trouble drawing if their radius is set to something less than 0.075 (it is currently unknown whether this is a bug in the pattern element or not). To work around that it is probably best to avoid drawing in "objectBoundingBox" units unless you have to. Neither of these uses is what one would normally think of when you think of a pattern. Patterns usually have a set size and repeat themselves independently of what an object's shape is. To create something like this, both the pattern and its contents must be drawn in the current userSpace, so they don't change shape if the object does: <pattern id="Pattern" x="10" y="10" width="50" height="50" patternUnits="userSpaceOnUse"> <rect x="0" y="0" width="50" height="50" fill="skyblue"/> <rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)"/> <circle cx="25" cy="25" r="20" fill="url(#Gradient1)" fill-opacity="0.5"/> </pattern> Of course, this means the pattern won't scale if you change your object size later. All three of the preceding examples are shown below on a rectangle that has been slightly elongated to a height of 300px, but I should note that it's not an exhaustive picture, and there are other options available depending on your application.


Texts

When talking about text in SVG we have to differentiate two almost completely separate topics. The one is the inclusion and display of text in an image, and the other are SVG fonts. The latter may be described in a later section of the tutorial, while we will focus completely on the first part: Bringing text into an SVG image.

Basics

We have seen in the introducing example, that the text element can be used to put arbitrary text in SVG documents: <text x="10" y="10">Hello World!</text> The x and y attributes determine, where in the viewport the text will appear. The attribute text-anchor, which can have the values "start", "middle", "end" or "inherit", decides in which direction the text flows from this point. The attribute dominant-baseline decides the vertical alignment. Like with the shape elements text can be colorized with the fill attribute and given a stroke with the stroke attribute. Both may also refer to gradients or patterns, which makes simple coloring text in SVG very powerful compared to CSS 2.1.

Setting font properties

An essential part of a text is the font in which it is displayed. SVG offers a set of attributes, many similar to their CSS counterparts, to enable font selection. Each of the following properties can be set as an attribute or via a CSS declaration: font-family, font-style, font-weight, font-variant, font-stretch, font-size, font-size-adjust, kerning, letter-spacing, word-spacing and text-decoration.

Other text-related elements

 tspan

This element is used to mark up sub-portions of a larger text. It must be a child of a text element or another tspan element. A typical use case is to paint one word of a sentence bold red. <svg width="350" height="60" xmlns="http://www.w3.org/2000/svg"> <text> This is <tspan font-weight="bold" fill="red">bold and red</tspan> </text> <style><![CDATA[ text{ dominant-baseline: hanging; font: 28px Verdana, Helvetica, Arial, sans-serif; } ]]></style> </svg> The tspan element has the following custom attributes: x Set a new absolute x coordinate for the containing text. This overwrites the default current text position. The attribute may also contain a list of numbers, that are one by one applied to the single characters of the tspan element. dx Start drawing the text with a horizontal offset dx from the default current position. Here, too, you may provide a list of values that are applied to consecutive characters, hence piling up the offset over time. Likewise, there are y and dy for vertical displacement. rotate Rotate all characters by this degree. A list of numbers makes each character rotate to its respective value, with remaining characters rotating according to the last value. textLength This is a more obscure attribute giving the calculated length of the string. It is meant to allow the rendering engine to fine-tune the positions of the glyphs when its own measured text length doesn't meet the one provided here.

 textPath

This element fetches via its xlink:href attribute an arbitrary path and aligns the characters, that it encircles, along this path: <svg width="200" height="100" xmlns="http://www.w3.org/2000/svg"> <path id="my_path" d="M 20,20 C 80,60 100,40 120,20" fill="transparent" /> <text> <textPath xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#my_path"> A curve. </textPath> </text> <style><![CDATA[ text{ dominant-baseline: hanging; font: 28px Verdana, Helvetica, Arial, sans-serif; } ]]></style> </svg>


Basic Transformations

Now we're ready to start distorting our beautiful images. But first, let's formally introduce the <g> element. With this helper, you can assign properties to a complete set of elements. Actually, that's its only purpose.

Example

<svg width="30" height="10"> <g fill="red"> <rect x="0" y="0" width="10" height="10" /> <rect x="20" y="0" width="10" height="10" /> </g> </svg> All following transformations are summed up in an element's transform attribute. Transformations can be chained by concatenating them, separated by whitespace.

Translation

It may be necessary to move an element around, even though you can position it with the according attributes. For this purpose, the translate() transformation stands ready. <svg width="40" height="50" style="background-color:#bff;"> <rect x="0" y="0" width="10" height="10" transform="translate(30,40)" /> </svg> The example will render a rectangle, translated to the point (30,40) instead of (0,0). If the second value is not given, it is assumed to be 0.

Rotation

Rotating an element is quite a common task. Use the rotate() transformation for this: <svg width="31" height="31"> <rect x="12" y="-10" width="20" height="20" transform="rotate(45)" /> </svg> This example shows a square that is rotated by 45 degrees. The value for rotate() is given in degrees.

Multiple transformations

Transformations can be concatenated easily just by separating them with spaces. For example, translate() and rotate() are common used transformations. <svg width="40" height="50" style="background-color:#bff;"> <rect x="0" y="0" width="10" height="10" transform="translate(30,40) rotate(45)" /> </svg> This example shows again the small square shown above that this time is also rotated by 45 degrees.

Skewing

To make a rhombus out of our rectangle, the skewX() and skewY() transformations are available. Each one takes an angle that determines how far the element will be skewed.

Scaling

scale() changes the size of an element. It takes two numbers, the first being the x scale factor and the second being the y scale factor. The factors are taken as the ratio of the transformed dimension to the original. For example, 0.5 shrinks by 50%. If the second number is omitted, it is assumed to be equal to the first.

Complex transformations with matrix()

All the above transformations can be expressed by a 2x3 transformation matrix. To combine several transformations, one can set the resulting matrix directly with the matrix(a, b, c, d, e, f) transformation which maps coordinates from a previous coordinate system into a new coordinate system by {xnewCoordSys=axprevCoordSys+cyprevCoordSys+eynewCoordSys=bxprevCoordSys+dyprevCoordSys+f\left{ \begin{matrix} x_{\mathrm{prevCoordSys}} = a x_{\mathrm{newCoordSys}} + c y_{\mathrm{newCoordSys}} + e \ y_{\mathrm{prevCoordSys}} = b x_{\mathrm{newCoordSys}} + d y_{\mathrm{newCoordSys}} + f \end{matrix} \right. See a concrete example on the SVG transform documentation. Detailed information about this property can be found in the SVG Recommendation.

Effects on Coordinate Systems

When using transformations you establish a new coordinate system inside the element the transformations apply to. That means, the units you specify for the element and its children might not follow the 1:1 pixel mapping, but are also distorted, skewed, translated and scaled according to the transformation. <svg width="100" height="100"> <g transform="scale(2)"> <rect width="50" height="50" /> </g> </svg> The resulting rectangular in the above example will be 100x100px. The more intriguing effects arise, when you rely on attributes like userSpaceOnUse and the such.

Embedding SVG in SVG

In contrast to HTML, SVG allows you to embed other svg elements seamlessly. This way you can also create new coordinate systems by utilizing the viewBox, width and height of the inner svg element. <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="100"> <svg width="100" height="100" viewBox="0 0 50 50"> <rect width="50" height="50" /> </svg> </svg> The example above has basically the same effect as the one above, namely that the rect will be twice as large as specified.


Clipping and masking

Erasing part of what one has created might at first sight look contradictory. But when you try to create a semicircle in SVG, you will find out the use of the following properties quickly. Clipping refers to removing parts of elements defined by other parts. In this case, any half-transparent effects are not possible, it's an all-or-nothing approach. Masking on the other hand allows soft edges by taking transparency and grey values of the mask into account.

 Creating clips

We create the above mentioned semicircle based on a circle element: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <clipPath id="cut-off-bottom"> <rect x="0" y="0" width="200" height="100" /> </clipPath> </defs> <circle cx="100" cy="100" r="100" clip-path="url(#cut-off-bottom)" /> </svg> Centered at (100,100) a circle with radius 100 is painted. The attribute clip-path references a <clipPath> element with a single rect element. This rectangular on its own would paint the upper half of the canvas black. Note, that the clipPath element is usually placed in a defs section. The rect will not be painted, however. Instead its pixel data will be used to determine, which pixels of the circle "make it" to the final rendering. Since the rectangle covers only the upper half of the circle, the lower half of the circle will vanish: We now have a semicircle without having to deal with arcs in path elements. For the clipping, every path inside the clipPath is inspected and evaluated together with its stroke properties and transformation. Then every part of the target lying in a transparent area of the resulting clipPath's content will not be rendered. Color, opacity and such have no effect as long as they don't let parts vanish completely.

 Masking

The effect of masking is most impressively presented with a gradient. If you want an element to fade out, you can achieve this effect quite quickly with masks. <svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <linearGradient id="Gradient"> <stop offset="0" stop-color="black" /> <stop offset="1" stop-color="white" /> </linearGradient> <mask id="Mask"> <rect x="0" y="0" width="200" height="200" fill="url(#Gradient)" /> </mask> </defs> <rect x="0" y="0" width="200" height="200" fill="green" /> <rect x="0" y="0" width="200" height="200" fill="red" mask="url(#Mask)" /> </svg> You see a green-filled rect at the lowest layer and on top a red-filled rect. The latter has the mask attribute pointing to the mask element. The content of the mask is a single rect element, that is filled with a black-to-white gradient. As a result the pixels of the red rectangle use the luminance value of the mask content as the alpha value (the transparency), and we see a green-to-red gradient as a result:

 Transparency with opacity

There is a simple possibility to set the transparency for a whole element. It's the opacity attribute: <rect x="0" y="0" width="100" height="100" opacity=".5" /> The above rectangle will be painted half-transparent. For the fill and stroke there are two separate attributes, fill-opacity and stroke-opacity, that control each of those property opacities separately. Note, that the stroke will be painted on top of the filling. Hence, if you set a stroke opacity on an element, that also has a fill, the fill will shine through on half of the stroke, while on the other half the background will appear: <svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <rect x="0" y="0" width="200" height="200" fill="blue" /> <circle cx="100" cy="100" r="50" stroke="yellow" stroke-width="40" stroke-opacity=".5" fill="red" /> </svg> You see in this example the red circle on blue background. The yellow stroke is set to 50% opacity, which leads effectively to a double-color stroke.

Using well-known CSS techniques

One of the most powerful tools in a web developer's toolbox is display: none. It is therefore not a surprise that it was decided to take this CSS property into SVG as well, together with visibility and clip as defined by CSS 2. For reverting a previously set display: none it is important to know, that the initial value for all SVG elements is inline.


Other content in SVG

Apart from graphic primitives like rectangles and circles, SVG offers a set of elements to embed other types of content in images as well.

 Embedding raster images

Much like the img element in HTML SVG has an image element to serve the same purpose. You can use it to embed arbitrary raster (and vector) images. The specification requests applications to support at least PNG, JPEG and SVG format files. The embedded picture becomes a normal SVG element. This means, that you can use clips, masks, filters, rotations and all other tools of SVG on the content: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"> <image x="90" y="-65" width="128" height="146" transform="rotate(45)" xlink:href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image/mdn_logo_only_color.png"/> </svg>

 Embedding arbitrary XML

Since SVG is an XML application, you can of course always embed arbitrary XML anywhere in an SVG document. But then you have no means to define how the surrounding SVG should react on the content. Actually, in a conforming viewer it will react in no way at all, the data will be omitted. Therefore the specification adds the <foreignObject> element to SVG. Its sole purpose is to be a container for other markup and a carrier for SVG styling attributes (most prominently width and height to define the space the object will take). The foreignObject element is a good way to embed XHTML in SVG. If you have longer texts, the HTML layout is more suitable and comfortable than the SVG text element. Another often cited use case is the embedding of formulas with MathML. For scientific applications of SVG this is a very good way to join both worlds. Note: Please keep in mind, that the content of the foreignObject must be processable by the viewer. A standalone SVG viewer is unlikely to be able to render HTML or MathML. Since the foreignObject is an SVG element, you can, like in the case of image, use any SVG goodness with it, which then will be applied to its content.


Filter effects

There are situations, where basic shapes do not provide the flexibility you need to achieve a certain effect. Drop shadows, to provide a popular example, cannot be created reasonably with a combination of gradients. Filters are SVG's mechanism to create sophisticated effects. A basic example is to add a blur effect to SVG content. While basic blurs can be achieved with the help of gradients, the blur filter is needed to do anything beyond.

Example

Filters are defined by <filter> element, which should be put in the <defs> section of your SVG file. Between the filter tags, goes a list of primitives, basic operations that build on top of the previous operations (like blurring, adding a lighting effect, etc). To apply your created filter on a graphic element, you set the filter attribute. <svg width="250" viewBox="0 0 200 85" xmlns="http://www.w3.org/2000/svg" version="1.1"> <defs> <!-- Filter declaration --> <filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="200" height="120"> <!-- offsetBlur --> <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/> <feOffset in="blur" dx="4" dy="4" result="offsetBlur"/> <!-- litPaint --> <feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75" specularExponent="20" lighting-color="#bbbbbb" result="specOut"> <fePointLight x="-5000" y="-10000" z="20000"/> </feSpecularLighting> <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/> <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litPaint"/> <!-- merge offsetBlur + litPaint --> <feMerge> <feMergeNode in="offsetBlur"/> <feMergeNode in="litPaint"/> </feMerge> </filter> </defs> <!-- Graphic elements --> <g filter="url(#MyFilter)"> <path fill="none" stroke="#D90000" stroke-width="10" d="M50,66 c-50,0 -50,-60 0,-60 h100 c50,0 50,60 0,60z" /> <path fill="#D90000" d="M60,56 c-30,0 -30,-40 0,-40 h80 c30,0 30,40 0,40z" /> <g fill="#FFFFFF" stroke="black" font-size="45" font-family="Verdana" > <text x="52" y="52">SVG</text> </g> </g> </svg>

 Step 1

<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/> <feGaussianBlur> takes in "SourceAlpha", which is the alpha channel of the source graphic, applies a blur of 4, and stores the result in a temporary buffer named "blur".

 Step 2

<feOffset in="blur" dx="4" dy="4" result="offsetBlur"/> <feOffset> takes in "blur", which we previously created, shifts the result 4 to the right and 4 to the bottom, and stores the result in the buffer "offsetBlur". The two first primitives just created a drop shadow.

 Step 3

<feSpecularLighting in="offsetBlur" surfaceScale="5" specularConstant=".75" specularExponent="20" lighting-color="#bbbbbb" result="specOut"> <fePointLight x="-5000" y="-10000" z="20000"/> </feSpecularLighting> <feSpecularLighting> takes in "offsetBlur", generates a lighting effect, and stores the result in the buffer "specOut".

 Step 4

<feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/> The first <feComposite> takes in "specOut" and "SourceAlpha", masks out the result of "specOut" so that the result is not bigger than "SourceAlpha" (the original source graphic), and overrides the result "specOut".

 Step 5

<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litPaint"/> The second <feComposite> takes in "SourceGraphic" and "specOut", adds the result of "specOut" on top of "SourceGraphic", and stores the result in "litPaint".

 Step 6

<feMerge> <feMergeNode in="offsetBlur"/> <feMergeNode in="litPaint"/> </feMerge> Finally, <feMerge> merges together "offsetBlur", which is the drop shadow, and "litPaint", which is the original source graphic with a lighting effect. Source graphic Source graphic Primitive 1 Primitive 1 Primitive 2 Primitive 2 Primitive 3 Primitive 3 Primitive 4 Primitive 4 Primitive 5 Primitive 5 Primitive 6 Primitive 6


SVG fonts

When SVG was specified, support for web fonts was not widespread in browsers. Since accessing the correct font file is however crucial for rendering text correctly, a font description technology was added to SVG to provide this ability. It was not meant for compatibility with other formats like PostScript or OTF, but rather as a simple means of embedding glyph information into SVG when rendered. Note: SVG Fonts are currently supported only in Safari and Android Browser. Internet Explorer hasn't considered implementing this, the functionality has been removed from Chrome 38 (and Opera 25) and Firefox has postponed its implementation indefinitely to concentrate on WOFF. Other tools however like the Adobe SVG Viewer plugin, Batik and parts of Inkscape support SVG font embedding. The base for defining an SVG font is the <font> element.

Defining a font

There are some ingredients required for embedding a font in SVG. Let's show an example declaration (the one from the specification), and explain the details. <font horiz-adv-x="1000"> <font-face font-family="Super Sans" font-weight="bold" font-style="normal" units-per-em="1000" cap-height="600" x-height="400" ascent="700" descent="300" alphabetic="0" mathematical="350" ideographic="400" hanging="500"> <font-face-src> <font-face-name name="Super Sans Bold"/> </font-face-src> </font-face> <missing-glyph><path d="M0,0h200v200h-200z"/></missing-glyph> <glyph unicode="!" horiz-adv-x="300"><!-- Outline of exclam. pt. glyph --></glyph> <glyph unicode="@"><!-- Outline of @ glyph --></glyph> <!-- more glyphs --> </font> We start with the <font> element. This bears an id attribute, to enable it to be referenced via a URI (see below). The horiz-adv-x attribute determines how wide a character is on average compared to the path definitions of the single glyphs. The value 1000 sets a reasonable value to work with. There are several accompanying attributes that help further define the basic glyph-box layout. The <font-face> element is the SVG equivalent of the CSS @font-face declaration. It defines basic properties of the final font such as weight, style, etc. In the example above the first and most important to be defined is font-family, the value of which can then be referenced in CSS and SVG font-family properties. The font-weight and font-style attributes have the same purpose as the equivalent descriptors in CSS. All following attributes are rendering instructions for the font layout engine, for example, how much of the glyphs' overall heights are ascenders. Its child, the <font-face-src> element, corresponds to CSS' src descriptor in @font-face declarations. You can point to external sources for font declarations by means of its children <font-face-name> and <font-face-uri>. The above example states that if the renderer has a local font available named "Super Sans Bold", it should use this instead. Following <font-face-src> is a <missing-glyph> element. This defines what should be displayed if a certain glyph is not found in the font and if there are no fallback mechanisms. It also shows how glyphs are created: By adding any graphical SVG content inside. You can use literally any other SVG elements in here, even <filter>, <a> or <script>. For simple glyphs, however, you can add a d attribute — this defines a shape for the glyph exactly like how standard SVG paths work. The actual glyphs are then defined by <glyph> elements. The most important attribute is unicode. It defines the unicode codepoint represented by this glyph. If you also specify the lang attribute on a glyph, you can further restrict it to certain languages (represented by xml:lang on the target) exclusively. Again, you can use arbitrary SVG to define the glyph, which allows for great effects in supporting user agents. There are two further elements that can be defined inside font: <hkern> and <vkern>. Each carries references to at least two characters (attributes u1 and u2) and an attribute k that determines how much the distance between those characters should be decreased. The below example instructs user agents to place the "A" and "V" characters closer together the standard distance between characters. <hkern u1="A" u2="V" k="20" />

Referencing a font

When you have put together your font declaration as described above, you can just use a simple font-family attribute to actually apply the font to some SVG text: <font> <font-face font-family="Super Sans" /> <!-- and so on --> </font> <text font-family="Super Sans">My text uses Super Sans</text> However, you are free to combine several methods for great freedom of how and where to define the font.

 Option: Use CSS @font-face

You can use @font-face to reference remote (and not so remote) fonts: <font> <!-- and so on --> </font> <style type="text/css"> @font-face { font-family: "Super Sans"; src: url(#Super_Sans); } </style> <text font-family="Super Sans">My text uses Super Sans</text>

 Option: reference a remote font

The above mentioned font-face-uri element allows you to reference an external font, hence allowing greater re-usability: <font> <font-face font-family="Super Sans"> <font-face-src> <font-face-uri xlink:href="fonts.svg#Super_Sans" /> </font-face-src> </font-face> </font>


SVG image element

The SVG <image> element allows for raster images to be rendered within an SVG object. In this basic example, a .jpg image referenced by an href attribute will be rendered inside an SVG object: <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="5cm" height="4cm" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <image href="firefox.jpg" x="0" y="0" height="50px" width="50px"/> </svg> There are some important things to take note of (referenced from the W3 specs): If you do not set the x or y attributes, they will be set to 0. If you do not set the height or width attributes, they will be set to 0. Having a height or width attribute of 0 will disable rendering of the image.


Tools for SVG

Now that we covered the basics of the SVG internals, we will take a look at some tools to work with SVG files.

 Browser support

As of Internet Explorer 9, all major browsers support SVG: IE 9, Mozilla Firefox, Safari, Google Chrome and Opera. Mobile devices with Webkit-based browsers also support SVG. On older or smaller devices, chances are that SVG Tiny is supported.

Inkscape

URL: www.inkscape.org One of the most important tools for a graphics format is a decent drawing program. Inkscape offers state-of-the-art vector drawing, and it's open source. Moreover, it uses SVG as its native file format. To store Inkscape specific data, it extends the SVG file with elements and attributes in a custom namespace, but you can also choose to export as plain SVG.

Adobe Illustrator

URL: www.adobe.com/products/illustrator/ Before Adobe acquired Macromedia, it was the most prominent promoter of SVG. From this time stems the good support of SVG in Illustrator. However, the resulting SVG often shows some quirks, that make it necessary to post-process it for general applicability.

Apache Batik

URL: xmlgraphics.apache.org/batik/ Batik is a set of open source tools under the roof of the Apache Software Foundation. The toolkit is written in Java and offers almost complete SVG 1.1 support, as well as some features that were originally planned for SVG 1.2. Batik offers a viewer (Squiggle), a rasterizer for PNG output, an SVG pretty printer to format SVG files, and a TrueType-to-SVG-Font converter. Together with Apache FOP Batik can transform SVG to PDF.

 Other renderers

Several projects exist that can create a raster image from an SVG source. ImageMagick is one of the most famous command-line image processing tools. The Gnome library rsvg is used by the Wikipedia to raster their SVG graphics. Usage of headless browsers such as SlimerJS and PhantomJS are also popular for this purpose, as the image produced is closer to what the SVG will look like in the browser.

Raphael JS

URL: raphaeljs.com This is a JavaScript library, that acts as an abstraction layer between browser implementations. Notably older versions of Internet Explorer are supported by generating VML, a vector markup language, that is one of two ancestors of SVG and exists since IE 5.5.

Snap.svg

URL: snapsvg.io A newer JavaScript abstraction layer from the same author of Raphael JS. Snap.svg is designed for modern browsers and therefore supports the newest SVG features like masking, clipping, patterns, full gradients, groups. It does not support the older browsers that Raphael does.

Google Docs

URL: www.google.com/google-d-s/drawings/ Drawings from Google Docs can be exported as SVG.

Science

The well-known plotting tools xfig and gnuplot both support exporting as SVG. To render graphs on the web JSXGraph supports VML, SVG and canvas, automatically deciding which technology to use based on browser capabilities. In GIS (Geographic Information System) applications SVG is often used as both storage and rendering format. See carto.net for details.

More tools!

The W3C offers a list of programs that support SVG.


SVG and CSS

This page illustrates the application of CSS to the specialized language for creating graphics: SVG. Below you'll create a simple demonstration that runs in your SVG-enabled browser. Note: Elements referenced by <use> elements inherit the styles from that element. So to apply different styles to them you should use CSS custom properties.

Example

Make a new SVG document as a plain text file, doc8.svg. Copy and paste the content from here, making sure that you scroll to get all of it: <svg width="600px" height="600px" viewBox="-300 -300 600 600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <title>SVG demonstration</title> <desc>Mozilla CSS Getting Started - SVG demonstration</desc> <defs> <radialGradient id="fade" cx="0" cy="0" r="200" gradientUnits="userSpaceOnUse"> <stop id="fade-stop-1" offset="33%"/> <stop id="fade-stop-2" offset="95%"/> </radialGradient> </defs> <text id="heading" x="-280" y="-270">SVG demonstration</text> <text id="caption" x="-280" y="-250">Move your mouse pointer over the flower.</text> <g id="flower"> <circle id="overlay" cx="0" cy="0" r="200" stroke="none" fill="url(#fade)"/> <g id="outer-petals"> <g class="quadrant"> <g class="segment"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(18)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(36)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(54)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(72)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> <g class="quadrant"> <g class="segment" transform="rotate(90)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(108)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(126)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(144)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(162)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> <g class="quadrant"> <g class="segment" transform="rotate(180)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(198)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(216)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(234)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(252)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> <g class="quadrant"> <g class="segment" transform="rotate(270)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(288)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(306)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(324)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(342)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> </g> <g id="inner-petals" transform="rotate(9) scale(0.33)"> <g class="quadrant"> <g class="segment"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(18)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(36)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(54)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(72)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> <g class="quadrant"> <g class="segment" transform="rotate(90)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(108)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(126)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(144)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(162)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> <g class="quadrant"> <g class="segment" transform="rotate(180)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(198)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(216)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(234)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(252)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> <g class="quadrant"> <g class="segment" transform="rotate(270)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(288)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(306)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(324)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g class="segment" transform="rotate(342)"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> </g> </g> </g> </svg> Make a new CSS file, style8.css. Copy and paste the content from here, making sure that you scroll to get all of it: /*** SVG demonstration ***/ /* page */ svg { background-color: beige; } #heading { font-size: 24px; font-weight: bold; } #caption { font-size: 12px; } /* flower */ #flower:hover { cursor: crosshair; } /* gradient */ #fade-stop-1 { stop-color: blue; } #fade-stop-2 { stop-color: white; } /* petals */ .segment-fill { fill: var(--segment-fill-fill); stroke: var(--segment-fill-stroke); stroke-width: var(--segment-fill-stroke-width); } .segment-fill:hover { fill: var(--segment-fill-fill-hover); stroke: var(--segment-fill-stroke-hover); } .segment-edge { fill: var(--segment-edge-fill); stroke: var(--segment-edge-stroke); stroke-width: var(--segment-edge-stroke-width); } .segment-edge:hover { stroke: var(--segment-edge-stroke-hover); } /* outer petals */ #outer-petals { opacity: .75; --segment-fill-fill: azure; --segment-fill-stroke: lightsteelblue; --segment-fill-stroke-width: 1; --segment-edge-fill: none; --segment-edge-stroke: deepskyblue; --segment-edge-stroke-width: 3; --segment-fill-fill-hover: plum; --segment-fill-stroke-hover: none; --segment-edge-stroke-hover: slateblue; } /* Non-standard way of styling elements referenced via <use> elements, supported by some older browsers */ #outer-petals .segment-fill { fill: azure; stroke: lightsteelblue; stroke-width: 1; } #outer-petals .segment-edge { fill: none; stroke: deepskyblue; stroke-width: 3; } #outer-petals .segment:hover > .segment-fill { fill: plum; stroke: none; } #outer-petals .segment:hover > .segment-edge { stroke: slateblue; } /* inner petals */ #inner-petals { --segment-fill-fill: yellow; --segment-fill-stroke: yellow; --segment-fill-stroke-width: 1; --segment-edge-fill: none; --segment-edge-stroke: yellowgreen; --segment-edge-stroke-width: 9; --segment-fill-fill-hover: darkseagreen; --segment-fill-stroke-hover: none; --segment-edge-stroke-hover: green; } /* Non-standard way of styling elements referenced via <use> elements, supported by some older browsers */ #inner-petals .segment-fill { fill: yellow; stroke: yellow; stroke-width: 1; } #inner-petals .segment-edge { fill: none; stroke: yellowgreen; stroke-width: 9; } #inner-petals .segment:hover > .segment-fill { fill: darkseagreen; stroke: none; } #inner-petals .segment:hover > .segment-edge { stroke: green; } Open the document in your SVG-enabled browser. Move your mouse pointer over the graphic to see what happens.

 Result

Notes about this demonstration: The SVG document links the stylesheet in the usual way. SVG has its own CSS properties and values. Some of them are similar to CSS properties for HTML.

 Challenge

Change the stylesheet so that the inner petals all turn pink when the mouse pointer is over any one of them, without changing the way the outer petals work. See a solution to this challenge.

Simplified structure

The SVG structure shown above could be written much more concise by referencing the individual parts of the flower via <use> elements. This behavior is standardized, though only a few browsers support the :hover pseudo-class and other more complex CSS selectors on elements referenced via <use> elements, at the moment. There is some discussion about what rules apply to such referenced elements. See below how the structure then looks like. <svg width="600px" height="600px" viewBox="-300 -300 600 600" xmlns="http://www.w3.org/2000/svg"> <title>SVG demonstration</title> <desc>Mozilla CSS Getting Started - SVG demonstration</desc> <defs> <g id="segment" class="segment"> <path class="segment-fill" d="M0,0 v-200 a40,40 0 0,0 -62,10 z"/> <path class="segment-edge" d="M0,-200 a40,40 0 0,0 -62,10"/> </g> <g id="quadrant"> <use xlink:href="#segment"/> <use xlink:href="#segment" transform="rotate(18)"/> <use xlink:href="#segment" transform="rotate(36)"/> <use xlink:href="#segment" transform="rotate(54)"/> <use xlink:href="#segment" transform="rotate(72)"/> </g> <g id="petals"> <use xlink:href="#quadrant"/> <use xlink:href="#quadrant" transform="rotate(90)"/> <use xlink:href="#quadrant" transform="rotate(180)"/> <use xlink:href="#quadrant" transform="rotate(270)"/> </g> <radialGradient id="fade" cx="0" cy="0" r="200" gradientUnits="userSpaceOnUse"> <stop id="fade-stop-1" offset="33%"/> <stop id="fade-stop-2" offset="95%"/> </radialGradient> </defs> <text id="heading" x="-280" y="-270">SVG demonstration</text> <text id="caption" x="-280" y="-250">Move your mouse pointer over the flower.</text> <g id="flower"> <circle id="overlay" cx="0" cy="0" r="200" stroke="none" fill="url(#fade)"/> <use id="outer-petals" xlink:href="#petals"/> <use id="inner-petals" xlink:href="#petals" transform="rotate(9) scale(0.33)"/> </g> </svg>

What next?

In this demonstration, your SVG-enabled browser already knows how to display SVG elements. The stylesheet only modifies the display in certain ways. This is also true for HTML and XUL documents. But you can use CSS for general-purpose XML documents, where there is no predefined way to display the elements. The next page demonstrates this: XML data