Dynamic and Responsive SVG

Jack Forbes
Sep 29, 2018 · Unlisted

I ran into a technical challenge while developing our new PadPiper about page. There’s one part of the page that you can probably guess required additional work. The SVG in the timeline (the purple line in the below GIF).

The problem

Without a dynamic path the height of the SVG (purple line) shrinks as the container width shrinks.

The solution

By introducing variables into the SVG’s path, the height can adjust appropriately on resize.

Getting to this solution was not easy. I couldn’t find any articles about solving this challenge either so I figured I’d document my solution in case it helps you.

While I will do everything in my power to keep styling in HTML/CSS, after in-depth research and experimentation I finally came to the conclusion that Javascript would have to be involved. With modern-day front-end frameworks, this isn’t so bad.

I’ll skip the multiple attempts I made and get right to the good stuff.

Note: The code snippets in this article are trimmed to provide a simplified, higher-level view.

HTML

<svg class="timeline" scale scroll-reveal viewBox="0 0 100 600" preserveAspectRatio="none">
<path class="hide-gt-xs" d={`M 70 1 h 18 a 10 10 0 0 1 10 10 v ${pathHeight} a 10 10 0 0 1 -10 10 h -20 h -57 a 10 10 0 0 0 -10 10 v ${pathHeight} a 10 10 0 0 0 10 10 h 78 a 10 10 0 0 1 10 10`} />
<path class="hide-xs hide-gt-sm" d="M 70 1 h 18 a 10 10 0 0 1 10 10 v 59 a 10 10 0 0 1 -10 10 h -20 h -57 a 10 10 0 0 0 -10 10 v 68 a 10 10 0 0 0 10 10 h 78 a 10 10 0 0 1 10 10" />
<path class="hide-xs hide-sm" d={`M 50 1 h 20 a 10 10 0 0 1 10 10 v ${pathHeight} a 10 10 0 0 1 -10 10 h -20 h -30 a 10 10 0 0 0 -10 10 v ${pathHeight} a 10 10 0 0 0 10 10 h 60 a 10 10 0 0 1 10 10`} />
</svg>

You’ll notice the three path elements. While it’d be ideal to have just one, as it goes with responsive web design, the structure of the page changes enough between mobile, tablet, and desktop that three different paths are required.

The good stuff

The key component to this solution is the variable vertical portions of the path. Since the aspect ratio of the SVG must be maintained (otherwise the SVG would overflow off the page upon resizing) the vertical portions of the SVG must grow as the horizontal portions shrink. In path speak, each v must be dynamic while each h and a can be fixed.

JavaScript

You may have noticed the scale attribute on the SVG. Using your preferred method or framework, you can attach a function to your SVG containing this attribute. The function can look something like this:

scale() {
// At 350px screen width the pathHeight coefficient should be 1
const startPathHeight = 1;
const startScreenWidth = 350;
// At 450px screen width the pathHeight coefficient should be .69
const midPathHeight = .69;
const midScreenWidth = 450;
// At 600px screen width the pathHeight coefficient should be .48
const endPathHeight = .48;
const endScreenWidth = 600;
const lgWidth = 1204;

Note: You will need to call the above onResize in a window event listener. You can figure that one out on your own :)

More math than you may have expected, eh? Same. It took me a while to get to the above formulas and while the formulas can most definitely be improved (I’m no mathematician) they give you an idea as to what kind of formulas can work to make your SVG responsive.

So what’s going on here?

Well, the first realization I had when making each path v dynamic was that it couldn’t scale linearly with the window width. You’ll likely have to use the Math.pow() or Math.sqrt() functions.

The reason for the if else statements is that as the window width shrinks below 600px I couldn’t find a one-size-fits-all formula (see what I did there?) for the path height coefficient. Any brilliant people out there may be able to figure one out and please do enlighten me if so.

Since I used a different path for tablet, you may notice that path doesn’t have any dynamic vertical portions. This is because our responsive tablet design has a fixed width between 600px and 960px so the width of the SVG doesn’t change and therefore the height doesn’t have to either.

SCSS

.timeline {
position: absolute;
width: 100%;
height: auto;
top: 64px;
left: -5px;
stroke-width: 3px;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 4250;
stroke-dashoffset: 4250;

The only noteworthy piece of CSS is the vector-effect. This needs to be set to non-scaling-stroke if you want to keep your path stroke the same width on all screen sizes.

The reason for setting the stroke-dasharray and stroke-dashoffset is for animating the SVG in the next bonus section.

Bonus: Reveal on scroll

In order to reveal the SVG animation when a user scrolls to it, you’ll need to use some JavaScript since it’s required for scroll-based animations.

You may have noticed the scroll-reveal attribute on the SVG. Using your preferred method or front-end framework, you can attach a function to your SVG that has this attribute. I kept it simple with the following logic that adds a class to the element when the top of the element enters the viewport.

scrollReveal(elem) {
const className = 'is-visible';
const ratio = .9;

Note: This needs to be configured appropriately depending on your framework of choice.

The above JavaScript will add the ‘is-visible’ class to the SVG. So the required Sass to animate the SVG is:

$timeline-num-line-items: 10;
$timeline-item-transition-delay: 0.5s;

By using Sass variables, it’s easy to keep the animation properly timed as more items are added to the timeline. We hope to add many more items to our PadPiper timeline, after all!

Faros

Furnished apartments and housemates for 1+ month stays —  https://www.gofaros.com/blog/

Thanks to Zach Waterfield

Unlisted

Jack Forbes

Written by

Co-Founder of Faros. Coding + Soccer === Life

Faros

Faros

Furnished apartments and housemates for 1+ month stays —  https://www.gofaros.com/blog/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade