Icons have a storied history on the web. In the bad old days, they were treated like any other images on a web page, implemented using individual image elements. This carried several negative implications, among them poor semantics and excessive HTTP requests as every icon image on a page were loaded separately. A much-improved method emerged with image replacement using CSS, pseudo-elements, and sprites. A CSS-based approach left HTML semantics undisturbed, and sprite images cut down on unnecessary asset requests with single large images combined with background positioning, instead of an image per icon.
Of course, even the CSS sprite technique still has the chief downfall that it’s image-based. This means that image editing software is required to create or edit sprites, whether or not you are creating your own icons or pulling them in from elsewhere. It also means that at the end of the day your icons are a flat set of pixels, subject to resolution limitations. (Note the Magento 1 responsive theme’s use of two distinct sizes of sprite image, in order to accommodate high pixel density displays like Retina devices.) An approach fast gaining wide adoption today, which cuts images out of the story entirely, is that of icon fonts. Magento 2’s native theme fully embraces this technique.
Using fonts for icons makes sense for a lot of reasons. In reality, iconography has always had more in common with text than content images; icons are glyphs that communicate meaning to the audience. And in technical terms, font glyphs are vector information that can scale up to any resolution. Of course, if you’re a web developer used to working with image-based icons, it’s likely that you have no small degree of discomfort with generating your own font files. Luckily, the growing adoption of icon fonts means there are great tools available for you. The native Magento theme provides the framework you need for implementation, and in this article, I’ll introduce you to a foundation that will leave you even better equipped for customizing Magento’s icons easily.
You’ll find the icon font files for the Magento Blank theme in
lib/web/fonts/Blank-Theme-Icons (in the typical multiple file formats to support all user agents).
lib/web/css/source/lib/variables/_typography.less defines the font icon path and name, and in the Magento Blank theme
web/css/source/_icons.less uses these to define the icon font face itself, to be used in all CSS declarations.
The final relevant piece to be aware of is
lib/web/css/source/lib/variables/_icons.less, where LESS variables are defined to store the Unicode characters that correspond to the right font glyphs for each icon. This will be a handy reference for you when needing to re-assign said character codes to new icons.
The defined icon font face and the character variables are used throughout the theme LESS code to define icons, usually through a call to the
Armed with this info about the CSS structure for customizing icon fonts, you’ve got a great starting point; change the variables defining the icon font path and name, and you’ve successfully replaced the native icons with your own. But that still leaves the question of how to generate your own icon font in the first place.
You’ve got two main options for defining custom icons for your Magento theme: Create your own, or cherry pick some from available libraries. There are online tools that support either approach and allow you to wrap up your custom creation in a final font. A great example, and the one covered here is IcoMoon.
This font generation tool has a number of free and paid icon sets from which you can pick and choose. It also supports other features important for your Magento icon customization: importing of existing fonts, importing of your own custom icon SVGs, and importing/exporting your selections as JSON-based configuration, so that you can pick up straight from an already configured icon set. IcoMoon also features a fairly robust editing interface for adjusting the scaling and positioning of individual icons.
Using IcoMoon, you can start with an imported font like Magento’s native icons, make your desired tweaks by removing some and adding others, and then re-export a finished font. Of the five file types that Magento makes available natively, IcoMoon’s are missing only woff2. That’s not a problem, though, since there are plenty of tools out there for font file type conversion as well. Try Everything Fonts. IcoMoon’s final package handily includes JSON configuration and example CSS as well, though you’ll be eschewing said CSS in favor of Magento’s native structure.
I said earlier that, once you’ve got your custom icon font in hand, replacing Magento’s native icons would be as simple as setting the right LESS variables for the font path and name. It would be great if that were the case. Unfortunately, if you’re using Magento Blank as your theme starting point and plan to customize it with available libraries, you’re likely to run into a snag: the size of the icons in the Blank font relative to their bounding box is significantly smaller than the typical fonts you’ll find on IcoMoon. Combining drop-in replacements with the font sizes and line heights in the Blank theme will result in unusually large icons compared with the spaces where they’re used.
There are two ways to approach this problem. The first is to scale down any icons you are using in your custom set using IcoMoon’s aforementioned editing interface. With this approach, you avoid any CSS changes, but you’ll have to touch every icon you wish to include in your custom font.
The second approach is to customize CSS font sizes and line heights to match the more typical icon sizes. This has the benefit of not needing to worry about sizing icons every time you drop a new one in, but it carries some up front overhead. It would be nice if a few typical icon sizes were defined in LESS variables for just such a customization. Unfortunately, the definition of these sizes is considerably more scattershot throughout the various module LESS source files in Magento. It’s a lucky break, then, that the Magento Luma example theme contains a more typically sized icon font, along with corresponding font sizes.
If you want to extend the leaner, more vanilla Magento Blank with your theme instead of extending Luma, the latter at least provides an appropriate boilerplate from which to extract the right styles to normalize icon sizes. And that’s exactly what I’ve done in this starter theme package. This theme extends Blank but uses the Luma icon font, containing appropriate CSS resets for sizing. You will note that these resets are contained within the theme’s
_extend.less, meaning that it supersedes rather than replaces the baseline styles. While this leads to slightly more bloated compiled CSS, it’s a trade-off to avoid entirely duplicating a myriad of core theme files, since the vast majority of styles in said files won’t change from Blank. (The resulting
_extend.less also provides a precise reference for which relevant styles should be tweaked if further re-sizing is needed.)
Note that this package is a work in progress, and you may find areas I’ve missed where further size tweaking is needed.
Because of the sizing issue with the Blank theme, you should first decide which of the following approaches you want to take with your custom icons:
Which approach is best? That probably depends on how many icons you intend to customize with drop-in replacements. If you’re replacing only a few, Approach A may work best for you. If you’re really giving your theme a distinct flavor with a wholesale new icon set, though, Approach B or C may be the way to go.
If you’re using Approach C, obtain this starter icon theme. You can install and extend this theme, or copy its styles directly into your own theme.
lib/web/css/source/lib/variables/_icons.less. (If you’re uncertain which character codes match which icons, you can take note of them in your initial imported font before removing the originals.)
web/css/source/_theme.lessin your theme, set
@icons__font-nameappropriately with the file path and name of your new icon font.
web/css/source/_extend.lessto implement these tweaks.