Manual:Coding conventions/SVG

This page describes the coding conventions used within files of the MediaWiki codebase written in SVG. See also the general conventions that apply to all programming & markup languages, including SVG.

On per-project base we make use of SVGO as optimisation tool, see automated optimisation below. Another helpful tool for further manual optimisation is SVGOMG. It provides a visual before/after comparison.

Code structure
Minimal code as possible with readability in mind is the premise.

Example for simple optimised file – subtract.svg from OOUI: Example for slightly more complex, optimised file – BetaFeatures screenshot template: We will explain the different coding conventions in the following section.

Automated optimisation (SVGO)
A standard set of conventions can be enforced by help of SVGO. If your original SVGs are well-formed, you should be able to automatically optimise them. As some SVGO v1.x default plugins (options) might result in unexpected appearance with more complex SVGs, we differentiate between safe, considerably less-safe and unsafe plugins. With latter it's recommended to involve per-file quality assurance.

Safe plugins:

Mentioning only plugins, that are changed from default setting or that might be counter-intuitive: See SVGO Readme for other enabled, safe plugins.
 * Sorting attributes 'sortAttrs' Enable by setting to  ; disabled by default
 * Remove DOCTYPE 'removeDoctype' Using a DOCTYPE in SVGs is considered harmful by SVG standards authors as of SVG 2 Working Draft; enabled by default
 * Remove or cleanup  attribute when possible 'cleanupEnableBackground' Deprecated attribute, only supported by IE/Edge; enabled by default

Plugins to consider carefully: Unsafe rules to disable (don't use!):
 * Round/rewrite number lists 'convertPathData' Might cause imprecise rendering; enabled by default
 * Remove unused and minify used IDs 'cleanupIDs' Might negatively affect readability in more complex SVGs; enabled by default
 * Remove raster images 'removeRasterImages' As general rule dangerous, could cause data loss; disabled by default
 * Remove XML processing instructions 'removeXMLProcInst', aka XML declaration  Issues when viewed as standalone file in some editors, also possible issues with MIME type interpretation Example: If the SVG doesn't start with an XML declaration, then it's MIME type will be detected as   rather than   by libmagic and consequently, MediaWiki's CSSMin CSS minifier. libmagic's default database currently requires that SVGs contain an XML declaration; disable by setting to  ; enabled by default
 * Remove 'removeTitle' Problematic for accessibility reasons; set to  ; enabled by default
 * Remove 'removeDesc' Problematic for accessibility reasons; set to  ; enabled by default
 * Remove  attribute 'removeViewBox' Results in troublesome appearance in some browsers, therefore both,  /  and   should be featured; set to  ; enabled by default
 * Remove dimensions /  when   is available 'removeDimensions' As above; set to  ; disabled by default

Exemplified safe configuration
Use  output for human readable code and in the process indent code by tabs.

Exemplified safe configuration (Gruntfile.js)
svgmin: { options: { js2svg: { indent: '\t', pretty: true },		plugins: [ { cleanupIDs: false }, {			removeDesc: false }, {			removeRasterImages: true }, {			removeTitle: false }, {			removeViewBox: false }, {			removeXMLProcInst: false }, {			sortAttrs: true } ]	}, }

Exemplified safe configuration (.svgo.yml)
Update March 2020: Maintainers of a handful of repos are exploring moving away from Grunt tasks and instead using raw NPM scripts (T246321). This is an example of migrating svgmin, using the .svgo.yaml file, which is functionally equivalent to the above Gruntfile.js variant.

multipass: true plugins: - cleanupIDs: false - removeDesc: false - removeRasterImages: true - removeTitle: false - removeViewBox: false # If the SVG doesn't start with an XML declaration, then its MIME type will # be detected as "text/plain" rather than "image/svg+xml" by libmagic and, # consequently, MediaWiki's CSSMin CSS minifier. libmagic's default database # currently requires that SVGs contain an XML declaration: # https://github.com/threatstack/libmagic/blob/master/magic/Magdir/sgml#L5 - removeXMLProcInst: false - sortAttrs: true
 * 1) Recommended options from:
 * 2) https://www.mediawiki.org/wiki/Manual:Coding_conventions/SVG#Exemplified_safe_configuration

js2svg: pretty: true indent: "\t"
 * 1) Configure the indent (default 4 spaces) used by `--pretty` here:
 * 2) @see https://github.com/svg/svgo/blob/master/lib/svgo/js2svg.js#L6 for more config options
 * 3) Unfortunately EOL cannot be configured, svgo uses the platform's EOL marker.
 * 4) On non-unix systems the linebreaks will be normalized to LF (unix) only at git commit, assuming `core.autocrlf` is 'true' (default) or 'input'.
 * 1) On non-unix systems the linebreaks will be normalized to LF (unix) only at git commit, assuming `core.autocrlf` is 'true' (default) or 'input'.

Manual optimisation
Beyond automated optimising SVGs there are further steps to consider:
 * Remove  from XML processing instruction, as it's default
 * Remove  attribute from   tag, as all browsers ignore it
 * Lowercase (for better gzipping) and shorten hex color values, if possible, e.g.  instead of.
 * Attributes that are the same for a group of elements can be applied to a common parent  instead.
 * Rely on defaults like  and.
 * The  syntax is almost always shorter than the syntax of basic shapes like   or even  . The only possible exceptions are ,  , and rounded  , as converting them to paths typically results in sequences of long floating point numbers.
 * Merge  elements where applicable.
 * Remove redundant  attribute when identical to   as renderer must consider both values identical when one's missing.
 * Remove not needed  and  . These rules only have an effect on certain paths, e.g. when a path intersects itself.
 * Look for IEEE rounding errors like  or  . Such numbers take up space without providing any additional information. They can almost always be cut off without visually changing anything.
 * Work with a non-fractional pixel grid while drawing, and align as much points as possible on this grid. These points have a much higher chance of being represented as short integer numbers in the resulting code.
 * Pick a non-fractional grid so that it matches the features of an existing image, and scale or redraw shapes so that as many points as possible fall on the grid. The result might be misaligned and can be cropped using.

If you want to dig even deeper, there are more optimisations to compress delivery, such as:
 * auto-closing paths (aka removing  for certain shapes),
 * use relative commands when creating paths (instead of absolute commands, e.g. "m" for "move by", instead of "M" for "move to"),
 * optimising for compression backreferences