I am attempting to build an svg that can be scaled horizontally and fluidly, similar to the old table-sliced images used to scale a header fluidly across the top of a page.
If you can place each svg in a DIV, its size will determine its svg. However, svg sizing must be in percentages. This may not serve you, for complex svg, with everything is 'floating'
The simple rectangle example is shown below:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body style='padding:10px;font-family:arial'>
<center>
DIV width=400px height=100px:
<div style='width:400px;height:100px;'>
<svg id="mySVG1" width="100%" height="100%">
<rect x=0 y=0 width="20%" height="100%" fill='lightBlue' stroke="black" stroke-width="1" />
<rect x="20%" y="20%" width="60%" height="60%" fill='lightBlue' stroke="black" stroke-width="1" />
<rect x="80%" y="0%" width="20%" height="100%" fill='lightBlue' stroke="black" stroke-width="1" />
</svg>
</div>
<br />No DIV<br />
<svg id="mySVG2" width="100%" height="100%" >
<rect x=0 y=0 width="20%" height="100%" fill='lightBlue' stroke="black" stroke-width="1" />
<rect x="20%" y="20%" width="60%" height="60%" fill='lightBlue' stroke="black" stroke-width="1" />
<rect x="80%" y="0%" width="20%" height="100%" fill='lightBlue' stroke="black" stroke-width="1" />
</svg>
<br />DIV width=300px height=50px:
<div style='width:300px;height:50px;'>
<svg id="mySVG2" width="100%" height="100%" >
<rect x=0 y=0 width="20%" height="100%" fill='lightBlue' stroke="black" stroke-width="1" />
<rect x="20%" y="20%" width="60%" height="60%" fill='lightBlue' stroke="black" stroke-width="1" />
<rect x="80%" y="0%" width="20%" height="100%" fill='lightBlue' stroke="black" stroke-width="1" />
</svg>
</div>
</center>
</body>
</html>
I'm answering this because I had to do the something similar.
Yes, you can do it with just SVG. The key attributes are viewBox
and preserveAspectRatio
. preserveAspectRatio="xMaxYMid"
keeps the rectangle to the right and xMinYMid
keeps the rectangle to the left. Set the viewBox
to be the desired size of the rectangles on the end.
This has been tested in Chrome, Firefox, and IE.
Here is a plunker demo.
Note that if the change the height of the svg to 100% instead of 20px you can make the image scale with a containing html div
.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svg width="100%" height="20px" version="1.0" state='normal'
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<!-- The right head -->
<svg class='head input-source' id='right'
height="100%"
width='100%'
viewBox="0 0 15 30"
preserveAspectRatio="xMaxYMid"
>
<rect width="100%" height="100%"/>
</svg>
<!-- The left head -->
<svg class='head input-source' id='left'
height="100%"
width='100%'
viewBox="0 0 15 30"
preserveAspectRatio="xMinYMid"
>
<rect width="100%" height="100%"/>
</svg>
</defs>
<svg
class='input-source'
stroke='black'
stroke-width='0'
fill="green">
<rect x="2" y="20%" width="100%" height="60%"
stroke='black'
stroke-width='0'
>
</rect>
<use xlink:href='#right'/>
<use xlink:href='#left'/>
</svg>
</svg>
This is a Javascript means to adjust the rectangles based on svg width. Sorry I couldn't create a CSS approach.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<center>
<svg width="200" height="40">
<rect id="leftAnchoRect" x="0" y="0" fill=blue stroke='black' stroke-width="1" width="40" height="40" />
<rect id="centerExpandRect" fill=lightBlue stroke='black' stroke-width="1" x=40 y=10 height="20" />
<rect id="floatRightRect" fill=red stroke='black' stroke-width="1" y="0" width="40" height="40" />
</svg>
<br />
<svg width="250" height="40">
<rect id="leftAnchoRect" x="0" y="0" fill=blue stroke='black' stroke-width="1" width="40" height="40" />
<rect id="centerExpandRect" fill=lightBlue stroke='black' stroke-width="1" x=40 y=10 height="20" />
<rect id="floatRightRect" fill=red stroke='black' stroke-width="1" y="0" width="40" height="40" />
</svg>
<br />
<svg width="300" height="40">
<rect id="leftAnchoRect" x="0" y="0" fill=blue stroke='black' stroke-width="1" width="40" height="40" />
<rect id="centerExpandRect" fill=lightBlue stroke='black' stroke-width="1" x=40 y=10 height="20" />
<rect id="floatRightRect" fill=red stroke='black' stroke-width="1" y="0" width="40" height="40" />
</svg>
<br />
<svg width="500" height="40">
<rect id="leftAnchoRect" x="0" y="0" fill=blue stroke='black' stroke-width="1" width="40" height="40" />
<rect id="centerExpandRect" fill=lightBlue stroke='black' stroke-width="1" x=40 y=10 height="20" />
<rect id="floatRightRect" fill=red stroke='black' stroke-width="1" y="0" width="40" height="40" />
</svg>
<br />
</center>
<script id=myScript>
document.addEventListener("onload",adjustRects(),false)
function adjustRects()
{
var svgElems=document.getElementsByTagName("svg")
for(var k=0;k<svgElems.length;k++)
{
var svg=svgElems[k]
var rects=svg.getElementsByTagName("rect")
var midRect=rects[1]
var rightRect=rects[2]
var svgWidth=parseInt(svg.getAttribute("width"))
var midWidth=svgWidth-80
var floatX=svgWidth-40
midRect.setAttribute("width",midWidth)
rightRect.setAttribute("x",floatX)
}
}
</script>
</body>
</html>
It's actually possible without Javascript by using foreignObject. But it will not work in Internet Explorer, bcs. IE doesn't support foreignObject. See my article at http://w3.eleqtriq.com/2014/03/the-holy-grail-of-image-scaling/