SVG Guidelines
==============

Pros and cons of SVG for images
-------------------------------

When used as a document format there is usually a compelling reason that
makes SVG the only solution. When used as an `image
format <https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_as_an_Image>`__,
it is sometimes less obvious whether it would be best to use SVG or a
raster image format for any given image. The vector format SVG and
raster formats like PNG both have their place. When choosing whether or
not to use SVG it is best to understand the advantages and disadvantages
of both.

File size
   Whether SVG or a raster format will produce a smaller file for a
   given image depends very much on the image. For example, consider an
   image of a path with a gradient fill. The size of an SVG of this
   image will be the same regardless of the dimensions of the image. On
   the other hand the size of a raster file of the same image will
   likely vary tremendously depending on the dimensions of the image
   since the larger the dimensions the more pixel data the file needs to
   store. At very small dimensions (the extreme case being 1px x 1px)
   the raster file will likely be much smaller than the SVG file since
   it only needs to store one pixel of data. At large dimensions the
   raster file may be much larger than the SVG file.
Scalability, with caveats
   One of the primary advantages of SVG is that as it is scaled it does
   not pixelate. However, this is not to say that it always does away
   with the need to have a collection of raster images for display at
   different scales. This can be particularly true for icons. While SVG
   may scale well enough for flat-ish icons without a lot of detail, for
   icons that try to pack in a lot of detail graphic artists generally
   `want to be able to pixel
   tweak <https://www.pushing-pixels.org/2011/11/04/about-those-vector-icons.html>`__.
Performance
   While SVG provides a lot of flexibility in terms of scaling,
   themability, etc. this flexibility depends on doing computations for
   SVG images at the time they're displayed, rather than at the time the
   author creates them. Consider an image that involves some complex
   gradients and filters. If saved as a raster image then the work to
   rasterize the gradients and filters takes place on the authors
   computer before the result is stored in the raster file. This work
   doesn't need to be redone when the image is displayed on someone
   else's computer. On the other hand, if the image is saved as an SVG
   image then all this work needs to be done each time the SVG is
   displayed on someone else's computer. This isn't to say that SVG
   images are always slower than raster equivalents. In fact it can be
   faster to send vector information from an SVG to a user's GPU than it
   is to extract raster data from an equivalent raster image. And even
   when an SVG image is slower than a raster equivalent, the difference
   is usually not noticeable. However, just don't fall into the trap of
   thinking that SVGs are faster than equivalent raster images, or vice
   versa. Once again, "it depends".

Authoring guidelines
--------------------

A lot of SVG files (particularly those generated by SVG editors) ship
without being cleaned up and can contain a ton of junk that bloats the
file size and slows down rendering. In general the best way to combat
this is to first run SVG files through a linter such as
`svgo <https://github.com/svg/svgo>`__ (see the Tools section below).
However, when authoring SVGs by hand here are some best practices to
help keep them lightweight. These rules are based on some real examples
seen in Mozilla's code.

Basics
~~~~~~

-  Two spaces indenting
-  No useless whitespaces or line breaks (see below for more details)
-  Adding a license header
-  Use double quotes

Whitespace and line breaks
~~~~~~~~~~~~~~~~~~~~~~~~~~

Whitespace
^^^^^^^^^^

In addition to trailing whitespace at the end of lines, there are a few
more cases more specific to SVGs:

-  Trailing whitespaces in attribute values (usually seen in path
   definitions)
-  Excessive whitespace in path or polygon points definition

Whitespace examples
^^^^^^^^^^^^^^^^^^^

This path:

.. code:: html

   <path d=" M5,5    L1,1z ">

can be cut down to this:

.. code:: html

   <path d="M5,5 L1,1z">

Similarly, this polygon:

.. code:: html

   <polygon points="  0,0   4,4  4,0  "/>

can be cut down to this:

.. code:: html

   <polygon points="0,0 4,4 4,0"/>

