Inline SVG in HTML5

In my quest to reduce the bandwidth used by my blog entries, I have reduced the user-pic from 42 KB to 6 KB using inline SVG.

One of the things I wanted to do was have a border on the image that was neither rectangular nor elliptical but instead some approximation to a superellipse.

The significance of rectangles and ellipses is they are shapes you can do easily in CSS by setting border-radius but having no actual border, since CSS borders have the side effect of clipping the content of the box.

The other usual way to do non-rectangular images it to use a PNG file, so you can use the alpha channel to make the part of the image outside the desired shape transparent (since JPEG does not have an alpha channel). The downside with using this with a photograph is that PNG does not compress photos as well as JPEG does.

My solution is to use SVG to apply a clipping path to the JPEG image, using something like this:

<svg xmlns=""
        width="100%" height="100%"
        viewBox="-1 -1 2 2">
        <clipPath id="s">
            <path d="M1,0 C1,1 1,1 0,1 S-1,1 -1,0 -1,-1 0,-1 1,-1 1,0Z"/>
    <image x="-1" y="-1" width="2" height="2" clip-path="url(#s)"

The gist of this is that the image has a clip path set to the one in the defs section. This uses a cubic Bézier (the C command in the path) with both its control points at the corners of the square (1, 1) to represent on quarter, then three S commands to repeat this for the other three quarters. I can’t be bothered to work out how much this is or isn’t a match for a genuine superellipse: it looks good enough for my purposes.

1 −1 −1 1

With modern browsers this can be embedded directly in the HTML of the page, which is convenient because it means I can use Django‘s static tag to get the URL of the image file correct. It can also be sized using CSS like any other content. Very civilized.

The right-sized JPEG image is 5.6 KB (compared with 42.3 KB for the PNG). The svg fragment is slightly longer than the img tag it replaces, but only by a few hundred bytes. Overall this shaves a little more than 36 KB from the first uncached view of my blog pages.