SVG
💊

SVG

Basic shapes

SVG and Canvas

SVG
  • Resolution independent.
  • Supports event handlers.
  • Not suitable for game applications.
  • SVG is an XML-based description of graphics.
  • Most suitable for applications with large rendering areas, such as Google Maps.
  • High complexity will slow down the rendering speed, and any application that overuses DOM will not be fast.
  • Exists independently as a single file, with the suffix .svg, which can be directly imported into html.
  • SVG is based on XML, which means that every element in the SVG DOM is available and can attach JavaScript event handlers to a particular element.
  • In SVG, each drawn graphic is treated as an object, and if the properties of the SVG object change, the browser can recreate the graphic on its own.

canvas

  • Depend on resolution.
  • Text rendering is weak.
  • Does not support event handlers.
  • Canvas is rendered pixel by pixel.
  • Canvas is drawn with JavaScript.
  • Can save the result graphics in .png or .jpg format.
  • Most suitable for image-intensive games, where many objects will be frequently redrawn.
  • Once the graphics are drawn in Canvas, they will no longer receive attention from the browser. If their position changes, the graphics need to be redrawn, including any objects that have been covered by the graphics.

Postion system in SVG

<text x=”20” y=”20%”>SVG Text</text>
Percentages are relative to the viewBox of the nearest <svg> or <symbol> element (or the actual width and height if no viewBox was given).

transform

<text transform="translate(10,64)">SVG Text</text>
it can only accepts use-unit values for translations, not the presentage
 

Sizing

<text transform="scale(4,1)">SVG Text</text>
 

Reuse part of the SVG shapes

Create SVG symbol objects and include them with SVG use. This way, we can define the SVG icon library in HTML and instantiate and customize it in React as needed.
XML
<!-- Definition -->
<svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
  <symbol id="myIcon" width="24" height="24" viewBox="0 0 24 24">
      <!-- ... -->
  </symbol>
  <!-- ... --> 
</svg>

<!-- Usage -->
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  <use href="#myIcon" />
</svg>
 
 
HTML
<svg width="400" height="400">
  <line x1="2" y1="2" x2="400" y2="400" stroke="green"></line>
  <rect height="150" width="150" y="100" x="100" fill="red" stroke="blue"></rect>
</svg>
 
notion image
CSS
element.style {
    width: 200px;
}

rect[Attributes Style] {
    height: 150;
    width: 150;
    y: 100;
    x: 100;
    fill: red;
    stroke: blue;
}
The css style will overwrite the attributes styles
 
