Inline SVG
Styling a SVG document with CSS for use on the web is most reliably achieved by adding classes to the document and embedding it inline in the HTML.
This gem adds a Rails helper method (inline_svg
) that reads an SVG document (via Sprockets, so works with the Rails Asset Pipeline), applies a CSS class attribute to the root of the document and
then embeds it into a view.
Inline SVG supports Rails 3 (from v0.12.0), Rails 4 and Rails 5 (from v0.10.0).
Changelog
This project adheres to Semantic Versioning. All notable changes are documented in the CHANGELOG.
Installation
Add this line to your application's Gemfile:
gem 'inline_svg'
And then execute:
$ bundle
Or install it yourself as:
$ gem install inline_svg
Usage
inline_svg(file_name, ={})
The file_name
can be a full path to a file, the file's basename or an IO
object. The
actual path of the file on disk is resolved using
Sprockets (when available), a naive file finder (/public/assets/...
) or in the case of IO
objects the SVG data is read from the object.
This means you can pre-process and fingerprint your SVG files like other Rails assets, or choose to find SVG data yourself.
Here's an example of embedding an SVG document and applying a 'class' attribute in HAML:
<html>
<head>
<title>Embedded SVG Documents<title>
</head>
<body>
<h1>Embedded SVG Documents</h1>
<div>
<%= inline_svg "some-document.svg", class: 'some-class' %>
</div>
</body>
</html>
Here's some CSS to target the SVG, resize it and turn it an attractive shade of blue:
.some-class {
display: block;
margin: 0 auto;
fill: #3498db;
width: 5em;
height: 5em;
}
Options
key | description |
---|---|
id |
set a ID attribute on the SVG |
class |
set a CSS class attribute on the SVG |
data |
add data attributes to the SVG (supply as a hash) |
size |
set width and height attributes on the SVG Can also be set using height and/or width attributes, which take precedence over size Supplied as "Width * Height" or "Number", so "30px*45px" becomes width="30px" and height="45px" , and "50%" becomes width="50%" and height="50%" |
title |
add a <title> node inside the top level of the SVG document |
desc |
add a <desc> node inside the top level of the SVG document |
nocomment |
remove comment tags from the SVG document |
preserve_aspect_ratio |
adds a preserveAspectRatio attribute to the SVG |
aria |
adds common accessibility attributes to the SVG (see PR #34 for details) |
Example:
inline_svg("some-document.svg", id: 'some-id', class: 'some-class', data: {some: "value"}, size: '30% * 20%', title: 'Some Title', desc:
'Some description', nocomment: true, preserve_aspect_ratio: 'xMaxYMax meet', aria: true)
Accessibility
Use the aria: true
option to make inline_svg
add the following
accessibility (a11y) attributes to your embedded SVG:
- Adds a
role="img"
attribute to the root SVG element - Adds a
aria-labelled-by="title-id desc-id"
attribute to the root SVG element, if the document contains<title>
or<desc>
elements
Here's an example:
<%=
inline_svg('iconmonstr-glasses-12-icon.svg',
aria: true, title: 'An SVG',
desc: 'This is my SVG. There are many like it. You get the picture')
%>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" \
role="img" aria-labelledby="bx6wix4t9pxpwxnohrhrmms3wexsw2o m439lk7mopdzmouktv2o689pl59wmd2">
<title id="bx6wix4t9pxpwxnohrhrmms3wexsw2o">An SVG</title>
<desc id="m439lk7mopdzmouktv2o689pl59wmd2">This is my SVG. There are many like it. You get the picture</desc>
</svg>
Note: The title and desc id
attributes generated for, and referenced by, aria-labelled-by
are one-way digests based on the value of the title and desc elements and an optional "salt" value using the SHA1 algorithm. This reduces the chance of inline_svg
embedding elements inside the SVG with id
attributes that clash with other elements elsewhere on the page.
Custom Transformations
The transformation behavior of inline_svg
can be customized by creating custom transformation classes.
For example, inherit from InlineSvg::CustomTransformation
and implement the #transform
method:
# Sets the `custom` attribute on the root SVG element to supplied value
# Remember to return a document, as this will be passed along the transformation chain
class MyCustomTransform < InlineSvg::CustomTransformation
def transform(doc)
doc = Nokogiri::XML::Document.parse(doc.to_html)
svg = doc.at_css 'svg'
svg['custom'] = value
doc
end
end
Add the custom configuration in an initializer (E.g. ./config/initializers/inline_svg.rb
):
# Note that the named `attribute` will be used to pass a value to your custom transform
InlineSvg.configure do |config|
config.add_custom_transformation(attribute: :my_custom_attribute, transform: MyCustomTransform)
end
The custom transformation can then be called like so:
%div
= inline_svg "some-document.svg", my_custom_attribute: 'some value'
In this example, the following transformation would be applied to a SVG document:
<svg custom="some value">...</svg>
You can also provide a default_value to the custom transformation, so even if you don't pass a value it will be triggered
# Note that the named `attribute` will be used to pass a value to your custom transform
InlineSvg.configure do |config|
config.add_custom_transformation(attribute: :my_custom_attribute, transform: MyCustomTransform, default_value: 'default value')
end
The custom transformation will be triggered even if you don't pass any attribute value
%div
= inline_svg "some-document.svg"
= inline_svg "some-document.svg", my_custom_attribute: 'some value'
In this example, the following transformation would be applied to a SVG document:
<svg custom="default value">...</svg>
And
<svg custom="some value">...</svg>
Passing a priority
option with your custom transformation allows you to
control the order that transformations are applied to the SVG document:
InlineSvg.configure do |config|
config.add_custom_transformation(attribute: :custom_one, transform: MyCustomTransform, priority: 1)
config.add_custom_transformation(attribute: :custom_two, transform: MyOtherCustomTransform, priority: 2)
end
Transforms are applied in ascending order (lowest number first).
Note: Custom transformations are always applied after all built-in transformations, regardless of priority.
Custom asset file loader
An asset file loader returns a String
representing a SVG document given a
filename. Custom asset loaders should be a Ruby object that responds to a
method called named
, that takes one argument (a string representing the
filename of the SVG document).
A simple example might look like this:
class MyAssetFileLoader
def self.named(filename)
# ... load SVG document however you like
return "<svg>some document</svg>"
end
end
Configure your custom asset file loader in an initializer like so:
InlineSvg.configure do |config|
config.asset_file = MyAssetFileLoader
end
Contributing
- Fork it ( http://github.com/jamesmartin/inline_svg/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
Please write tests for anything you change, add or fix. There is a basic Rails app that demonstrates the gem's functionality in use.