Reputation: 77
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
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