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

What might be causing the in-viewport javascript to not work in my code?

Why is my in-viewport JavaScript code not functioning properly? Link to JSFiddle code When the Click to move button is clicked, the cat image will slide correctly. However, when implementing the following code: if($("#testtest").is(":in-viewport")) ...

Is it possible to create a single button that, upon clicking, fades in one image while simultaneously fading out another?

My goal is to have the blue square fade in on the first button click, then fade out while the red square fades in on the second click. Unfortunately, it seems that my current code is not achieving this effect. I'm open to any suggestions or help on h ...

Modification of a CSS element

The CSS I am working with looks like this: .cls .imageX { float:left; } .cls .imageY { float:right; } It is currently being used on a page in this way: <div class="cls"> <a href="" class="imageX"><img src="left.png"/></a> &l ...

Is there a way to eliminate the menuArrow from a Select widget in gwt-bootstrap3?

In my current project, using gwt-bootstrap3, I have been attempting to conditionally remove the menu arrow from a Select box. I have experimented with various methods such as: <select:Select ui:field="fieldName" name="fieldName" b:id="fieldName" showM ...

What is the best way to display a collection of square Views in a FlatList in a react native application?

How can you create a scrollable square grid with two columns of squares in a FlatList using react-native and ensure it is responsive to different screen sizes? Which CSS properties in react-native are necessary to achieve square shapes for each <Item/& ...

Issues with IE 11: SVG Map Not Triggering Mouseenter or Mouseleave Events

I've been grappling with this issue for the past couple of days and despite trying numerous solutions, nothing seems to be working. My SVG map of the US has jQuery mouseenter and mouseleave events that function properly in browsers other than IE 11 ( ...

The fixed left div and scrollable right div are experiencing issues with their alignment

I am having an issue with a section where the left div is fixed and the right div is scrollable. However, the content of the right div scrolls even before the scroll top reaches the section. My goal is for the right div to scroll only when it reaches the t ...

Having trouble with your website not adjusting properly when resizing the browser or viewing it on a mobile phone

My website is not adapting properly to different screen sizes, even after I have added the META tags below. Any advice would be appreciated. Thank you. HTML <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="UTF-8> ...

Troubleshooting: jQuery animation for background-color doesn't function in Internet Explorer

I've been working on a website and I'm trying to create a navigation bar similar to the one found at . My goal is to have the navbar transition from transparent to a colored background as the user scrolls down the page. For this project, I am ut ...

What is the process for adjusting the color of a mat-divider?

Has anyone been successful in changing the color of mat-divider? I attempted the following but had no luck: component.html <mat-divider class="material-devider"></mat-divider> component.scss .material-devider { color: red } ...

"Add a new style sheet to the homepage of your WordPress site using the

I have been attempting to utilize a separate style sheet in order to customize the front page of my wordpress website. Despite several attempts, I have not had any success. Below is the current code that I am working with: add_action('wp_enqueue_styl ...

Is it possible to use HTML code as content in CSS?

How do I go about displaying the variable $text as HTML? Take a look at the code snippet provided below: <?php header('Content-type: text/css'); $background = "#ffafff"; $color = "#000000"; $green = "#16a86f"; $text= '<h1&g ...

Materriel-UI ToggleButton has the appearance of a traditional button

Looking to style a ToggleButton like a button? Having trouble with an error in the console when nesting a button inside? Check out this solution: const StyledToggleButtonGroup = withStyles((theme) => ({ grouped: { margin: theme.spacing(0.5) ...

Proper alignment of content in HTML using Bootstrap following the integration of .json data

After aligning the emergency hotlines properly, I am struggling to position the text under the image to display the data in three rows. I attempted col-4 but encountered issues with JSON. My objective is to show the image followed by the numbers directly b ...

When state updates in React, the component will rerender without affecting its style

There seems to be a minor oversight on my part. The issue arises in the parent component where I maintain a state of selected items, which are added from the child component. The background color of the child component changes when an item is selected. Ad ...

What is the best way to align two HTML elements in a single column?

I need to adjust the layout of an existing <td> in order to display a checkbox and one additional field on the same line. The current setup places these elements on separate lines. Below is the provided HTML code: <!DOCTYPE html> <html> ...

Adjusting the alignment of button text in an Angular Kendo grid

I am currently utilizing the grid view feature of Kendo UI for Angular. While I have buttons on the grid, the issue is that the text within the buttons is not centered properly despite applying styles such as text-align:center. Here is the template for my ...

Easy Div Centering with jQuery Toggle for Internet Explorer 6

Press the button to center the div, press it again to align it to the left. This feature is compatible with all browsers except for IE6, which does not support margin: 0 auto;. How can I find a solution to this issue? The width of the div is not fixed and ...

Using Javascript to dynamically swap images within a div as the user scrolls

Can someone help me achieve a similar image scrolling effect like the one on the left side of this website: I am looking to change the image inside a div as I scroll and ensure that the page doesn't scroll further until all the images have been scrol ...

Aligning the column to the right to ensure the text is centered horizontally on the screen

<div className={css.title} > <div className={css.row}> <div className={css.columnLeft}> <div className={css.header}>Images</div> </div> <div className={css.col ...