§ Interactive demo

This is what I call a fluid SVG. See for yourself, use the slider.

It’s an svg element contained in a div.

The div has its width set to 50%

Width 50

If the div grows, then the svg will also grow.

This is very convenient as we get resize adaptability for free.

§ Fluid SVGs

So, a fluid SVG is one that can extend on the horizontal axis as far as its parent allows it to.

It preserves its aspect ratio, growing and shrinking accordingly, depending on how wide its parent is.

The trick lies in how we define the <svg> element.

For that we should only set the viewBox attribute.

But don’t set a height or width on it. That’s it!

The Vue.js component above is called SimpleBox, and this is how it looks like:

< template lang = "pug" > .simple-box svg(:viewBox="viewBoxString") rect( :x="square.x" :y="square.y" :width="square.width" :height="square.height" ).square </ template > < script > export default { data () { return { square : { x : 100 , y : 100 , width : 300 , height : 300 }, svg : { width : 1000 , height : 1000 } } }, computed : { viewBoxString () { return `0 0 ${ this .svg.width} ${ this .svg.height} ` } } } </ script > < style lang = "sass" scoped > svg background-color : var ( --v-primary-lighten1 ) border : 2 px solid black display : block .square fill : var ( --v-accent-lighten2 ) stroke : black stroke-width : 5 </ style >

The wrapper is called SimpleWrapper, and it looks like:

< template lang = "pug" > .simple-wrapper(:style="styles").mb-4 slot </ template > < script > export default { props : { width : { default : undefined , type : Number } }, computed : { styles () { return { width : ` ${ this .width} %` } } } } </ script > < style lang = "sass" scoped > .simple-wrapper border : 1 px solid red padding : 16 px </ style >

It’s very simple, it just contains a <div> which width can be set from outside —that’s how the slider controls it.

And it has a slot where the SimpleBox component goes in, and it shrinks and grows as much as is permitted by its parent width.

The code for the mini-demo above is just this: