Spin-off from #3080100: Assess accessibility of Claro in High Contrast AKA forced colors mode.

Problem/Motivation

Problem 1: High Contrast issues

Claro has many CSS background images. These are stripped out by Internet Explorer and Firefox, but Edge displays them.

When Windows high contrast themes were originally introduced, IE and Firefox policy was to strip out all CSS background image, on the assumption that they interfered with the legibility of text that was on top of them. Early versions of Edge did this too, but later Edge changed the policy to display background images, but enforce a plain background in places where text was on top of a background image.

Some of these icons may include essential information. In those cases they can't be background images.

Some suggestions mentioned:

If any of these icons are essential, we should not use CSS background images.

Alternative techniques are to use SVG-in-HTML, or use CSS content: url() instead of background images.

A gotcha of not using CSS background image, is that you lose the other useful background properties like position (sprite images) and size, so workarounds are needed for those.

Problem 2: inlining concerns

From #3085245: Un-inline SVGs in pcss.css files, add build tool to inline them when compiled. Among other things, the issue states

That'd make it much easier to inspect the SVGs, to apply SVG optimization tools, to encourage reuse, etc. It also allows us to decide whether we truly want to inline these as data: URIs, or whether it makes more sense to let them be loaded by HTTP requests. This particular CSS file is 24 KB ungzipped and unminified. That's … a lot. Most of that is due to these inlined SVG files (this CSS file is the single largest CSS file in Claro).

In other words: for developer ergonomics and for web performance optimization reasons I think we should consider changing this.

Problem 3: Not inlining concerns

Not inlining makes reuse easier and can potentially reduce filesize of the files doing the inlining. However, it also removes the ability to easily change color, which means a new file/request is needed for each color change of the same shape.

Problem 4: SVG Spritemap problems

#3020422: Toolbar style update Attempted to use SVG spritemap and discovered (comment #49)

Unfortunately: Firefox, IE11 and Edge are downloading the SVG sprite as many times as it is referenced with a different fragment id. And since the sprite SVG is obviously bigger than the singe SVG file, this is a huge performance penalty.

Problem 5: There are drawbacks to Icon Fonts as an option

See comment #16

Proposed resolution

See #16, #18, and #20 for results from exploring different approaches.

Based on the research, there is no approach that would be able to cater all use cases. The proposal is to use background: url() and request svg images, but add a postcss plugin to convert the url() calls to data uris whenever possible. Doing this in the build stage maintains the SVGs auditability/reuseability while still providing the benefits of inlining.

In cases where that isn't an option, be it animation or icons that must be visible in high-contrast, exceptions can be made but should be accompanied by a comment stating why.

Remaining tasks

  • Move icons from CSS background image to CSS content.
  • Figure out how to manage size, position, etc.

User interface changes

More robust cross-browser support for icons in Windows high contrast.

Comments

andrewmacpherson created an issue. See original summary.

andrewmacpherson’s picture

fhaeberle’s picture

@andrewmacpherson Do you agree on the approach in this patch for icons?

Basically it's what you suggested but with the adding of a color and fill='currentColor'

https://www.drupal.org/project/claro/issues/3083048#comment-13270936

Anyway, sprites are not useable and positioning gets harder with this approach.

andrewmacpherson’s picture

There's no patch in #3. Oh, you meant a patch in another issue.

Almost, but not quite. I'll test that patch first, then come back here and start notes for a general approach.

andrewmacpherson’s picture

Title: Missing icons in Windows high-contrast with IE and Firefox. » Make icons more robust in Windows high-contrast with Egde, IE, and Firefox.
fhaeberle’s picture

Thank you! Looking forward to.

andrewmacpherson’s picture

Issue summary: View changes

minor edit, remove empty list item

huzooka’s picture

I still feel that since Claro uses monochromatic icons, we will have an icon font in the end...

andrewmacpherson’s picture

#8: icon fonts are a possibility for sure. There is a slight problem that CSS content is exposed to assistive tech, and this sometimes results in problems where a TTS tries to pronounce the character; but it's intended as a decorative image. Icon fonts are OK so long as they are applied to a <span aria-hidden="true">.

