I have an arrow as a SVG which's length I want to alter in response to the width of a wrapping DIV (for example).
All my previous attempts have led into this behavior (scaling the whole SVG):
Rather than this, I want to achieve this behavior:
Is it possible to just alter single shapes inside of a SVG by simply adding percentual values to the code? If not, how could I perform this?
SVG as code:
<svg width="35px" viewBox="0 0 35 985" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Group" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(0.000000, 0.000000)">
<rect id="Rectangle-2" fill="#5FDCC7" x="12" y="19.7987928" width="11" height="100%"></rect>
<polygon id="Triangle" fill="#5FDBC6" points="17.5 0 35 20.7887324 0 20.7887324"></polygon>
<rect id="Rectangle-3" fill="#5FDBC6" x="0" y="973.110664" width="35" height="11"></rect>
</g>
</svg>
For this particlular usecase, I think I would go for a CSS approach, it might (depending on your markup) add a html element if you can't use pseudo elements but it won't require JS or to manualy input values for stroke-width or transform elements.
Here is a way to make this arrow using the paragraph tag :
By using symbol's you can make the shapes you want and just include them in. Then to extend the middle section, just make a new path and make the line longer. They can be positioned wherever you like by using the
transform
property** EDITED **
This behavior is caused by your
viewBox
attribute on<svg>
. Your SVG’s aspect ratio is being preserved by default. You want this behavior on#Triangle
and#Rectangle-3
, but not on#Rectangle-2
(you want theheight
to increase, but thewidth
to stay the same).I think you'll want to add
preserveAspectRatio=none
to your<svg>
inline CSS and then do some tweaking (since that messes up the aspect ratio of your#Triangle
and#Rectangle-3
- or instead of that, you could try changing theheight
of#triangle-2
to the same height as your wrapper div (in my JS fiddle I've done it this way, setting#Triangle-2
s height to 25vh). Play with the height of the window -#Rectangle-2
's height elongates but doesn't change width, although I haven’t yet got your#Rectangle-3
to dynamically stick to the bottom of#Rectangle-2
(#Rectangle-3
is stuck at bottom of window): https://jsfiddle.net/KyleVassella/dnagft6q/6/I suspect you’ll know how to fix this, but either way I’ll keep working on it and in the meantime you can read up here where there is much more info on this subject:
How can I make an svg scale with its parent container?
As a general rule, there is no way to create a scalable SVG where parts of it don't scale. If an SVG has a viewBox, and you scale it, then all the contents will scale. There is no way to mark some of the contents as immune to the scaling.
The nearest you can get is to restrict scaling to the X axis. However the arrowhead will still stretch.
If you want a generalised solution, then you have to monitor resize events and update the SVG dynamically.
The limited sneaky clever solution...
Having said all that, there is a clever technique that works in a limited set of circumstances. The limitations are:
Here is a demo of your shape implemented using this technique. If you resize the window horizontally, you'll see it stretches appropriately.:
Yes, you can use percentages in svg.
for basic shapes its quite simple. You can write your main rect as
your second rect is even simpler, as it sits at 0,0 all the time
but with the arrow there is a problem in pathes and polygon you can not use percentages. To work around this problem there is a two step solution.
first put the path in a symbol element:
now you can position this symbol like you would position a rect... easy...
but now your arrow starts a 100% and is completely outside of your viewport. you could just set overflow: visible on your svg and be done with it, but that is not what we want... we want the arrow to end at 100%. But that easy as well, we know that the arrow is 20px wide. So just translate the use back 20px:
using this approach, you can position any shape at any position base on percentages...
to warp it all up, your complete svg now looks like this:
and here is a snippet using this svg with 3 different widths: