Interactive SVG viewport dimension

Check out my "hamburger button" made in SVG, shown 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>

I have a question:

Currently, if I want to resize the button, I need to adjust both the dimensions of the viewport and viewBox manually by the same amount of pixels.

Is there a way to make this more adaptable? Perhaps by setting viewBox as a percentage of the viewport?

Based on the specification, it appears that viewBox can only be a numeric value and cannot be expressed as a percentage.

Any ideas or suggestions are welcome!

Thank you for your input.


Note:

Accessibility and additional features have not been implemented in this button yet. The focus is solely on making it responsive.


Additional Information:

I am aware that I can set the SVG viewport size relative to its container or the browser window.

However, this approach does not resolve my issue since maintaining a fixed ratio between the viewBox and viewport dimensions is crucial for the button's shape retention.

Therefore, my goal was to define the viewBox as a percentage of the viewport.

In case you are curious, here are some key aspects of my current solution:

  • The viewBox is wider than the viewport but shares the same height
  • To horizontally center the rects, the preserveAspectRatio property is utilized
  • Dimensions of the rects are defined in relation to the viewBox

An outline has been added to address jagged lines observed in Firefox after applying transformations.


Edit:

If future visitors find it helpful, the finalized version of the button, including comprehensive accessibility features, can be accessed through this link: https://codepen.io/magnusriga/pen/KrrJKa

Answer №1

To make your SVG responsive, add the width and height properties to your CSS. Set the width and let the height adjust automatically.

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>

Answer №2

Just a heads up, I would suggest removing the width and height specifications from the svg element. Instead, adjust the SVG's width using CSS to be 20% of the window width. This way, you can maintain proper proportions without needing to include

preserveAspectRatio="xMidYMid meet"
.

To ensure consistency in sizing, I've enclosed the "hamburger" icon within a

<symbol viewBox="0 0 80 80">
. With this setup, you won't require the preservation aspect ratio attribute 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The alignment of list bullets is inconsistent across different web browsers

Check out this code snippet on JSFiddle: http://jsfiddle.net/PZgn8/8/. It's interesting to see how the rendering differs between Chrome 27 and Firefox 21. Despite the difference, I believe Firefox is actually displaying the desired outcome. <ul st ...

Horizontal JQuery Slider for CategoriesDiscover the smooth, sleek category navigation with

Looking to create a sliding horizontal menu with various categories using a clever div layer setup. The goal is to have one fixed-width div containing another wider div, with only a portion of the second one visible at a time. Encountering two challenges ...

Is it possible to incorporate a label within a dropdown menu (<select>)?

How can I add a label inside a select box using Bootstrap? Here is an example: Before selecting an option After selecting an option, the label should appear in a small size like this: After selecting an option : <div class="form-group"> & ...

What is causing the left scroll to not work with negative values?

My design features three blocks stacked on top of each other with an additional block at the bottom below the middle. Left <--------> Middle<---------->Right -----------------Bottom------------------ I have a couple of queries. Why is scr ...

The menu seems to be off-center

I'm struggling to center my menu/navigation bar horizontally. I can't seem to figure out what mistake I've made or what I've forgotten. Additionally, there is right padding after my last list item. How can I get rid of it? HTML <di ...

The XPath for the span element

Is there a way to obtain the Xpath of the specific element below? <div class="datum"> <span>180 KM</span> </div> The desired value is "180 KM". I am struggling to extract it because the span element lacks a name at ...

Mastering the art of horizontal alignment for button and ul elements

I aim to create a unique layout that appears as follows: [the button][world1][world2] The code provided is in HTML format: <div id='container'> <button id='my-button'>the button</button> <ul id='my-ul&a ...

The method I used to position a triangle at the bottom border of a parent element with relative

https://i.stack.imgur.com/RZjJ9.png I am trying to achieve a centered triangle within a border, but I am facing a challenge due to the parent component being relative. When I remove the relative positioning, I struggle to position the triangle in the cent ...

Display the JSON result from a RESTful API call within an Ionic framework

I am facing a challenge in displaying a JSON response retrieved from a RESTful API request. Below is the code snippet: products:Observable<any>; constructor(public navCtrl: NavController, private backgroundGeolocation: BackgroundGeolocation, public ...

Retrieve the Data from Input Fields with Matching Classes and Transmit to a Script Using AJAX Request

I am working on a form that includes multiple input fields: <input type="text" class="date" name="date[]" onkeyup="showHint()" /> <input type="text" class="date" name="date[]" onkeyup="showHint()" /> <input type="text" class="date" name="da ...

How can I successfully transfer all user information when the edit button is clicked?

A new display page has been developed using php to show all user records in a table. The page includes delete and edit buttons for managing users. While the delete option is working fine, there is an issue with getting the edit button to function correctly ...

Attempting to transfer a string variable into a JavaScript scope within an HTML document using handlebars-express

Struggling to pass a variable from server-side to client-side using handlebars-express... After searching through the content here for some time, I realize I might need some help. I've confirmed that the object passed is indeed of string type, but h ...

Displaying every nth image in a new row of a CSS grid

I have a react component and I want to arrange 3 photos inline in a row with their names below each photo, and then continue in new rows for the next set of 3 elements and so on... I attempted to use :nth-child(3n+1) but encountered some issues... const P ...

Submitting HTML elements from a webpage using PHP

Is there a way to store an entire HTML table as a single record in my database? I would like the following table data to be submitted when I click the submit button: <table> <tr><td>Items</td></tr> </table> Can thi ...

Aligning Text to the Right Using CSS

HTML <body> <div class="menu_items"> <h1>My Heading</h1> <nav> <a>Item 1</a> <a>Item 2</a> <a>Item 3</a ...

Dynamic class name changes in Angular.js based on JSON object

I am trying to dynamically change the class of an <li> element based on the category value I am getting, but for some reason the class name won't update. Here is the code snippet: <div id="content"> <ul id="container" ng-controller ...

Guide on accessing the text content within a div element in HTML by triggering a button click

To extract specific text from multiple div tags, I need to trigger an event when clicking a button. <div class="col-lg-3 col-md-6 mb-4"> <div class="pricing-table pricing-secondary"> <div class="price-hea ...

Looking to display or conceal several divs according to the option selected from a dropdown menu?

I've been searching for a solution to my simple dropdown issue, but haven't had any luck in the forums. This is the code for the dropdown: <select id ="category_faq"> <option value="1">item1</option> <option value= ...

struggling to update an array with user inputs on my to-do list app

I'm currently in the process of creating a small to-do list with some specific functionality. I want each text input (or a copy of it) to be added to an empty string, ensuring that the original input remains unchanged. The goal is to have a function t ...

I am unable to move HTML data to PHP

Here is my HTML code: <form action="test.php" method="get> <input type="text" name="text" /> </form> And this is my PHP code: <html> <head> <title>Result</title> </head> <body style="background: ...