Tag Name
Description
Example
<svg>
This tag is the root container for all SVG elements.
<svg width="500" height="500"></svg>
<circle>
This tag is used to draw circles.
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/>
<ellipse>
This tag is used to draw ellipses.
<ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2"/>
<line>
This tag is used to draw lines.
<line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2"/>
<polygon>
This tag is used to create a graphic that contains at least three sides.
<polygon points="200,10 250,190 160,210" style="fill:lime;stroke:purple;stroke-width:1"/>
<polyline>
This tag is used to create any shape that consists of straight lines.
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180" style="fill:none;stroke:black;stroke-width:3"/>
<rect>
This tag is used to draw rectangles.
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)"/>
<text>
This tag is used to create text.
<text x="0" y="15" fill="black">This is SVG text</text>
<path>
This tag is used to define a path.
<<svg height="400" width="400"> <!-- Cat face --> <circle cx="200" cy="200" r="100" stroke="black" stroke-width="4" fill="lightgrey" /> <!-- Eyes --> <circle cx="150" cy="180" r="20" stroke="black" stroke-width="2" fill="green" /> <circle cx="250" cy="180" r="20" stroke="black" stroke-width="2" fill="green" /> <!-- Nose --> <polygon points="190,230 210,230 200,250" style="fill:pink;stroke:black;stroke-width:2" /> <!-- Mouth --> <path d="M150 260 Q 200 290 250 260" stroke="black" fill="transparent"/> <path d="M150 260 Q 200 280 200 260" stroke="black" fill="transparent"/> <path d="M250 260 Q 200 280 200 260" stroke="black" fill="transparent"/> <!-- Whiskers --> <line x1="120" y1="270" x2="180" y2="270" style="stroke:black;stroke-width:2" /> <line x1="220" y1="270" x2="280" y2="270" style="stroke:black;stroke-width:2" /> <line x1="130" y1="290" x2="170" y2="280" style="stroke:black;stroke-width:2" /> <line x1="230" y1="280" x2="270" y2="290" style="stroke:black;stroke-width:2" /> </svg> d="M150 0 L75 200 L225 200 Z"/>
<g>
This tag is used to group SVG shapes together.
<g fill="black"><circle cx="50" cy="50" r="30"/><circle cx="70" cy="70" r="30"/></g>
<defs>
This tag is used to store graphical objects that will be used at a later point. These objects should be defined inside the <defs> element.
<defs><radialGradient id="grad1" cx="50%" cy="50%" r="50%" fx="50%" fy="50%"><stop offset="0%" style="stop-color:rgb(255,255,255); stop-opacity:0" /><stop offset="100%" style="stop-color:rgb(0,0,255); stop-opacity:1" /></radialGradient></defs>
<marker>
This tag is used to define marker or arrowhead shapes that can be later used by a <path>, <line>, <polyline> or <polygon> element.
<marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#f00" /></marker>
<pattern>
This tag is used to define patterns that can be used to fill or stroke SVG shapes.
<pattern id="patt1" patternUnits="userSpaceOnUse" width="100" height="100"><image href="image.jpg" x="0" y="0" width="100" height="100" /></pattern>
<mask>
This tag is used to define an alpha mask for compositing the current object into the background.
<mask id="m1" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox"><circle cx=".5" cy=".5" r=".4" fill="white" /></mask>
<clipPath>
This tag is used to define a clipping path, to be used by the clip-path property.
<clipPath id="myClip"><circle cx="50" cy="50" r="50" /></clipPath>
<image>
This tag allows an external graphic to be included in the SVG.
<image href="image.jpg" height="200" width="200"/>
<a>
This tag is used to make a shape or text clickable, much like in HTML.
<a href="https://www.example.com"><text x="0" y="15" fill="black">Click me</text></a>
<use>
This tag is used to reuse an element that is defined elsewhere in the SVG.
<use href="#myCircle" fill="blue"/>

Path

  • M moves the pen to a new location without drawing a line. It requires two parameters for the x and y coordinates. In this case, it moves the pen to the coordinates (150, 0).
  • L draws a line from the current position to the new position. Again, two parameters are needed for the x and y coordinates. Here, it draws lines to the points (75, 200) and then (225, 200).
  • Z closes the path by drawing a straight line back to the starting point.
Here is a more detailed tutorial about how to use the <path> tag:
  1. Move To - M/m
      • The M command is used to move the pen (without drawing anything). It takes two numbers, or parameters: x and y. For example, M 10 10 would move the pen to the point (10,10) on the grid.
      • If you use the lowercase m, it will move the pen relative to the last point. If the pen was at (30,30), the command m 10 10 would move the pen to (40,40).
  1. Line To - L/l
      • The L command is used to draw a line from the current point to a new point. It takes two parameters: x and y. For example, if the pen is currently at (10,10), the command L 20 20 would draw a line to the point (20,20).
      • If you use the lowercase l, it will draw a line relative to the current point. If the pen was at (30,30), the command l 10 10 would draw a line to (40,40).
  1. Horizontal Line To - H/h and Vertical Line To - V/v
      • The H and V commands are used to draw horizontal and vertical lines, respectively. Each takes one parameter. If the pen is currently at (10,10), H 20 would draw a horizontal line to (20,10), and V 20 would draw a vertical line to (10,20).
      • The lowercase h and v are used to draw lines relative to the current point.
  1. Cubic Bézier Curve - C/c and S/s
      • The C command is used to draw a cubic Bézier curve. It takes six parameters: x1 y1, x2 y2, x y (control points and end point). For example, C 20 20, 40 20, 50 10 would draw a curve from the current point to (50,10) using (20,20) and (40,20) as the control points.
      • The S command is a shorthand command for C. It takes four parameters and the first control point is assumed to be a reflection of the second control point on the previous command relative to the current point.
      • The lowercase c and s draw curves relative to the current point.
  1. Quadratic Bézier Curve - Q/q and T/t
      • The Q command is similar to C, but it draws a quadratic Bézier curve. It takes four parameters: x1 y1, x y (control point and end point).
      • The T command is a shorthand command for Q. It takes two parameters and the control point is assumed to be a reflection of the control point on the previous command relative to the current point.
      • The lowercase q and t draw curves relative to the current point.
  1. Close Path - Z/z
      • The Z command is used to close the path. It does not take any parameters. It draws a straight line from the current point to the start point.
       
