SVG is the web graphics tool

While CSS has added features to shape, style and transform elements so that it can do some things SVG can, it still seems that in many cases there is no substitute for SVG.
SVG can do logos, complex graphics and element backgrounds in a ways not possible with other tools.

SVG scales

One of the key reasons to use SVG is that since it uses vector graphics instead of bitmaps (images are bitmaps) it can scale infinitely up or down, in concept, without loss of features and appearance. This means very large graphics can be very small file size wise compared to an image.

Viewport is a very useful argument

The reason viewport is so important is that SVG elements have a size that determines their space on a page like all other html elements, but then all of the svg shapes/paths they contain use a separate Svg coordinate system. If the size of the element changes, it will display the Svg that fits the element size.

Viewbox tells SVG to always display the same coordinates

In this example the svg element has been given height/width that would cut the shapes normally because they fall outside a width/height of 20/30. With the viewBox set to 0-50 for x and y, the circles will be displayed correctly but scaled down. This is used for anything you want to always scale to size.

  <svg width: '20px' height='30px'viewBox="0 0 50 50" version="1.1" xmlns="http://www.w3.org/2000/svg" >
    <circle cx="20" cy="20" r="15" fill="orange" />
    <circle cx="30" cy="30" r="15" fill="red" />
  </svg>

Designing SVG directly in your html is hard

If you want to make anything more than simple shapes/curves/arcs, it is hard to do this by writing out the path equations directly. I find even basic bezier curves hard to reason about just using coordinates.

So use and SVG editor and export the design

The best approach I have found is to use a dedicated SVG editing tool like InkScape or Illustrator. Do the full design there, and then export it and use it in your website.

Exporting usable SVG from Inkscape

Inkscape is an open source SVG editor and I use it when I need to put together a design. The default format is Inkscape SVG, which won’t work in an html context. You can switch to optimized format which in most cases should be directly usable however.

File > Save As > Optimized SVG  

An options dialog will pop up with a bunch of options. I usually try and make the output file as simple as possible so I check:

  • Collapse Groups
  • Create Groups for Similar Attributes
  • Remove Metadata/Comments
  • Remove Unused IDs
  • Convert CSS attributes
  • And select a resonable # of significant digits.

Then use the contents of that save

The saved contents are an <svg> that you can put right into your site. You can also then edit simple aspects like fill/stroke manually to change the appearance manually without needing to edit in the software and export each time.

Optimized File example

I put this amorphous blob together in a minute or so using Inkscape. A path of this fairly simple complexity would take far more time to do without the editor. These are the exact contents of my quick example file. The viewbox was set by Inkscape.

<svg width="113.3mm" height="82.34mm" version="1.1" viewBox="0 0 113.3 82.34" xmlns="http://www.w3.org/2000/svg">
  <g transform="translate(-36.86 -9.398)">
    <path d="m96.19 81.35c-22.05-5.714-10.49-19.28-19.09-21.73-8.375-5.135-15.76 9.564-24.57 6.048-0.6956 1.67-11.11-11.65-14.93-17.2-2.261-3.284 2.293-21 5.67-24 0.3831-0.3408 21.82-14.29 26.46-13.23 1.878 0.4313 63.43-1.775 64.63-1.701 17.5 1.081 19.29 27.22 10.39 28.73-14.41 2.438-66.5-23.72-61.04-13.99-1.73 4.942 26.37 20.91 33.83 21.36 11.96 0.7195 28.59 39.1 27.03 40.63-9.048 14.85-22.87-5.062-35.15-13.8-3.256-5.063-6.531-3.658-10.21 1.512-2.232 2.273 1.978 8.031-3.024 7.371z" fill="#2c2c2c" stroke="#000" stroke-width=".2646px"/>
  </g>
</svg>

Using SVG in backgrounds vs directly

The two most common ways I deploy SVGs are to either use them as elements directly, or to embed them in the background of other elements. When I want to place SVG I usually first decide which of these methods to use.

Using directly allows CSS interaction, flexibility

If I want the SVG to have hover effects or interactivity I use a stand alone SVG element, becuase it can take CSS parameters like any other element. So for something like a hoverable button or icon, I will use an SVG element.

Background SVG is hard to change, but easier to layer

Putting SVG in the background of an element makes it much harder to change it, but allows taking advantage of stacked background colors/images/SVG to form more layered and complex visuals. Therefore I use SVG in element backgrounds when I am focused on the visual end result as opposed to any sort of interavtivity or modifications to the SVG.

Putting SVG in the background in React

There are a couple ways to do it. First way is just to have the svg somewhere and load it directly.

// React version
const backgroundplus = {   
  backgroundImage: `url(/path/to/image.svg)`,  
  borderColor: '#f2f3f4',  
}
// Plain CSS should be about the same
{   
  background-image: url(/path/to/file.svg);
  border-color: '#f2f3f4';
}

You can also inline it

To do this I use a function to set up the SVG and another to encode it to base64 for passing to the element. Then I use the same url() CSS function to get the information from this. I usually use this setup if I have many smaller SVG drawings and want to put them all in a single JS file, like a library so that I can easily pass it around.

// Set up the svg
const svgwrap = R.curry((path, width, height) => {  
  return ( `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"   
> ${path} </svg>` )  
})
// An encoding function that transforms the svg to base64 and indicates
// this in the heading.
const svgtobase64 = (svg) => {
  return R.concat('data:image/svg+xml;base64,')(btoa(svg)) 
}

