Magnus
Magnus

Reputation: 7821

Responsive SVG viewBox

I made a "hamburger button" in SVG, as seen below.

body {
  margin: 0;
  text-align: center;
}

svg#ham-btn {
  margin: 2rem;
  border: 1px solid black;
  fill: #383838;
}
<svg id="ham-btn" width="107.5px" height="80px" viewBox="0 0 80 80" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
  <style>
    #ham-btn {
      cursor: pointer;
    }
    #ham-btn:hover #r1 {
      outline: 1px solid transparent;
      transition: transform 0.2s;
      transform-origin: 50% 50%;
      transform: rotate(37deg) translate(0%, 28.75%) scaleX(1.1);
    }
    #ham-btn:hover #r2 {
      transition: transform 0.2s;
      transform: translate(120%, 0);
    }
    #ham-btn:hover #r3 {
      outline: 1px solid transparent;
      transition: transform 0.2s;
      transform-origin: 50% 50%;
      transform: rotate(-37deg) translate(0%, -28.75%) scaleX(1.1);
    }
    
  </style>
  <rect id="r3" x="0" y="71.25%" width="100%" height="15%" rx="5%" />
  <rect id="r2" x="0" y="42.5%" width="100%" height="15%" rx="5%"/>
  <rect id="r1" x="0" y="13.75%" width="100%" height="15%" rx="5%" />
</svg>

Question

Right now, if I want to make the button smaller, I have to manually make the dimensions of the viewport and viewBox smaller by the same amount of px.

Is there any way to make that more responsive? For instance, by making viewBox be a percentage of the viewport?

According to the spec, it seems viewBox has to be a <number>, and thus cannot be a percentage.

Any thoughts?

Thank you.


Note 1

I have not added any accessibility or other features to the button. This question is about its responsiveness.


Note 2

I know I can make the SVG viewport a percentage of its container / the browser viewport.

That does not solve my issue unfortunately, as to make this button work my viewBox-to-viewport ratio must stay fixed (otherwise the button looses its shape).

Thus, I wanted to make the viewBox be a percentage of the viewport.

In case it is of interest, my solution takes advantage of the following:

The outline is to fix a Firefox issue with jagged lines after transform.


Edit:

In case helpful to future visitors, the final button, including full accessibility, can be found here: https://codepen.io/magnusriga/pen/KrrJKa

Upvotes: 4

Views: 15526

Answers (2)

enxaneta
enxaneta

Reputation: 33044

As I've told you in my comment: I would remove the width and height of the svg element. Then in CSS I would made SVG's width:20%. I'm making the SVG's width 50% of the width of the window.

In order to keep the proportions I've putted the "hamburger" inside a <symbol viewBox="0 0 80 80">. Of coarse in this case you don't need preserveAspectRatio="xMidYMid meet" anymore.

body {
  margin: 0;
  text-align: center;
}

svg#ham-btn {
  width: 20%;
  margin:auto;
  top:0;bottom:0;left:0;right:0;
  border: 1px solid black;
  fill: #383838;
  position:absolute; 
}
<svg id="ham-btn" viewBox="0 0 107.5 80" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
  <style>
    #ham-btn {
      cursor: pointer;
    }
    #ham-btn:hover #r1 {
      outline: 1px solid transparent;
      transition: transform 0.2s;
      transform-origin: 50% 50%;
      transform: rotate(37deg) translate(0%, 28.75%) scaleX(1.1);
    }
    #ham-btn:hover #r2 {
      transition: transform 0.2s;
      transform: translate(120%, 0);
    }
    #ham-btn:hover #r3 {
      outline: 1px solid transparent;
      transition: transform 0.2s;
      transform-origin: 50% 50%;
      transform: rotate(-37deg) translate(0%, -28.75%) scaleX(1.1);
    }
    
  </style>
  <symbol id="s" viewBox="0 0 80 80"> 
  <rect id="r3" x="0" y="71.25%" width="100%" height="15%" rx="5%" />
  <rect id="r2" x="0" y="42.5%" width="100%" height="15%" rx="5%"/>
  <rect id="r1" x="0" y="13.75%" width="100%" height="15%" rx="5%" />
  </symbol>  
  
  <use xlink:href="#s"  width="80" x="13.75"/>
</svg>

Upvotes: 1

Ludovit Mydla
Ludovit Mydla

Reputation: 822

Add width & height properties to your svg css. With width set and height auto.

body {
  margin: 0;
  text-align: center;
}

svg#ham-btn {
  margin: 2rem;
  border: 1px solid black;
  fill: #383838;
  /* percentage of viewport - height will autocalculate */
  width: 7vw;
  height: auto;
}
<svg id="ham-btn" width="107.5px" height="80px" viewBox="0 0 80 80" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
  <style>
    #ham-btn {
      cursor: pointer;
    }
    #ham-btn:hover #r1 {
      transition: transform 0.2s;
      transform-origin: 50% 50%;
      transform: rotate(37deg) translate(0%, 28.75%) scaleX(1.1);
    }
    #ham-btn:hover #r2 {
      transition: x 0.2s;
      x: 120%;
    }
    #ham-btn:hover #r3 {
      transition: transform 0.2s;
      transform-origin: 50% 50%;
      transform: rotate(-37deg) translate(0%, -28.75%) scaleX(1.1);
    }
    
  </style>
  <rect id="r3" x="0" y="71.25%" width="100%" height="15%" rx="5%" />
  <rect id="r2" x="0" y="42.5%" width="100%" height="15%" rx="5%"/>
  <rect id="r1" x="0" y="13.75%" width="100%" height="15%" rx="5%" />
</svg>

Upvotes: 3

Related Questions