Want the transformation to relate to the element itself rather than the entire SVG canvas.
In SVG, transform-box and transform-origin are properties used to control the behavior of transformations such as scaling, rotation, and skewing.
Here's a breakdown of each:
  1. transform-box: This property defines the layout box to which the transform and transform-origin properties relate. It takes the following values:
      • view-box: The bounding box is equivalent to the SVG's view box. This is the initial value.
      • fill-box: The bounding box is equivalent to the object's fill area.
      • stroke-box: The bounding box is equivalent to the object's stroke area.
  1. transform-origin: This property sets the origin for an element's transformations. It takes two values that determine the x and y coordinates of the origin:
      • X% Y%: The origin of transformation is positioned at X% across, Y% down relative to the element.
      • Xpx Ypx: The origin of transformation is positioned at X pixels across, Y pixels down relative to the element.
      It can also accept keywords 'top', 'bottom', 'left', 'right', and 'center' for both X and Y positions.
       
       
SVG animations can be done in a few different ways. You can use CSS animations, JavaScript, or SMIL (Synchronized Multimedia Integration Language) which is a native SVG animation syntax.
Here is an example of each:
1. CSS Animations:
HTML
<svg width="100" height="100" viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="45" fill="blue" class="myCircle"/>
</svg>

<style>
  .myCircle {
    animation: pulse 1s infinite;
  }

  @keyframes pulse {
    0% {
    fill: blue;
  }
  50% {
    fill: red;
  }
  100% {
    fill: blue;
  }
}
</style>
This animation will make the circle continuously change its color from blue to red and back again, every second.
2. JavaScript:
HTML
<svg id="mySvg" width="100" height="100" viewBox="0 0 100 100">
  <circle id="myCircle" cx="50" cy="50" r="45" fill="blue"/>
</svg>

<script>
  let circle = document.getElementById('myCircle');

  setInterval(() => {
    if (circle.getAttribute('fill') === 'blue') {
      circle.setAttribute('fill', 'red');
    } else {
      circle.setAttribute('fill', 'blue');
    }
  }, 1000);
</script>
This JavaScript animation will achieve the same effect as the CSS animation above, but using a different method.
3. SMIL:
HTML
<svg width="100" height="100" viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="45">
    <animate attributeName="fill" values="blue;red;blue" dur="1s" repeatCount="indefinite" />
  </circle>

	<rect x="50" y="50" width="100" height="100" fill="lime">
	    <animateTransform 
	      attributeName="transform"
	      type="rotate"
	      from="0 100 100"
	      to="360 100 100"
	      dur="2s"
	      repeatCount="indefinite"/>
	  </rect>