Line breaks
^^^^^^^^^^^

You should only use line breaks for logical separation or if they help
make the file readable. You should avoid line breaks between every
single element or within attribute values. It's recommended to put the
attributes on the same line as their tag names, if possible. You should
also put the shortest attributes first, so they are easier to spot.

Unused tags and attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~

Editor metadata
^^^^^^^^^^^^^^^

Vector editors (Inkscape, Adobe Illustrator, Sketch) usually add a bunch
of metadata in SVG files while saving them. Metadata can mean many
things, including:

-  The typical "Created with *editor*" comments
-  Non-standard editor specific tags and attributes (``sketch:foo``,
   ``illustrator:foo``, ``sopodi:foo``, …)
-  The `XML
   namespace <https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course>`__
   definition that comes with the latter (``xmlns:sketch``,
   ``xmlns:sopodi``, …)

Other metadata
^^^^^^^^^^^^^^

In addition to non-standard editor metadata, standard compliant metadata
also exists. Typical examples of this are ``<title>`` and ``<desc>``
tags. Although this kind of data is supported by the browser, it can
only be displayed when the SVG is opened in a new tab. Plus, in most of
the cases, the filename is quite descriptive So it's recommended to
remove that kind of metadata since it doesn't bring much value.

You shouldn't include DOCTYPEs in your SVGs either; they are a source of
many issues, and the SVG WG recommends not to include them. See `SVG
Authoring
guidelines <https://jwatt.org/svg/authoring/#doctype-declaration>`__.

Avoid the use of CDATA sections
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

`CDATA
sections <https://developer.mozilla.org/en-US/docs/Web/API/CDATASection>`__
are used to avoid parsing some text as HTML. Most of time, CDATA isn't
needed, for example, the content in ``<style>`` tags doesn't need to be
wrapped in a CDATA section as the content inside the tag is already
correctly parsed as CSS.

Invisible shapes
^^^^^^^^^^^^^^^^

There are two kinds of invisible shapes: The off-screen ones and the
uncolored ones.

The offscreen shapes are hard to spot, even with an automated tool, and
are usually context aware. Those kinds of shapes are visible but off the
`SVG view
box <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox>`__.
Here's `an
example <https://hg.mozilla.org/mozilla-central/diff/9fb143f3b36a/browser/themes/shared/heartbeat-star-lit.svg>`__
of a file with offscreen shapes.

On the other hand, the uncolored ones are easier to spot, since they
usually come with styles making them invisible. They must meet two
conditions: they must be devoid of any fill (or a transparent one) or
stroke.

Unused attributes on root ``<svg>`` element
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The root ``<svg>`` element can also host many useless attributes. Here's
an
`example <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/components/loop/content/shared/img/icons-10x10.svg>`__
taking into account the list below:

-  ``version``
-  ``x="0"`` and ``y="0"``
-  ``enable-background`` (unsupported by Gecko and now deprecated by the
   Filter Effects specification)
-  ``id`` (id on root element has no effect)
-  ``xmlns:xlink`` attribute when there are no ``xlink:href`` attributes
   used throughout the file
-  Other unused `XML
   Namespace <https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course>`__
   definitions
-  ``xml:space`` when there is no text used in the file

Other
^^^^^

-  Empty tags, this may be obvious, but those are sometimes found in
   SVGs
-  Unreferenced ids (usually on gradient stops, but also on shapes or
   paths)
-  ``clip-rule`` attribute when the element *is not* a descendant of a
   ``<clipPath>``
-  ``fill-rule`` attribute when the element *is* a descendant of a
   ``<clipPath>``
-  Unreferenced/Unused clip paths, masks or defs
   (`example <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/toolkit/themes/shared/reader/RM-Plus-24x24.svg>`__)

Styling
~~~~~~~

Styling basics
^^^^^^^^^^^^^^