Then write the SVG and use the functions

Here is a simple case with a plus symbol. I write out the path for the symbol, then pass that to an svg path

let plus = "M55,55 v -35 h 10 v 35 h 35 v 10 h -35 v 35 h -10 v -35 h -35 v -10 h   
let darkplus = formEncodedSvg(`<path fill="#212f3c" d="${plus}" />`)  
// And then the CSS; 
// The React style object
const backgroundplus = {   
  backgroundImage: `url(${darkplus})`,  
  borderColor: '#f2f3f4',  
}

Fun stuff; animations for shape, color

SVG can do some pretty neat animations using SMIL (Synchronized Multimedia Integration Language).

Note on SMIL deprecation

SMIL was deprecated by Chrome, then they suspended that decision. I currently use it if nothing else will work because the deprecation was suspended because it still does thing CSS won’t. The indication is that it will remain supported until there are alternate ways to do most of what SMIL does.

What SMIL does CSS wont

Two things I noted were that color gradients can be easily animated and shapemorphing can be animated where one shape seamlessly changes to the next.

A morphing, rotating path

My example is a React component, but the critical part to making this work regardless of your setting is to use <animate> on different version of a path, but make sure they all have the same number of points.

// A cone shape object that shifts and can be filled
// rotate argument configures transform rotation. 
// dur argument configures length of animation loop
// fill and filter arguments configure coloration.
const GlowCurveShift = (props) => {
  return (
    <path filter={`url(${props.filter})`} fill={`url(#${props.fill})`} transform={`${props.transform}`} >
     <animate attributeName='d' 
       values="
         M 50 250 
         C 30,220 20,200 30,145 
         60,140 110,140 160,140 
         160,200 160,230 160,280 
         130,280 70,280 50,250;

         M 40 240 
         C 40,200 30,180 50,140 
         90,130 90,130 160,140 
         150,190 160,230 145,290 
         130,280 90,270 40,240;

         M 50 240 
         C 40,190 40,150 40,150 
         40,150 140,160 160,140 
         140,160 160,230 155,300 
         110,300 80,290 50,240;

         M 50 250 
         C 30,220 20,200 30,145 
         60,140 110,140 160,140 
         160,200 160,230 160,280 
         130,280 70,280 50,250;
         "
         dur={`${props.dur}s`} repeatCount="indefinite" />
     <animateTransform attributeName='transform' type='rotate' values={`${props.rotate} 150 150; ${props.rotate + 360} 150 150`} dur='74s' repeatCount='indefinite' /> 
    </path >
  )
}

Animating a gradient

This is a SVG <linearGradient> element, but for each stop the color values are animated. Also a react element, so if you wanted to use this in plain html, replace all the arguments with literal values. The colstart/colend define the color the gradient will start at, go to, and then return to the start.

// Creates an animated gradient to apply as element fill.
// Id argument specifies how the name for using the gradient.
// Takes a start and and color for the gradient, and then also an
// intermediate color for each of those to animate the ends.
// Also takes x1/x2/y1/y2 to specify gradient directionality
// dur1 and dur2 allow configuring the timing of the gradient start/end
const AnimateGradient = ({id, colstart, colend, startinter, endinter, x1,x2,y1,y2, dur1, dur2}) => {
  return(
    <linearGradient id={id} x1={x1} x2={x2} y1={y1} y2={y2}>
      <stop offset="0%" stopColor={colstart} >
        <animate attributeName="stop-color" values={`${colstart}; ${startinter}; ${colstart};`} dur={`${dur1}s`} repeatCount="indefinite" />
      </stop>
      <stop offset="100%" stopColor={colend} >
        <animate attributeName="stop-color" values={`${colend}; ${endinter}; ${colend};`} dur={`${dur2}s`} repeatCount="indefinite" />
      </stop>
    </linearGradient>
  )
}

Putting it together

Swirling color demo
Makes for some interesting possibilities to put some of these together. The problem was that it seemed to be very resource intensive and so it was not practical to use one of this complexity unless you want to test user’s machine capabilities.

Filters in Svg allow more complex patterns/textures

Creating surface texture/pattern for SVG and modifying imported images is possible using SVG filters. Filters are defined using the <filter> element and one of its specific filter sub elements, and then applied to an element using the filter= argument.
Here is a simple example applying blur to an ellipse.

   <filter x="-50%" y="-30%" width="200%" height="160%" id="blurMe">
     <feGaussianBlur  stdDeviation="15"/>
   </filter>

    <ellipse filter="url(#blurMe)" cx='150' cy='70' rx='20' ry='90' fill='url(#blue1)' >
    </ellipse >

Filters I find useful

<feGaussianBlur /> and <feTurbulence /> are two I see as useful because they can add blurring/randomness to objects. I just happen to find I am usually trying to blur/randomize to add either transitions or texture, so this is heavily use dependent. <feMorphology /> - This one is designed to thicken/thin, so this would be analagous to grow/shrink type functions. <feOffset /> - offset an object, like a translate parameter. <feDisplacement />- randomized displacement, like splattered edges.

Using filter notes

Filter area - The filter example above show the x/y width/height of the filter. This is important because by default the filter region is the same as the object being filtered, and any spread/splatter will hit the edges and look bad. Adjust the filter area to accomodate the result of your filter.

Filter shortcomings

I had a few instances when experimenting with filters where the effect varied between browsers. I had a difficult time determining what I was doing to cause the difference, though, so I don’t have a clear rule on how to avoid this.