</svg>
SMIL allows you to animate SVG elements directly within the SVG syntax itself. This SMIL animation will produce the same effect as the previous two examples.
Please note that support for SMIL is not universal across all web browsers (it's not supported in IE, and its future support in Chrome has been uncertain). For this reason, many developers prefer using CSS or JavaScript for SVG animations.
 
HTML
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <path
    id="motionPath"
    d="M 10 80 Q 52.5 10, 95 80 T 180 80"
    fill="none"
    stroke="lightgrey"
  />

  <circle r="5" fill="red">
    <animateMotion dur="4s" repeatCount="indefinite" rotate="auto">
      <mpath href="#motionPath" />
    </animateMotion>
  </circle>
</svg>
 

Example

Drag a ball on a curved path
HTML
<!DOCTYPE html>
<html>
  <head>
    <style>
      /* Styling for the draggable ball and the motion path */
      #ball {
        cursor: pointer; /* Changes the cursor to a hand when hovering over the ball */
        fill: red;
      }
      #motionPath {
        fill: none;
        stroke: lightgrey;
      }
    </style>
  </head>
  <body>
    <svg id="svg" width="500" height="500">
      <path id="motionPath" d="M 10 80 Q 52.5 10, 95 80 T 180 80" />
      <!-- The path the ball will move along -->
      <circle id="ball" r="5" />
      <!-- The ball that will be dragged -->
    </svg>

    <script>
      // Getting the path and ball elements from the SVG
      const path = document.getElementById('motionPath');
      const ball = document.getElementById('ball');

      // Calculating the total length of the path
      const pathLength = path.getTotalLength();

      // Initializing the current and target positions along the path
      let currentLength = 0;
      let targetLength = 0;

      // Function to set the position of the ball on the path
      function setPosition(length) {
        // Getting the point at a specified length along the path
        const point = path.getPointAtLength(length);

        // Setting the position of the ball to the point
        ball.setAttribute('cx', point.x);
        ball.setAttribute('cy', point.y);
      }

      // Function to smoothly animate the ball towards the target position
      function animate() {
        // If the current and target positions are not close
        if (Math.abs(targetLength - currentLength) > 0.1) {
          // Move the current position a bit closer to the target position
          currentLength += (targetLength - currentLength) * 0.2;

          // Update the position of the ball
          setPosition(currentLength);

          // Request the next frame of the animation
          requestAnimationFrame(animate);
        }
      }

      // Setting the initial position of the ball
      setPosition(currentLength);

      // When the ball is pressed
      ball.addEventListener('mousedown', function(event) {
        // Function to move the ball when the mouse is moved
        function onMouseMove(event) {
          // Getting the position of the SVG relative to the page
          const rect = svg.getBoundingClientRect();

          // Getting the position of the mouse relative to the SVG
          const x = event.clientX - rect.left;
          const y = event.clientY - rect.top;

          // Initializing the shortest distance to Infinity
          let minDist = Infinity;

          // Looping over points along the path
          for (let length = 0; length <= pathLength; length += pathLength / 1000) {
            // Getting the point at the current length
            const point = path.getPointAtLength(length);

            // Calculating the distance from the mouse to the point
            const dx = x - point.x;
            const dy = y - point.y;
            const dist = Math.sqrt(dx * dx + dy * dy);

            // If the distance is shorter than the current shortest distance
            if (dist < minDist) {
              // Update the shortest distance and target position
              minDist = dist;
              targetLength = length;
            }
          }

          // Start the animation towards the target position
          animate();
        }

        // When the mouse is moved, move the ball
        svg.addEventListener('mousemove', onMouseMove);

        // When the mouse button is released
        svg.addEventListener('mouseup', function() {
          // Stop moving the ball
          svg.removeEventListener('mousemove', onMouseMove);
        }, {once: true});
      });
    </script>
  </body>
</html>

Text

All the text need to be put into the <text> tag to be able to show it.
💡
The y="0" default value can position text above the SVG if using the default top-left origin.
💡
Default font-size should be 16px (medium) on most browsers. But it is also safe to set a font size for text
💡
In CSS-styled HTML, the color property sets the color of the text letters. However, in SVG text, the color is controlled by the same fill property used to set the color of SVG shapes.
To set the font-size property in SVG, you can use either CSS rules with the same syntax as for HTML(The using method is same as css) or define the font-size presentation attribute. For font-size presentation attribute, we can also set unit value.