-  Privilege short lowercase hex for colors
-  Don't use excessive precision for numeric values (usually comes from
   illustrator)
-  Use descriptive IDs
-  Avoid inline styles and use class names or SVG attributes

Styling examples
''''''''''''''''

Here are some examples for excessive number precision:

-  5.000000e-02 → 0.05 (as seen
   `here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/devtools/images/tool-network.svg#l1.31>`__)
-  -3.728928e-10 → 0 (as seen
   `here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/aboutNetError_alert.svg#l1.12>`__)
-  translate(0.000000, -1.000000) → translate(0, -1) (as seen
   `here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/heartbeat-icon.svg#l1.13>`__)

As for descriptive IDs:

-  For gradients: SVG_ID1 → gradient1 (as seen
   `here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/aboutNetError_alert.svg#l1.12>`__)

Use of class names
^^^^^^^^^^^^^^^^^^

-  Avoid using a class if that class is only used once in the file
-  If that class only sets a fill or a stroke, it's better to set the
   fill/stroke directly on the actual shape, instead of introducing a
   class just for that shape. You can also use SVG grouping to avoid
   duplicating those attributes
-  Avoid introducing variants of the same file (color/style variants),
   and use sprites instead (with class names)

Default style values
^^^^^^^^^^^^^^^^^^^^

There's usually no need to set the default style value unless you're
overriding a style. Here are some commonly seen examples:

-  ``style="display: none;"`` on ``<defs>`` elements (a ``<defs>``
   element is hidden by default)
-  ``type="text/css"`` on ``<style>`` elements
-  ``stroke: none`` or ``stroke-width: 0``

SVG grouping
~~~~~~~~~~~~

Style grouping
^^^^^^^^^^^^^^

Group similarly styled shapes under one ``<g>`` tag; this avoids having
to set the same class/styles on many shapes.

Avoid excessive grouping
^^^^^^^^^^^^^^^^^^^^^^^^

Editors can sometimes do excessive grouping while exporting SVGs. This
is due to the way editors work.

Nested groups
'''''''''''''

Avoid multiple-level nesting of groups, these make the SVG less
readable.

Nested transforms
'''''''''''''''''

Some editors use ``<g>`` tags to do nested transforms, which is usually
not needed. You can avoid this by doing basic algebra, for example:

.. code:: xml

   <g transform="translate(-62, -310)"><shape transform="translate(60, 308)"/></g>

can be cut down to:

.. code:: xml

   <shape transform="translate(-2,-2)"/>

because: -62+60 = -310+308 = -2

Performance tips
~~~~~~~~~~~~~~~~

These rules are optional, but they help speeding up the SVG.

-  Avoid using a ``<use>`` tag when that ``<use>`` tag is being
   referenced only once in the whole file.
-  Instead of using CSS/SVG
   `transforms <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform>`__,
   apply directly the transform on the path/shape definition.

Tools
~~~~~

Tools can help to clean SVG files. Note, however that some of the rules
stated above can be hard to detect with automated tools since they
require too much context-awareness. To this date, there doesn't seem to
be a tool that handles all of the above. However, there are some
utilities that cover parts of this document:

-  Mostly complete command line tool: https://github.com/svg/svgo
-  Alternatives to SVGO:

   -  https://github.com/RazrFalcon/svgcleaner
   -  https://github.com/scour-project/scour

-  GUI for command line tool (use with "Prettify code" and "Remove
   ``<title>``" options on): https://jakearchibald.github.io/svgomg/
-  Good alternative to SVGO/SVGOMG:
   https://petercollingridge.appspot.com/svg-editor
-  Fixes the excessive number precision:
   https://simon.html5.org/tools/js/svg-optimizer/
-  Converts inline styles to SVG
   attributes: https://www.w3.org/wiki/SvgTidy
-  RaphaelJS has a couple of utilities that may be useful:
   `raphael.js <https://dmitrybaranovskiy.github.io/raphael/>`__
