Unusual behavior of diagonal viewBox in SVG

Trying to understand how the viewBox attribute works in SVG, but the code below is confusing me. Can someone please explain if this is a bug or the expected behavior of SVG? I can't seem to figure out what I'm doing wrong...

<svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>

This is my SVG symbol here, and I'm attempting to stack multiple instances both horizontally and vertically.

//vertical stack ->viewBox = 0, 0, 10*1, 7*2
<svg viewBox="0 0 10 14">
      <use href="#Atom"/>
      <use href="#Atom" y="7"/> 
</svg>

//horizontal stack ->viewBox = 0, 0, 10*2, 7*1
<svg viewBox="0 0 20 7">
      <use href="#Atom"/>
      <use href="#Atom" x="10"/>    
</svg>

//"diagonal" stack ->viewBox = 0, 0, 10*2, 7*2
<svg viewBox="0 0 20 14">
      <use href="#Atom"/>
      <use href="#Atom" x="10"/>
      <use href="#Atom" y="7"/>
</svg>

The first stacking example has two symbols placed vertically, with the same viewBox dimensions as the symbol but with double the height from 7 to 14. This works perfectly.

In the second example, there are two symbols stacked horizontally, maintaining the same viewBox dimensions as the original symbol but doubling the width from 10 to 20. This also works correctly.

However, in the third example with two symbols stacked both horizontally and vertically, setting the viewBox width and height to be twice the original does not work properly. https://i.stack.imgur.com/kKiPS.png

As shown in the image, the symbols overlap (indicating a potential issue with the viewBox).

Here is an example of what I am trying to achieve (note that overflow: visible is used, causing the symbols to extend beyond the viewBox).

https://i.stack.imgur.com/cQTO0.png

Could someone please clarify where I might be going wrong with this? Any assistance would be greatly appreciated.

For anyone interested in experimenting with this, here's the codepen link.

Answer №1

your symbol desires to occupy the entire width or height when only one dimension of the viewport is stretched, it fits perfectly because it takes up the full width or height and refrains from stretching in the other direction in order to maintain its aspect ratio.

However, in this scenario, the svg viewport is twice as large as the symbol, so it occupies all the available space

here is a simple solution

.svg {
  max-width: 200px;
  border: 1px solid red;
}
<svg class="svg" viewBox="0 0 20 14">
    <use href="#Atom" x="0" y="0"  width="50%" />
    <use href="#Atom" x="0" y="7"  width="50%" />
    <use href="#Atom" x="10" y="0" width="50%" />
    <use href="#Atom" x="10" y="7" width="50%" />
</svg>
<svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>


UPDATE:

if you do not wish to manually add width to the use tag AND are generating them programmatically (I assumed you are using JavaScript but the same logic could be applied to other languages), you simply need to calculate the rows and columns in your viewport and determine the width and height of each use

here is an example

const config = {
    svg: {
        width: 20,
        height: 14,
        rows: 2,
        cols: 2,
        symbol: '#Atom'
    }
}
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', '0 0 '+config.svg.width+' '+config.svg.height);

for (let i = 0; i < config.svg.rows; i++) {
    for (let j = 0; j < config.svg.cols; j++) {
        const xPosition = (config.svg.width / config.svg.rows) * i;
        const yPosition = (config.svg.height / config.svg.cols) * j;

        const width = (100 / config.svg.rows);
        const height = (100 / config.svg.cols);

        const svgUse = document.createElementNS('http://www.w3.org/2000/svg', 'use');
        svgUse.setAttribute('href', config.svg.symbol);
        svgUse.setAttribute('x', xPosition);
        svgUse.setAttribute('y', yPosition);
        svgUse.setAttribute('width', width + '%');
        svgUse.setAttribute('height', height + '%');

        svg.append(svgUse);
    }
}

document.body.prepend(svg)
<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>
    </body>
</html>

Answer №2

Although it may seem odd, I inadvertently replied to my own comment and I'd like to give a shoutout to @ciekals11 for their valuable input.

The missing piece that resolved my issue was including specific width and height attributes in my symbol. It's interesting how such a small detail can make everything fall into place flawlessly. Despite not fully understanding why this is necessary, I am happy to provide the updated version of my symbol for you to compare.

<svg class="symbol"><symbol width="10" height="7" id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"/></symbol></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

Issues with Google Fonts failing to load correctly

Would you mind taking a look at this issue for me? In all browsers except Firefox, the expected behavior is that a web font remains invisible until fully loaded, preserving space on the page. Interestingly, in Chrome and IE9 (the browsers I tested), ther ...

Revamp the Bootstrap Form Upload feature

I am looking to redesign the Bootstrap Form Upload field. The main reason behind this is that in Bootstrap, the file upload field is treated as one single component, making it impossible to separate the file upload button from the file upload text. The fi ...

Creating parallel lines utilizing pseudo elements

Can someone assist me in drawing double lines under my paragraph using pseudo elements only without using display block? Here is my code snippet with display block: p:after { content: ""; display: block; width: 40px; margin: 20px auto 0; bord ...

Using Jquery to select and apply functions to specified div elements

As someone who is relatively new to JQuery, I have a question regarding the .on() function. Take this example: $('div').on('click', function() {$(this).toggleClass('show-description');}); This code selects all the 'div& ...

Is it possible to combine margin auto with a transform on the left simultaneously?

While examining a webpage, I noticed a positioning issue and decided to remove some CSS code to determine the root of the problem. It appears that the navbar has a 1px gap on the left side from the edge of the screen. After removing the last two lines of c ...

The header that sticks on scroll is annoyingly blocking the content

I managed to create a sticky on-scroll header/navigation bar successfully. Here is how it looks now However, I encountered an issue. When it reaches the top, it automatically 'covers' the top part of my content, which has text on it, and I don& ...

The highlight_row function seems to be delayed, as it does not trigger on the initial onClick but works on subsequent clicks. How can I ensure it works properly right from the first click?

I developed an application using the Google JavaScript Maps API to calculate distances between addresses. I've encountered a bug where the row in the table is not highlighted on the first click, requiring a second click for the highlighting to take ef ...

What is the process for embedding a 3D model using three.js into a specific div on a webpage?

Lately, I've been struggling with a persistent issue. I can't seem to figure out how to integrate my three.js scene into a div on my website. Despite watching numerous YouTube videos and reading countless articles on the topic, I still haven&apos ...

Is Jquery Mobile's Table lacking responsiveness?

I have implemented a basic table from the jQuery Mobile website on my page. Take a look at the HTML code below: <div data-role="page" id="mainPage"> <div data-role="content> <table data-role="table" id="my-table" da ...

What is the best way to move the numerical range value into a span element?

How can I implement the "update" function to retrieve the current slider value and transfer it to a Meter element with the message "Value: [current value]". The indicator color should be #ffff00 if the current value is at least 85, otherwise, it should b ...

What is the lowest opacity value allowed in CSS?

When adjusting the opacity value of a button in CSS, I have noticed that even when the opacity is reduced to 0.005, the button remains clickable to some extent. However, when reducing the value to 0.000000000000000000000000000000000001, the button becomes ...

Creating my website with a unique inverse color scheme

I'm looking to change the color scheme of my webpage so that it is inverse (white becomes black and black becomes white) similar to the Dark Reader chrome extension: https://chrome.google.com/webstore/detail/dark-reader/eimadpbcbfnmbkopoojfekhnkhdbiee ...

Why is the placement of PHP code (for file uploads) in relation to HTML code important?

I am in the process of learning PHP. Could someone please provide an explanation for why this issue is occurring? I find myself extremely puzzled and struggling to comprehend even the smallest detail. I'm also interested in gaining a clear grasp of ho ...

Prevent the movement of the first column in a table when rearranging rows up or down by utilizing

Feeling a bit stuck here, can't seem to figure out what I've missed. I've managed to move up or down a row in a table, but I need the value of the cell in the first column to remain unchanged. Here's my code: This is my HTML file: &l ...

Ways to position an element at the center using Flexbox技

Having some difficulty centering an element in my code using flexbox. It seems to work for everything else, but not here. Any suggestions or ideas? .answer { text-shadow: 0 0 2px gr; display: flex; justify-content: center; border-radius: 5px; ...

Solve the problem with SCSS at the component level in NextJS

I've decided to transition my regular React app to Next.js. In the past, I would simply import SCSS files using: import from '.componentName.scss' However, now I need to import them using: import style from 'componentName.module.scss ...

Using selenium in conjunction with python to click a unique button

Having trouble clicking the connect button on the "people you may know" page of LinkedIn () The HTML code for these buttons is: <a class="vcard-button bt-connect bt-primary" href="#"><span>&nbsp;</span>Connect</a> I attempted ...

Is there a way to activate the mousewheel feature in order to zoom in and out on a webpage using jquery plugins like panzoom and circleslider?

Is there a way to enable mouse scroll functionality? For my project, I am using the CircleSlider.js library (more information available here) and jquery.panzoom-1.7.0. I have created a semi-circle where users can zoom in (+) and out (-) by moving a button ...

Utilizing Host Styles in Angular2 Components

In the midst of developing a custom form component for my Angular project, I am facing challenges with styling. I wish to allow variable widths for the input element and have them controlled by the host component. For instance: <my-input class="input" ...

Tips on transitioning from Modal1 to Modal2 in Ionic after a successful submit button press?

My survey app requires users to fill out a form and click the Submit Feedback button. Upon successful submission, a message saying "Feedback submitted successfully" should be displayed in Modal2, which is inside another modal named (Modal1). However, being ...