-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow loading icons from SVG files #4206
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
houndci-bot
reviewed
Oct 23, 2020
javierm
force-pushed
the
svg_icons
branch
5 times, most recently
from
October 26, 2020 10:52
9040482
to
ab2b8da
Compare
Even if "r" is shorter, "regular" is easier to understand, and we're going to store these icons in a folder named "regular", which is the convention Font Awesome uses.
We were using `display: inline` assuming that's the way elements will be displayed by default when shown. However, those elements could be displayed in a different way (inline-flex, for instance). So we avoid any possible conflicts by using the `display: none` rule when we want to hide the elements. Besides, the code is now symmetrical and IMHO easier to follow.
There are a dozen ways to add an icon used for decoration. Each of them offers advantages and disadvantages regarding these topics: * Accessibility * Ease of use for developers * Ease of customization for CONSUL installations * Maintainability * Resulting file size * Number of HTTP requests * Browser support * Robustness We were using one of the most common ones: icon fonts. This technique shines in many of these aspects. However, it misses the most important one: accessibility. Users who configure their browser to display a custom font would see "missing character" icons where our icons should be displayed. Some users have pointed out they use a custom font because they're dyslexic and webs using icon fonts make it extremely painful for them [1]. Screen reader users might also be affected, since screen readers might try to read the UTF-8 character used by the icon (even if it uses a UTF Private Use Area) and will react to it in inconsistent ways. Since right now browser support for different techniques to prevent it with CSS ranges from non-existant (CSS speech module) to limited (use an alternative text in the `content` property [2]), we've been adding an HTML element with an `aria-hidden` attribute. However, by doing so the ease of customizations for CONSUL installations is reduced, since customizing ERB files is harder than customizing CSS. Finally, font icons are infamous for not being that robust and conflicting with UTF settings in certain browsers/devices. Recently Font Awesome had a bug [3] because they added icons out of the Private Use Area, and those icons could conflict with other UTF characters. So, instead of loading Font Awesome icons with a font, we can add them using their SVG files. There are several ways to do so, and all of them solve the accessibility and robustness issues we've mentioned, so that point won't be mentioned from now on. All these techniques imply having to manually download Font Awesome icons every time we upgrade Font Awesome, since the `font-awesome-sass` gem doesn't include the `sprites/` and `svgs/` folders Font Awesome includes in every release. So, from the maintenance poing of view, they're all pretty lacking. Method 1: SVG sprites with inline HTML We can use SVG files where template icons are defined, like so: <svg> <use xlink:href="solid.svg#search"></use> </svg> This technique has great browser support and it only generates one HTTP request for all icons. However, it requires adding <svg> tags in many views, making it harder to customize for CONSUL installations. For developers we could reduce the burden by adding a helper for these icons. Downloading all the icons just to use one (or a few) might also be inconvenient, since the total file size of these icons will be up to a megabyte. To reduce the impact of this issue, we could either minimize the SVG file, compress it, or generate a file with just the icons we use. However, generating that custom file would be harder to maintain. Method 2: CSS with one SVG icon per file We can use the separate SVG files provided by Font Awesome, like so: background: url("solid/search.svg"); Or, if we want to add a color to the icon: backgound: blue; mask-image: url("solid/search.svg"); Using this technique will result in one HTTP request per icon, which might affect performance. Browser support is also limited to browsers supporting mask-image, which at the time of writing is 95% of the browsers, with the notable exception of Internet Explorer 11. On the plus side, using CSS makes it easy to customize and (IMHO) easy to work with on a daily basis. Method 3: CSS with SVG sprites We can use the aforementioned sprites provided by Font Awesome and use them with CSS: backgound: blue; mask-image: url("solid.svg#search"); The number of HTTP requests and file size are similar to Method 1, while browser support, ease of customization and ease of use are similar to Method 2. There's one extra gotcha: this method requires doing minor changes to the files provided by Font Awesome, which means this solution is harder to maintain, since we'll have to do the same changes every time we upgrade Font Awesome. Mainly we need to add these changes to every sprite file: - <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> +<!-- +This is a modified version of Font Awesome Free regular sprite file. The icons are exactly as they originally were; the only changes are: + +* <symbol> tags have been replaced with <svg> tags and a <style> tag has been added +* A <style> tag has been added +* The style="display:none" attribute of the main <svg> tag has been removed +--> +<svg xmlns="http://www.w3.org/2000/svg"> + <style> + svg svg { display: none } + svg svg:target { display: inline } + </style> And then replace every <symbol> tag with a <svg> tag. Method 4: CSS with Data URI Finally, we can write the icons directly in the CSS: backgound: blue; mask-image: url('data:image/svg+xml;utf8,<svg...'); This method does not generate any extra HTTP requests and only downloads the icons we need. However, maintaining it is really hard, since we need to manually copy all the <svg> code for every icon we use, and do it again every time we upgrade Font Awesome. In this commit, we implement Method 2. To improve browser support, we're falling back to font icons on browsers which don't support mask images. So 5% of the browsers might still conflict with users changing the fonts or with screen readers trying to announce the icon character. We believe this is acceptable; the other option for these browsers would be to show those icons as a background image, meaning the icons would always be black, meaning users of these browsers would have trouble to distinguish them if the background was dark as well. Since we aren't sure whether the performance hit of having one HTTP request per icon is overcome by only requesting the icons we actually use, we aren't taking this factor into account when choosing between methods 2 and 3. We believe this method will be the less painful one to maintain and customize. Generating SVG sprites with just the icons we use would increase performance, but it would make it harder for existing CONSUL installations to use icons we haven't included in the sprites. [1] https://speakerdeck.com/ninjanails/death-to-icon-fonts [2] https://developer.mozilla.org/en-US/docs/Web/CSS/content#Browser_compatibility [3] https://blog.fontawesome.com/fixing-a-unicode-bug-in-5-14-0/
Senen
approved these changes
Nov 3, 2020
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someday we decide to move from Asset Pipeline to Webpacker probably we will be able to use a Node.js package with SVG files already included so we will be able to remove all these SVG files from the vendor
folder.
Tested successfully in the production environment.
javierm
added a commit
that referenced
this pull request
May 21, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image-property`. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
javierm
added a commit
that referenced
this pull request
Jun 16, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image-property`. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
javierm
added a commit
that referenced
this pull request
Jun 21, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
javierm
added a commit
that referenced
this pull request
Jun 29, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
javierm
added a commit
that referenced
this pull request
Jun 30, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
javierm
added a commit
that referenced
this pull request
Jul 2, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
javierm
added a commit
that referenced
this pull request
Jul 2, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
Senen
pushed a commit
that referenced
this pull request
Jul 2, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
javierm
added a commit
that referenced
this pull request
Jul 5, 2021
Back in commit 925f04e from pull request #4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
Senen
pushed a commit
to rockandror/consuldemocracy
that referenced
this pull request
Jul 8, 2021
Back in commit 925f04e from pull request consuldemocracy#4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
Senen
pushed a commit
to rockandror/consuldemocracy
that referenced
this pull request
Jul 8, 2021
Back in commit 925f04e from pull request consuldemocracy#4206 we wrote about our way to load SVG icons: > Using this technique will result in one HTTP request per icon, which > might affect performance We considered using CSS with Data URIs, and wrote: > This method does not generate any extra HTTP requests and only > downloads the icons we need. However, maintaining it is really hard, > since we need to manually copy all the <svg> code for every icon we > use, and do it again every time we upgrade Font Awesome. Back when I wrote that, I didn't know Sass had a function named `asset-data-url` which generated Data URIs automatically given a filename. I searched for it, but somehow I only found Compass helpers doing a similar thing. Note we're using CSS variables to reduce the size of the generated CSS. If we used `mask-image: asset-data-url(...)`, the generated CSS would include the value returned by `asset-data-url` twice: once for the `mask-image` property and once for the `-webkit-image` property. The percentage of browsers supporting `mask-image` and not supporting CSS variables is really small (less than 1%), so in that regard things remain more or less the same and unsupported browsers will render the icons using the `font-family: "Font Awesome 5 Free` property. After these changes, the size of the generated CSS increases from 475KB to 533KB. If we didn't use CSS variables, the generated CSS would use 591KB. We believe this is acceptable because the SVG icons we use are very small files (about 1-1.5KB big) and, downloaded separately, they also amount to about 45KB, which is similar to the CSS file increase we get. Using `asset-data-url` we download them in one request instead of having one request per file (about 35 extra requests).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
References
Objectives
Notes
vendor/assets/images/fontawesome
folder every time we update the font-awesome-sass gem