1. 程式人生 > >Flexible Icons with React + SVG

Flexible Icons with React + SVG

Flexible Icons with React and SVG

I am old enough to remember when IE didn’t properly support transparency in PNG files. I am old enough to remember when PNGs were new, a better alternative to GIFs. I am old enough to remember spacer GIFs. These weren’t just things I read about, they were problems I had to work around at my job as a software developer. #dark

The web has matured in a million different ways since the 2000s, and things that used to be hard or a pain are now quite easy. Even though new and shiny tech exists, it does not mean companies are immediately taking advantage of all of it. Getting an entire organization to change their workflow or setup is still hard.

We have been upgrading a lot of our workflows at The New York Times in the past two years, and most of The Times is now served via Node and React. In switching to React, we have been able to unlock entirely new techniques for rendering our UIs. I would like to focus on one of them: rendering icons and logos as SVG.

SVGOMG makes optimizing SVG files easy!

Logos

A logo is often provided by a designer. If it’s an image file, it is typically a PNG with transparency. If you live in a modern world, the logo is provided to you as a scalable vector graphic (SVG). We prefer SVG because it means we can change the size of the image without degrading its quality (and without having to go back to Photoshop or Sketch). It also means we can change the color(s) of the logo without exporting a new file. However, most of the SVGs we as developers receive from designers do not make this so obvious. It is also not always apparent what the “best practice” is here. When do I use SVG? How do I use SVG?

If you’ve never interacted with the contents of an SVG file, MDN has great docs and tutorials, as per usual.

SVG is HTML

Remember one thing: SVG is HTML and HTML attributes can be dynamic in React. We use React to render SVG (since it’s HTML!).

All of this being true, our redesign of The Times over the past few years still suffered from a problem: for each logo, designers tended to make a new file if they needed a new color or if they needed a different size. We ended up with a gang of files like:

icon-t-logo-16x16-333333.svgicon-t-logo-16x16-white.svgicon-t-logo-64x64-333333.svgicon-t-logo-64x64-white.svg

One icon I found had eight variations, which meant it had eight files. When you open one of these files, you see the inner brain of the design program trying to make sense of a line drawing:

Just like you wouldn’t accept the HTML output of Dreamweaver as law, you don’t need to accept this SVG content as law. Most of the output you get from design programs contains extraneous and unfortunate-looking XML.

SVGOMG

You can get rid of this junk by running the file or its contents through SVGOMG, an online GUI for manipulating and optimizing SVG.

I usually just paste the markup of a file into the “Paste Markup” tab. After doing so, you get a preview of your icon and a chance to copy the optimized output. After pasting the above file, I got this markup:

As you can see, our icon can actually just live as one <path> element. The d attribute value is simply a list of instructions: the numbers act as offsets, the letters tell the numbers how to behave.

viewBox describes our icon’s area: 0 0 16 16 means that the numbers in d are related to an area 16 pixels by 16 pixels in dimension. It does not mean that the icon is limited to being 16 pixels by 16 pixels, it means that the instructions have a relationship with this theoretical size.

We also notice that the color of the icon is controlled by the fill attribute. It should be obvious by now, but changing the value of fill will make the icon a different color. That’s great and all, but how are we supposed to change the color if the contents of the SVG are in a static file?

SVG as React

This is where React comes in. Because SVGs are just HTML, and JSX is HTML, we can use SVG like any other nugget of HTML. Here’s our logo as a React component:

We now have a React component that encapsulates our icon, and gives us the ability to change the value of fill with a property. We can use CSS to do whatever else we want to the icon, including setting a different width and height.

As you can see, we never need to create another file whenever we want to change size or color. I’m using CSS-in-JS in these examples — if the syntax is foreign to you, take a glance here:

You can even change the value of fill using CSS since path is just an HTML element and fill is a CSS rule:

The logo in the masthead of The Times’s website works exactly this way. All of these logos are the same React component: