Skip to main content

Responsive Logo Composition With SVG

By Tyler Sticka

Published on April 20th, 2016

Topics

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>Code language: HTML, XML (xml)

Let’s break down how this is working.

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>Code language: Handlebars (handlebars)

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>Code language: HTML, XML (xml)

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>Code language: HTML, XML (xml)

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

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;
  }
}Code language: CSS (css)

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.

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">Code language: Handlebars (handlebars)

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%;
}Code language: CSS (css)

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.

Comments

Mario Grandioso said:

Is there any way to use SVG logo in a mobile native app? As far as I know iPhone supports only PDF, Android from version 5+. Windows? Does it mean that I have to export logo in different formats for different OS and versions?