Transparent JPG (With SVG)

Avatar of Chris Coyier
Chris Coyier on

Let’s say you have a photographic image that really should be a JPG or WebP, for the best file size and quality. But what if I need transparency too? Don’t I need PNG for that? Won’t that make for either huge file sizes (PNG-24) or weird quality (PNG-8)? Let’s look at another way that ends up best-of-both-worlds.

The original photographic image.

The goal is to clip myself out of the image, removing the background. My technique for that is usually to use Photoshop and cut a clipping path manually with the Pen tool.

Now I can select the inverse of that clipping path to easily remove the background.

Attempting to save this as a 1200px wide image as PNG-24 out of Photoshop ends up as about a 1MB image!

1MB is huge :(

We could cut that by 75% using PNG-8, but then we 1) get that weird Giffy look (less photographic) and 2) have to pick a matte color for the edges because we aren’t getting nice alpha transparency here, just binary transparency.

Much better file size, but quality is weird.

Gosh what if we could just use JPG? The quality and file size is way better.

No transparency though.

But wait! Can’t we just clip this thing out? We have clip-path now. Well… yeah. We do have clip-path. It can’t take a path(), though, and what we’ve created for vector points in Photoshop is path data. It could take a polygon() though, if we made all the lines straight. That’s probably not ideal (I’m curvy!). Or we could make a <clipPath> element in some inline SVG and use clip-path: url(#id_of_clipPath);, which does support a <path> inside.

There is masking as well, which is another possibility.

Let’s look at a third possibility though: put everything into <svg>. That made some logical sense to me, so all this stays together and scales together.

The trick is to make two things:

  1. The JPG
  2. The clipping <path>

The JPG is easy enough. Output that right from Photoshop. Optimize.

Now we can set up the SVG. SVG is happy to take a raster graphic. SVG is known for vector graphics, but it’s a very flexible image format.

<svg>
  <image xlink:href="/images/chris.jpg" x="0" y="0">
<svg>

To get the path, we export the path we created with the Pen tool over to Illustrator.

Now we have the path over there, and it’s easy to export as SVG:

Now we have the path data we need:

Even with all those points, this was 1.5K unoptimzed and ungzipped. Not much overhead.

Let’s use that <path> within a <clipPath> in the SVG we’ve started. Then also apply that clip path to the <image>:

<svg viewBox="0 0 921.17 1409.71">
  <defs>
    <clipPath id="chris-clip">
      <path d=" ... " />
    </clipPath>
  </defs>
  <image xlink:href="/images/chris.jpg" clip-path="url(#chris-clip)" x="0" y="0" width="921" height="1409">
<svg>

Tada!

A transparent JPG, essentially.