Logos are an ideal use-case for SVG. Because they’re typically designed for reproduction and versatility, they’re almost always vector to begin with. SVG’s support of CSS and media queries means we can adapt brand imagery depending on the display size, a technique artfully documented by the likes of Andreas Bovens, Ilya Pukhalski, Sara Souedian and Ana Sampaio.

But what if we want to re-arrange our logo elements depending on the aspect ratio of the asset, perhaps to account for the amount of vertical real estate available to us?

We could use two separate image assets, recomposing them using the float , display or position properties, but that makes it difficult to scale both assets together. We could also use the <picture> element, but that requires two different image files and awareness of how large the image will be relative to the viewport.

Is it possible for a single SVG (embedded as an <img> ) to adapt to the aspect ratio of its dimensions in-page?

Turns out, yes! Here’s a demo:

The <img> element is sized using percentages. Notice how the image contents scale to meet the nearest edge of their container, re-composing when the aspect ratio has changed significantly.

The demo source itself is unremarkable. The magic’s in the SVG file:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <style> #emblem { fill: #39cccc; } #word { fill: #225b6d; } #wide { visibility: hidden; } @media all and (min-aspect-ratio: 3/1) { #wide { visibility: visible; } #tall { visibility: hidden; } } </style> </defs> <symbol id="emblem" viewBox="0 0 51 60"> <polygon points="31 38.43 46 29.52 46 35.23 31 44.13 31 51.02 51 39.5 51 20.7 31 32.21 31 38.43"/> <polygon points="50.88 15 25.44 0 0 15 0 45 25 60 25 30 50.88 15"/> </symbol> <symbol id="word" viewBox="0 0 200 26"> <path d="M16.72,0.14V5H5.11v5.25h9.41v4.83H5.11v5.82H16.72V25.7H0V0.14H16.72Z"/> <path d="M24.21,25.7H18.64l7.67-13.1L18.85,0.14h6L29.57,8.2l4.72-8.06h5.57L32.45,12.92,40.08,25.7h-6l-5-8.45Z"/> <path d="M46.43,25.7H41.14L49.38,0.14h6L63.58,25.7h-5.5L56.41,20H48.14Zm3.12-10.58H55l-2.7-9.37Z"/> <path d="M91.38,25.7H86.55v-17L81,21.62H77.32l-5.54-13v17H66.95V0.14h5.61l6.6,15,6.6-15h5.61V25.7Z"/> <path d="M110,0.14a4.81,4.81,0,0,1,5,5v6.46a4.81,4.81,0,0,1-5,5h-8v9H97V0.14H110Zm-1.28,11.72A1.09,1.09,0,0,0,110,10.65V6.18A1.09,1.09,0,0,0,108.77,5h-6.67v6.89h6.67Z"/> <path d="M124.32,0.14V20.88H135V25.7H119.2V0.14h5.11Z"/> <path d="M155.63,0.14V5H144v5.25h9.41v4.83H144v5.82h11.61V25.7H138.91V0.14h16.72Z"/> <path d="M172.31,6a1.09,1.09,0,0,0-1.21-1.21h-5.54A1.09,1.09,0,0,0,164.36,6V19.81A1.09,1.09,0,0,0,165.57,21h5.54a1.09,1.09,0,0,0,1.21-1.21V16.69h5.11V20.8a4.81,4.81,0,0,1-5,5h-8.09a4.81,4.81,0,0,1-5-5V5a4.81,4.81,0,0,1,5-5h8.09a4.81,4.81,0,0,1,5,5V9.16h-5.11V6Z"/> <path d="M195,0a4.81,4.81,0,0,1,5,5V20.8a4.81,4.81,0,0,1-5,5H186.4a4.81,4.81,0,0,1-5-5V5a4.81,4.81,0,0,1,5-5H195Zm-0.07,6a1.09,1.09,0,0,0-1.21-1.21h-6A1.09,1.09,0,0,0,186.47,6V19.81A1.09,1.09,0,0,0,187.68,21h6a1.09,1.09,0,0,0,1.21-1.21V6Z"/> </symbol> <svg id="wide" viewBox="0 0 260 60"> <use xlink:href="#emblem" width="51"/> <use xlink:href="#word" width="200" x="60"/> </svg> <svg id="tall" viewBox="0 0 200 130"> <use xlink:href="#emblem" x="60" width="80" height="92"/> <use xlink:href="#word" y="104" width="200" height="26"/> </svg> </svg>

Let’s break down how this is working.

1. Making Our Container Responsive

Because we’re going to change the dimensions of our logo depending on the container size, we can’t have any attributes that suggest a size or aspect ratio up-front. This means no viewBox , width or height .

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>

2. Adding Reusable Elements

Both logo variations use the same two assets: The hexagonal mark, and the “ExampleCo” type. Because our container has no inherent dimensions, we’ll store these assets as <symbol> elements with their own viewBox . We use CSS to style both symbols.

<defs> <style> #emblem { fill: #39cccc; } #word { fill: #225b6d; } </style> </defs> <symbol id="emblem" viewBox="0 0 51 60"> <!-- (paths, etc.) --> </symbol> <symbol id="word" viewBox="0 0 200 26"> <!-- (paths, etc.) --> </symbol>

3. Creating “Wide” and “Tall” Compositions

Now that we have all our ingredients, we can arrange them using <svg> elements, each with its own viewBox attribute:

<svg id="wide" viewBox="0 0 260 60"> <use xlink:href="#emblem" width="51"/> <use xlink:href="#word" width="200" x="60"/> </svg> <svg id="tall" viewBox="0 0 200 130"> <use xlink:href="#emblem" x="60" width="80" height="92"/> <use xlink:href="#word" y="104" width="200" height="26"/> </svg>

At this point, both compositions will be visible all of the time.

4. Hiding or Showing Based on Aspect Ratio

We return to the <style> element, using the visibility property and min-aspect-ratio to determine when to hide or show each variation:

#wide { visibility: hidden; } @media all and (min-aspect-ratio: 3/1) { #wide { visibility: visible; } #tall { visibility: hidden; } }

By default, the “tall” variation will be visible. If the asset is at least three times wider than it is tall, the “wide” variation will be visible instead.

5. Displaying in Our Page

With our asset complete, we can include it in our page. We should also provide a default width and height in case styles fail to load (since we haven’t specified any in the SVG asset itself):

<img id="logo" src="logo.svg" alt="ExampleCo" width="200" height="130">

We’re now free to style the width and height of the image however we like. The demo uses percentages:

#logo { display: block; height: 33.3%; width: 100%; }

Is This a Good Idea?

Sometimes! It’s super flexible, only takes one request, caches beautifully and works in IE 9 and above.

That said, media queries in external SVG elements without a viewBox can be rather finicky. If I wanted more than two compositions, I would definitely consider using <picture> instead.