kostyashupenko’s picture

Actually the problem here is not only with TTS. Main problem is that iconic font impossible to use for inputs. Only possible with pre-defined value attribute, which is wrong solution. Ex:
<input type="submit" value="&#xf043;">

This problem solves by adding new tags and wrappers with absolute positioning.

kostyashupenko’s picture

Good and fresh idea will be to use svg-sprite and svg use + shadow dom technic: same way it was done on https://www.mass.gov
Please have a look on docs here https://www.npmjs.com/package/svg-sprite

Advantages:
1. Sprite can be cached by browser.
2. Icons are building immediately on page load without waiting for styles.
3. It is fully customizable on css side. (sizes, fill color and other properties are available)

Disadvantages:
1. This technic is not supported by IE, but it's possible to use polyfill for that https://www.npmjs.com/package/svg4everybody

Now few words about usages:
1. We keep config for svg-sprite (https://www.npmjs.com/package/svg-sprite) package in `scripts` folder (for example in json format)
2. We keep svg icons in `images` folder
3. We keep inners of svg icons as simple as possible, for ex:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  <path d="M0 12.116l2.053-1.897c2.401 1.162 3.924 2.045 6.622 3.969 5.073-5.757 8.426-8.678 14.657-12.555l.668 1.536c-5.139 4.484-8.902 9.479-14.321 19.198-3.343-3.936-5.574-6.446-9.679-10.251z"/>
</svg>

4. We define path to svg sprite in .theme, like

/**
 * Returns path to svg sprite.
 */
function _claro_get_svg_sprite_path() {
  return base_path() . \Drupal::theme()->getActiveTheme()->getPath() . '/svg/sprite.svg';
}

/**
 * Hook_page_attachments().
 *
 * Prepares claro_svg_sprite_path variable to get
 * full path to svg sprite from js.
 */
function claro_page_attachments_alter(array &$attachments) {
  $attachments['#attached']['drupalSettings']['claro_svg_sprite_path'] = _claro_get_svg_sprite_path();
}

/**
 * Hook_preprocess().
 *
 * Prepares claro_svg_sprite_path variable to get
 * full path to svg sprite from twig.
 */

/** 
 * Of course here can be used any preprocess, not global for all entities.
 * I added it just for example
*/
function claro_preprocess(&$variables, $hook) { 
  $variables['claro_svg_sprite_path'] = _claro_get_svg_sprite_path();
}

5. Now you can use it from anywhere, for example twig:

<svg aria-hidden="true">
  <use xlink:href="{{ claro_svg_sprite_path }}#svg-any-icon"></use>
</svg>

or js:

<svg aria-hidden="true">
  <use xlink:href="${settings.claro_svg_sprite_path}#svg-any-icon"></use> // settings here is a drupal settings
</svg>

or preprocess:

'#template' => '<svg aria-hidden="true"><use xlink:href="' . _claro_get_svg_sprite_path() . '#svg-any-icon"></use></svg>',

6. package.json (just an example)

 "icons": "svg-sprite --config ./scripts/icons/svg-sprite.json ./images/*.svg",

7. call `yarn icons` or whatever else.

Profit.

fhaeberle’s picture

Version: 8.x-1.x-dev » 8.x-2.x-dev

Lately we agreed (in our weekly drupal slack meeting – channel #admin-ui) to do a comparison table for the different icon / svg approaches to get a better overview. That would be really helpful because there are various options to consider.

  • Inline vs. Not inline
  • background-image: url() / content: url()
  • icon font vs. no font (single svg's)
  • various PostCSS plugins
  • IE11 High Contrast support
huzooka’s picture

Project: Claro » Drupal core
Version: 8.x-2.x-dev » 8.9.x-dev
Component: Code » Claro theme

You can test the latest patch of #3020422: Toolbar style update.

This was my experience with SVG sprites:

Firefox, IE11 and Edge are downloading the SVG sprite as many times as it is referenced with a different fragment id. And since the sprite SVG is obviously bigger than the singe SVG file, this is a huge performance penalty.

The SVG icons are really blurry on IE11 and Edge compared to the icon-font-based solution (#30).

See #3020422-49: Toolbar style update.

bskibinski’s picture

Just to chime in with the icons discussion.
If accessibility is big point for Claro, iconfonts are not the way to go, there are many caveats with this technique:

  • Users can disable loading external fonts. Usually this will result in meaningless characters as icons, or icons disappearing completely
  • Users can override font settings, this can then affect icons, breaking them in places.
  • Screenreaders are not on the same page about when to pronounce or not to pronounce it. And usually this technique is used with psuedo elements, where we can't apply the 'aria-hidden' attribute
  • Previous point can be mitigated by not using pseudo-elements for font-icons, or using 'unused characters' in utf-8, but then we get to the next point;
  • Iconfonts don't support any "alt" text, So if you want to convey the meaning of the icon, you need a bit more complex html to 'hide text behind the icon'. But if users disable the CSS, icons disapear and replaced by text, this is probably not what you want.

And these are just the accessibility issues/concerns, if you want to support more modern things, responsive icons, animated icons, or just simply multi-color icons, or changing the color of one part of the icon, then iconfonts are not a good choice.
They can't be responsive in one file. They don't support native animations, etc.

Also the web is moving towards icons in SVG, so contributors would be more comfortable to edit/update/create SVG's icons. Making iconfonts in a "good" way is a bit more tricky, and could hold people back to help out.

@hazooka I've been using SVG sprites for a pretty long time now, and have never noticed SVG icons are blurry on EDGE or IE11, do you have an example, i'm curious what could cause this.
The loading is pretty bad though, didn't notice that in my sites, I'll do some more research.

I would really recommend trying to go for SVG (sprites). The sprite loading problem will only occur in FF en IE11 (edge is moving to chromium very soon). And FF will fix this, just leaving IE11. But I could live with a little bit slower IE11 if modern browsers would work better. (opinion).

andrewmacpherson’s picture

#14 is good accessibility advice.

In particular, the scenarios where the author-specified fonts don't get used are a indeed a very big problem. If the icon font is using the unicode private-use codepoints, the user's preferred font will likely not have the intended glyphs. This situation isn't just hypothetical; it's something that users commonly do in the real world.

Some icon fonts are moving away from the private-use unicode codepoints, to put their glyphs at standard codepoints. In theory it could mitigate the problem; the author-specified font doesn't get used, but the user-specified font has a glyph at that code point. But it's not safe to rely on this, because there is no way of knowing what fonts the user has. It might work if the user has the entire set of Noto font files, say.

This part isn't correct though (emphasis mine):

Iconfonts don't support any "alt" text, So if you want to convey the meaning of the icon, you need a bit more complex html to 'hide text behind the icon'. But if users disable the CSS, icons disapear and replaced by text, this is probably not what you want.

In cases where you need to convey the meaning of the icon, that's exactly what you want. Text alternatives are intended for all users who don't get the image. WCAG doesn't care how you implement images, or their text alternatives. If we were using <img src="foo.png" alt="foo">, and users turned off images (to save data transfer, say) then the text alternative would be displayed. Text alternatives for CSS icons should behave the same way.

bnjmnm’s picture

Title: Make icons more robust in Windows high-contrast with Egde, IE, and Firefox. » Devise strategy to address several icon-related issues
Issue summary: View changes
Issue tags: +Needs issue summary update

@wimleers detailed his thoughs on Icon fonts in an early D8 toolbar issue #1963886: Use HiDPI icons in the toolbar

The arguments favoring icon fonts are pretty strong, but Wim pointed out several reasons they are probably not suitable for Toolbar. That said, it may be possible to find a solution that leverages icon fonts in a way that addresses these concerns, or the policy may need to exclude toolbar.

Pasting what Wim said here because we have too many tabs open already.

Requirements (for a Toolbar icon approach)

  1. Drupal modules adding additional entries to the toolbar, with their own icons (i.e. modules extending the set of icons)
  2. Drupal modules altering existing entries in the toolbar (i.e. modules overriding the set of icons)
  3. Drupal themes altering existing entries in the toolbar (i.e. themes overriding the set of icons)
  4. Efficient serving of icons: one HTTP request, not many, keeping the possibility of generating an icon font

Approaches

Approach 1: "icon font"

Implementation
CSS file with classes, with each icon having CSS like such:
.iconfont.icon-something:before {
  content: "\e000";
}

, and with a @font-face declaration for .iconfont so that the inserted character uses the icon font.

Requirements
This fails to meet requirements 1 & 2 — it would require the icon font to be rebuilt dynamically by Drupal.
Notes
This is the path being taken in this issue so far AFAICT, and it's also the path taken by #2032773: Use Libricons (icon font) in Seven, consider using it more broadly in core.

Approach 2: "modules define their (SVG) icons; modules and themes can override them; build CSS dynamically"

Implementation
CSS file with classes, with each icon having CSS like such:
.icon-something {
  background-image: url(data:<URI-encoded SVG here>);
}
Requirements
This meets all requirements.
Notes
It is the only way that I currently see we can meet all requirements. It requires having all icons be specified by owning modules as individual, monochromatic SVG icons (i.e. an .svg file per icon). We could then automatically generate a single CSS file with all icons embedded as data URIs (like #52 already says, but using URI encoding).

However, a side-effect of this approach is that we need some sort of hook or .yml to indicate which icons this module provides. How else can Drupal know how to generate that CSS file? It's less than ideal that we need another "metadata thing", this time for icons, but at the same time that is also utterly essential.

How else will modules be able to override existing entries? How else can a theme override only Drupal core's default icons as well as the icons for modules a and b, and still have the system serve up the default icons for modules x and y?

A contrib module could then *still* override the default CSS generator and generate an icon font instead. Or a site-specific theme could override the default icon CSS file and embed its own optimized icon font.

............

Also, I'm converting this to a broader SVG related issue to avoid us simultaneously working on several SVG related issues only to discover the solutions conflict with one another. I'm choosing to make this one the central one as the most has been discussed here. I did update the issue summary, but still tagging "needs issue summary update" as it could use a bit more.

bnjmnm’s picture

Title: Devise strategy to address several icon-related issues » Devise strategy to address several SVG loading+usage issues
Issue summary: View changes
bnjmnm’s picture

After reading through this and issues covering similar territory, here's what I can gather so far regarding some of the options presented:

Icon Fonts

Despite having many appealing benefits... Between the accessibility issues documented in #14 and the concerns I quoted from @wim-leers in #16, this does not seem like a feasible option.

Icon fonts: Not an option (unless the concerns in #14and #16 can all be addressed)

SVG Sprites

Edge has switched to Chromium, so the multiple requests issue would impact Firefox (3.28% usage) and IE11 (1.44% usage). 4.72% isn't a huge number, but significant enough that SVG sprites would require enough other benefits to justify

#14 mentions that "Firefox will fix this" regarding the SVG sprite multiple-loading problem. I looked the issue and if you filter out the "is this still active" comments, the last activity on this issue was 6 years ago https://bugzilla.mozilla.org/show_bug.cgi?id=1027106. Perhaps @bskibinski is aware of progress not documented in the issue, but based on what I could find it doesn't seem like a fix is imminent.

Maintainability is another concern, particularly for modules like Toolbar that encourage icons from contrib modules extending it.

SVG sprites: Probably not unless there's a strong enough argument to justify the performance hit on 4.72% of browsers.

The remaining choices?

In a hypothetical situation where my assessment is correct and we can rule out SVG sprites and icon fonts, these are the remaining things I can think of that would need to be considered:

  • Inline vs. Not inline
  • background-image: url() vs content: url()

This seems too short a list for the amount of discussion...

Open to hearing why Icon fonts or Sprites should remain in consideration.

bnjmnm’s picture

Here's my take

Based on:
- The many similar conversations had about this topic
- The multiple-request bugs with SVG Sprite
- The accessibility issues with icon fonts
- The difficulty in auditing / reusing inline SVGs

My proposal is to - whenever feasible - use background: url() and request svg images, but add a postcss plugin to convert the url() calls to data uris. Doing this in the build stage maintains the SVGs auditability/reuseability while still providing the benefits of inlining.

In cases where this isn't an option, be it animation or icons that must be visible in high-contrast, exceptions can be made but should be accompanied by a comment stating why.

lauriii’s picture

Status: Active » Needs review
Issue tags: +Needs followup

Good job on making a summary of the previous discussions @bnjmnm!

It seems like there are strong arguments that go against using icon fonts and SVG sprites. While the extendability issues could be overcome, it seems like there are also some accessibility concerns in particular with the icon fonts approach #14. We can reconsider SVG sprites once the performance issues have been resolved in Firefox and IE 11.

It doesn't seem like any of the assessed approaches would be perfect. It seems like the best solution is to continue on the path that we have already taken. I'm glad that we identified that we can resolve some of the concerns by moving SVG icons to individual files and inlining them with PostCSS.

Let's open a follow-up for adding the PostCSS plugin for inlining the SVG images.

bnjmnm’s picture

Did a small IS change to an earlier issue, and that can serve as the PostCSS plugin issue #3085245: Un-inline SVGs in pcss.css files, add build tool to inline them when compiled
Created one for high contrast mode tasks #3130305: Ensure all of Claro's background images are visible in forced colors mode.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

justafish’s picture

StatusFileSize
new68.11 KB
new351.58 KB

I can't reproduce that Firefox cache issue in neither Firefox for Linux (75) nor Mac (76.0.01)
https://justafish.github.io/sprite-test/
https://github.com/justafish/sprite-test

Example of sprite caching in Firefox for Mac
Example of sprite caching in Firefox for Linux

bnjmnm’s picture

The example in #24 also works fine for me in Firefox. The Firefox bug is documented here https://bugzilla.mozilla.org/show_bug.cgi?id=1027106 and still open, I'm unsure if this means the bug was fixed in a different issue or there's an implementation difference.

bnjmnm’s picture

Confirmed it is still an issue and it is specific to fragments in css background images https://bbenjamin.github.io/bnjmnm/. One request on not-FF, three requests in FF. (yes, the SVG I quickly used to test doesn't have fragments in it, but the presence of a fragment identifier replicates the issue regardless).

Even if there was a postcss solution that used something other than fragments to access parts of a sprite (not sure if this exists...), our current plan to auto-inline svg css background images will similarly reduce requests.

ambient.impact’s picture

I've been using SVG sprites inlined as <use> which reference an SVG file with icons defined as <symbol>s for a few years now after looking at all the pros and cons of the various solutions. While I'd have preferred to use a pure CSS solution, I think that approach loses a lot of flexibility, especially the ability to recolour and transform icons. You can see my icon system on my site, which I use from the more obvious (Drupal, GitHub, and GitLab logos in the content; the social icons at the bottom) to less so (the drop-down menu arrows). More extensive use can be seen on my snippets page.

Specifically to this discussion, back before migrating to Drupal 8, I heavily altered the Drupal 7 backport of the toolbar (a.k.a. the Navbar project), which you can see in this comparison video I made. Note how the new icons (on the second site) can have transform transitions and have no loading on hover/focus because it's just recolouring the existing icon, not loading anything new. The code itself for that project was pretty hacky, so I'd love to see some sort of proper, extendable way to alter the icons and provide our own implementation, if possible, but I'd very much recommend the inlined <use> method. If you're curious about my Drupal 8 system, you can find it in my GitHub repo.

lauriii’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs issue summary update, -Needs followup

Updated the issue summary with the conclusion. We can also remove the needs followup tag because the followup was opened in #22.

lauriii’s picture

Status: Reviewed & tested by the community » Fixed

I think we have given people enough time to provide feedback on this, especially given that we're not proposing that significant of a change at all. Usually, decisions like this would be posted on g.d.o but in this case it might not make sense given that we're just making a decision to continue more or less what we have done before. Let's focus next on #3085245: Un-inline SVGs in pcss.css files, add build tool to inline them when compiled.

lauriii’s picture

Updating credits

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

mherchel’s picture

Adding a comment here for posterity that the content: url() technique does not work for Chromium versions of MS Edge (or really any Chromium browsers).

In my opinion the easiest method is to use mask-image. Note that this isn't supported under IE11, but we can do this with Drupal 10.

Example:

https://codepen.io/mherchel/pen/PoEbxeR