css properties used to style text

  • font-family, font-size, font-size-adjust, font-stretch, font-style, font-variant, and font-weight for selecting and scaling the font data
  • text-shadow for blurring or adding an offset copy behind the main text
  • text-transform for converting to uppercase, lowercase, or cap‐ italized words
  • text-decoration for adding underlines, overlines, and strike- throughs
  • direction and unicode-bidi to control multidirectional language
  • letter-spacing and word-spacing to adjust text spacing
  • Use values such as keywords, hex colors (e.g. #080844 or #fab), or functions like rgb(20, 100, 128) or hsla(0,80%,75%,0.7) for fill and stroke or a url() reference to the id of an SVG paint server (gradient or pattern element).

Text effects

XML
<svg
  width="4in"
  height="0.8in"
  viewBox="0 0 400 80"
>
  <title>Filter Effects on SVG Text</title>
  <style type="text/css">
    text {
      font: bold 64px Verdana, Geneva, sans-serif;
      text-decoration: underline;
      fill: darkBlue;
      stroke: indigo;
      filter: url(#shine);
    }
  </style>
  <defs>
    <filter id="shine">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2" result="blur" />
      <feColorMatrix
        values="1.5 0 0 0.5 0 0 1.5 0 0.5 0 0 0 1.5 0.5 0
  0 0 0 1 -0.5"
      />
      <feOffset dx="-2.5" dy="-1.5" />
      <feComponentTransfer result="highlight">
        <feFuncA type="linear" amplitude="2" />
      </feComponentTransfer>
      <feComposite
        in="blur"
        in2="highlight"
        operator="arithmetic"
        k1="0"
        k2="1"
        k3="1"
        k4="0"
      />
      <feComposite in2="SourceGraphic" operator="atop" />
    </filter>
  </defs>
  <rect width="100%" height="100%" fill="lightYellow" />
  <text x="10" y="80%">SVG Text</text>
</svg>
notion image
 
Painted Effects (similar to background-clip: text in html css)
XML
<svg
  xml:lang="en"
  height="50px"
  width="410px"
>
  <title>Gradient-Filled Text</title>
  <defs>
    <linearGradient id="fade">
      <stop stop-color="orange" stop-opacity="1" offset="0" />
      <stop stop-color="orange" stop-opacity="0" offset="1" />
    </linearGradient>
  </defs>
  <g
    transform="translate(10,40)"
    style="
      font-family: Arial;
      font-weight: bold;
      font-size: 24pt;
      fill: url('#fade');
    "
  >
    <text>A Whiter Shade of Pale</text>
  </g>
</svg>
 
notion image
 

Text segments

To apply different styles to part of the text <tspan class="em" dy="-0.5cm" >One</tspan>
There are four positioning attributes for SVG text: x, y, dx, and dy. The first two declare absolute positions within the coordinate system, while the latter two declare differences in position that should be added to the otherwise applicable position.
Or
<text x="0 1.0in 1.6in 2.2in 3.0in 3.6in"
y="0.8in 0.4in 0.8in 0.4in 0.8in 0.4in"
>Wiggle</text>
which can specific multi words position

Aria label

<text xml:lang="la" role="heading" aria-level="2" x="190" y="480">Lilium montanum</text>

Color

linearGradient
XML
<linearGradieny x1="0" y1="0" x2="100%" y2="100%">
  <stop stop-color="blue" offset="0" />
  <stop stop-color="darkSeaGreen" offset="1" />
</linearGradient>

JS manuplate

create the element
JavaScript
const rect = document.createElementNS(
    'http://www.w3.org/2000/svg',
    'rect'
  );

Pitfall

The transform origin is relative to the parent SVG element's viewbox, not the element itself. Therefore, if we set transform-origin: center center, the transformation will use the center coordinates of the parent SVG, not the path element.
Setting a transform-box property to fill-box
CSS
.body {
  animation: sparkle 0.15s 1s steps(2, jump-none) infinite alternate;
  transform-box: fill-box;
  transform-origin: center center;
}

Tools

Reduce the SVG size
svgo
svgUpdated Oct 18, 2024
 
 

SVG manupliate