Daniel W. R. Hart
Daniel W. R. Hart

Reputation: 77

SVG rect is Responsive with CSS in Firefox but not Chrome

I figured out two ways to make an element inside an SVG have responsive resizing relative to the SVG's parent or the SVG itself (SVG height is 100% anyway):

This is a simplified version of what I want for ease of readability. In my project I'm trying to build an SVG nav button that looks like a vertical border with an arrow in the center of it, where the arrow stays the same size, but the vertical lines above and below it change with the button height, and the button height is 100vh - 100px to make room for the header and footer that are 50px each for now. For this reason I need the viewbox dimensions to be responsive in addition to the SVG's height, so I can't do this part in CSS.

https://codepen.io/Daniel-WR-Hart/pen/PoKPebb

approach1.html : JS only handles the viewbox resizing

<html lang="en">
<head>
    <title>Responsive SVG Rect</title>
    <link rel="shortcut icon" href="data:,">
    <style>
        :root {
            --view-box-half: calc(50%);
            --rect-thick: calc(25px);
            --end-gap: calc(50px);
            --longer-side: calc(var(--view-box-half) - var(--end-gap));
        }

        body {
            margin: 0;
        }

        rect {
            width: var(--rect-thick);
            height: var(--longer-side);
        }

        button {
            width: 50px;
            margin: var(--end-gap) 0 0 0;
            padding: 0;
            height: calc(100vh - 100px);
            background-color: blue;

            cursor: pointer;
            border: none;
        }
        svg {
            opacity: 0.7;
            transition: opacity 0.4s;
        }
        svg:hover {
            opacity: 1;
        }
    </style>
    
    <script type="module" defer>
        const svg = document.querySelector('svg');
        const parent = svg.parentNode; // a button
        const rect = document.querySelector('rect');
        setResponsiveArrowResizing();

        function setResponsiveArrowResizing() {
            window.addEventListener('load', updateSizes);
            window.addEventListener('resize', updateSizes);
            function updateSizes() {
                updateViewBoxSize();
                updateRectSize();
            }
            function updateViewBoxSize() {
                // (0,0) is in the center of the svg's viewBox
                svg.viewBox.baseVal.x = parent.offsetWidth / -2;
                svg.viewBox.baseVal.y = parent.offsetHeight / -2;
                svg.viewBox.baseVal.width = parent.offsetWidth;
                svg.viewBox.baseVal.height = parent.offsetHeight;
            }
            function updateRectSize() {
                // Handled in CSS
            }
        }
    </script>
</head>

<body>
    <button>
        <svg width="100%" height="100%" viewBox="0 0 0 0" style="background-color: rgb(150, 40, 40)">
            <rect/>
        </svg>
    </button>
</body>
</html>

approach2.html : Same as approach1.html but with these changes, so that JS handles changing the height of the rect instead of CSS:

        rect {
            width: var(--rect-thick);
            /* height: var(--longer-side); */
        }

            function updateRectSize() {
                rect.style.height = parent.offsetHeight / 2 - 50 + 'px';
            }

Upvotes: 1

Views: 246

Answers (1)

Berci
Berci

Reputation: 3386

For your case replacing --view-box-half: calc(50%); with --view-box-half: calc((100vh - 100px) / 2); should do the job (and would be the easiest solution)

Check your updated working example here

I think the issue with percentage height is related to viewBox and preserveAspectRatio

The viewBox attribute defines the position and dimension, in user space, of an SVG viewport.

While the height is updating the viewport stays the same therefore the height of the rect is not updated. here is an interesting question that might be related

Upvotes: 1

Related Questions