Scalable Vector Graphic (SVG) images have many advantages over regular images. They have a very low file size and barely affect site bandwidth. They can be easily scaled and easily modified using CSS. Compared to regular images, SVG graphics are in fact just strings of XML. Thanks to that, they can be treated more like parts of a template than separate files.
SVG images can be included into website using img HTML tag, like this <img src="some_svg.svg">
, but it's better to inline them as <svg>
HTML element. By inlining them, we make SVGs part of DOM tree - thanks to that browser won't make additional requests and you will be able to style your SVG using CSS - for example easily change it's color using fill
CSS attribute.
Loading SVG into the template #
While you could load SVG file using include
Twig tag, it's better to use svg() function. include
can load only files from templates
directory. svg()
on the other hand can load SVGs from webroot directory (named web
by default), templates
directory or even from text string. Since you most likely keep regular images somewhere in webroot directory, it would only make sense to also keep your SVG ones there.
After loading SVG image, svg()
function sanitizes it from potential malicious scripts contained within and namespaces all styles and parameters like classes and IDs within SVG to avoid conflicts with rest of the website.
What conflicts, you might ask? Let's imagine such SVG file:
<svg width="150" height="150" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg">
<style>
/* <![CDATA[ */
.shape {
fill: orange;
stroke: black;
stroke-width: 10px;
color: red;
}
/* ]]> */
</style>
<circle cx="50" cy="50" r="40" class="shape" />
</svg>
Using such SVG without passing it through svg()
function would mean that the whole website would be affected by styles contained within it. Good luck debugging such errors if you use more than dozen SVG images on your website.
Processing SVG files #
Since version 3.3, Craft has attr
, prepend
and append
Twig filters that can be used to process and modify HTML (or XML). Since inlined SVGs are parts template and XML strings, these filters are perfect for working with them.
- attr filter modifies HTML tags attributes. For example, it can be used to set class or remove it. Not to be confused with attr() function.
- append filter appends HTML elements inside other HTML elements. It can be also used to overwrite specific element.
- prepend - same as append, but it prepends instead of appending.
How can we use these filters?
attr
will be useful for adding attributes to SVG images, like CSS classes. Without this filter we would need to directly modify SVG files. Here's how to load SVG from file, add class to it and output it into template:
{{ svg('@webroot/icon.svg')|attr({
class: 'icon'
}) }}
How about making SVG image accessible? prepend
filter can be used to do that, by adding <title>
tag into SVG markup. It will work in same way as alt
attribute on <img>
tag:
{{svg('@webroot/icon.svg')|prepend('<title>Some text</title>', 'replace')}}
SVG macro #
Loading and processing SVG files is a repetitive task - that's why we should put all SVG-related functionality in Twig macro.
{%- macro svg(path, attributes = null, alt = null) -%}
{# settings #}
{% set directory = 'svg' %}
{# logic #}
{% if path is defined and path is not empty %}
{% set svg = svg('@webroot/'~directory~'/'~path~'.svg', namespace=true) %}
{% if alt %}
{% set svg = svg|prepend('<title>'~alt~'</title>') %}
{% endif %}
{% if attributes and attributes is not iterable %}
{% set svg = svg|attr({class: attributes}) %}
{% elseif attributes and attributes is iterable %}
{% set svg = svg|attr(attributes) %}
{% endif %}
{{svg|raw}}
{% endif %}
{%- endmacro -%}
Here are macro parameters:
- path - path of SVG file within webroot (
web
) directory. You don't need to end filename with.svg
- file extension is appended automatically within macro. At the beginning of macro, you can set directory name containing your SVG files within webroot directory. - attributes - optional paramater for adding HTML attributes. If a single string is passed, it will add class to SVG. If an object containing "attribute-value" pairs is passed, you can set what specific attributes SVG should have.
- alt - optional parameter for adding alternative text to SVG image.
So, how does "attributes" parameter works in practice? Using a macro like this...
{{_self.svg('file_path', {
id: 'some-id',
data-something: 'abc',
})}}
...will render SVG with id
and data-something
attributes. If you just want to add class to SVG, use macro like this:
{{_self.svg('file_path', 'some-class')}}
Article update history
- 07 february 2021 - added missing,
namespace=true
param to macro.