CSS Custom Properties — ``var()``
=================================
CSS custom properties, or the ``var()`` feature, let one define named
variables with CSS values that can then be substituted where a property is used. To quote an example from the spec:
.. code-block:: css
:root {
--main-color: #06c;
--accent-color: #006;
}
/* The rest of the CSS file */
#foo h1 {
color: var(--main-color);
}
Additionally, ``var())`` can specify a fallback value, in case the
implementation does not support defining custom properties:
.. code-block:: css
.foo { color: var(--main-color, #aabbcc); }
In this example, if ``--main-color`` is not defined, it will be
substituted with ``#aabbcc``.
OpenType fonts with SVG data and a color substitution table ("emoji fonts")
---------------------------------------------------------------------------
OpenType allows fonts to define some glyphs in terms of SVG documents.
These glyphs can be recolored: OpenType also allows fonts to have a
color substitution table that will be applied to the SVG. To do this,
RGB entries in the color table are effectively turned into custom
properties named ``color0``, ``color1``, etc. with RGB values. Then,
SVG elements specify their colors like ````, often with a fallback.
OpenType's minimal requirements are that SVG implementations support
``var()`` just in places where a color may be specified (i.e. the
properties that specify SVG paint servers), and that they support the
fallback value. It does **not** require that implementations actually
support defining custom values for the
``color0``/``color1``/``colorN`` variables, just that fallbacks are used.
This lets librsvg approach supporting CSS custom properties in an
incremental fashion.
Roadmap for incremental support
-------------------------------
* Stage 1 (:issue:`997`): support ``var(--blah, fallback)`` just for
colors in properties that take paint servers, plus properties like
``lightingColor`` (filters) and ``stopColor`` (gradients). Look in
``property_defs.rs`` for places that use the ``Color`` type. This
should will make OpenType fonts with color fallbacks work in minimal
fashion.
* Stage 2 (:issue:`459`): support defining custom properties and
referencing them. I wanted to cut&paste Servo's implementation of
this, but it is a bit involved and may require plenty of refactoring
to accomodate it from librsvg's code. If it is too complex, maybe
we can have a homegrown implementation that just lets one define
``--foo: value;`` in a ``:root`` selector, and that just substitutes
whole values without substitution into other tokens
(e.g. ``width: var(--some_number)px;`` wouldn't work).
* Stage 3, full support for custom properties with substitution into
other values.
Letting the caller define values for custom properties
------------------------------------------------------
Adobe's SVG Native Viewer has a `simple API to specify a color map
`_
that maps string names to RGBA colors. I think it would be more
future-proof to actually let the caller specify the values in a
``:root`` selector via an external stylesheet; this way we can
accomodate media queries in a clean fashion without growing the public
API. Media queries are often used to set the custom property values
depending on the media's characteristics (e.g. change colors depending
on dark-mode), and later the properties are used with ``var()``.
Security considerations
-----------------------
If we fully support variable substitution, be careful about the `macro
expansion attack
`_ that can be
done with them. The spec mentions a mitigation; I think the Servo
code already does this.
References
----------
* Specification: `CSS Custom Properties for Cascading Variables Module Level 1
`_
* OpenType specification for `Colors and Color Palettes
`_