-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Current state
Historically we have CSS class based icons, but they suffer one major issue:
They are hard to theme, meaning for dark mode or even for users primary color.
So to overcome this issue we switched to inline SVGs for icons, as they can be themed just with CSS and adjust automatically to the current theme.
Problems
The first problem we at least had in the past is that we have inconsistent design across apps, because some used icons provided by server (css classes), some Material Design Icons and some already Material Symbols.
The bigger problem is when we want to change the icon set used, like at the time of writing the long term goal in design is to move from MDI to Material Symbols. Changing icons need every app, every component and potentially API to be adjusted to use a different library with potentially different names.
Also implementation wise this currently leads to various approaches which are often mixed:
- Use
vue-material-design-icons-> Vue components of SVGs - Use
@mdi/svg-> use of inline SVG files which are then rendered by e.g.NcIconSvgWrapper - Use
@mdi/js-> inline SVG but we try to circumvent the problem of bigger bundle size due to inline SVGs by only using thepathof the SVG. - Use legacy icon classes provided by server (e.g. also used by some API like the contact menu)
To sum up:
- Inconsistent icon design
- Hard to switch to different icons
- also means no customization possible (branding)
- Increased app bundle sizes due to inline SVG graphics into code
- SVGs cannot be returned in API as this bloats the requests when a common icon is used
- Code complexity to support all those ways
Solutions
Seeing those problems and also the initial problem with icon classes I came up with this two options that enhance the current situation:
Unify to SVG and provide a common @nextcloud/icons SVG package
- Pro:
- allows to change the icons based on a version of the package
- allows to return common identifier from API that resolves to an SVG icon controlled by us
- only one way to apply icons
- Con:
- still no customization (branding)
- still bigger app bundles
Unify to server provided SVG icons
Similar to the previous idea this one is a bit different, here we do not provide a package with those SVGs but instead we use a modern approach and let the server provide an icon sprite that is used by SVGs of the apps.
- Pro:
- allows to change the icons based on the server version
- theoretically even allows to change the icon sprite by admin (branding)
- allows to return common identifier from API that resolves to an SVG icon controlled by us
- apps no longer need to bundle the icons thus slightly smaller bundles and faster JS parsing
- Con:
- first time loading the icon sprite is another (but cached!) HTTP request
Proposed solution
We move icons into server as mentioned above - this way the server is the only source of truth for icon design.
Meaning apps no longer need to care about package versions or design changes.
With SVG <symbol> it is possible to group multiple icons into one SVG file which looks like:
<svg>
<symbol id="arrow-up">
<!-- the content of that icon -->
</symbol>
<!-- more icons -->
</svg>This file can easily be generated by already existing tools.
Then in your HTML you can refer the icon you like with:
<svg style="width: 20px; height: 20px; fill: currentColor;">
<use href="/core/img/icons.svg#arrow-up" />
</svg>The benefit here is that any migration would be quite easy:
- API expects an SVG? Just pass the icon svg as show above - could be done with a shared method.
- API only provides a icon class? No problem we can now keep that API and just use the icon IDs where WE controll the name
- We can easily create a component for this
To sum up this would - from my point of view - make working with icons much easier:
- we have all benefits of inline SVGs
- we have the benefit of small API responses (icon names only)
- we can use branding
- we can change design based on server - so apps will always look good even if they support multiple versions
Further reference
- Its supported widely: https://caniuse.com/svg-fragment
- Existing discussions:
- Example tool for sprite generation: https://github.com/svg-sprite/svg-sprite