We’ve been experimenting lately with SVG path animations, creating transitions for our image slider and hero slider. Today’s tutorial shows you how to animate at once multiple SVG paths to create a stylish background effect for a modal window.
Inspiration: UI8 Nav on Dribbble
Creating the structure
The HTML structure is composed by 2 main elements: a <section>
, used to wrap the action button (#modal-trigger
), and a div.cd-modal
, the modal window, containing the modal content (.cd-modal-content
) and the div.cd-svg-bg
, used to create the background covering effect.
<main class="cd-main-content">
<section class="center">
<h1>SVG Modal Window</h1>
<a href="#0" class="cd-btn" id="modal-trigger" data-type="cd-modal-trigger">Fire Modal Window</a>
</section>
</main> <!-- .cd-main-content -->
<div class="cd-modal" data-modal="modal-trigger">
<div class="cd-svg-bg" data-step1="M-59.9,540.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L864.8-41c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L-59.5,540.6 C-59.6,540.7-59.8,540.7-59.9,540.5z" data-step2="M33.8,690l-188.2-300.3c-0.1-0.1,0-0.3,0.1-0.3l925.4-579.8c0.1-0.1,0.3,0,0.3,0.1L959.6,110c0.1,0.1,0,0.3-0.1,0.3 L34.1,690.1C34,690.2,33.9,690.1,33.8,690z" data-step3="M-465.1,287.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L459.5-294c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C-464.9,287.7-465,287.7-465.1,287.5z" data-step4="M-329.3,504.3l-272.5-435c-0.1-0.1,0-0.3,0.1-0.3l925.4-579.8c0.1-0.1,0.3,0,0.3,0.1l272.5,435c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C-329,504.5-329.2,504.5-329.3,504.3z" data-step5="M341.1,797.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L1265.8,216c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L341.5,797.6 C341.4,797.7,341.2,797.7,341.1,797.5z" data-step6="M476.4,1013.4L205,580.3c-0.1-0.1,0-0.3,0.1-0.3L1130.5,0.2c0.1-0.1,0.3,0,0.3,0.1l271.4,433.1c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C476.6,1013.6,476.5,1013.5,476.4,1013.4z">
<svg height="100%" width="100%" preserveAspectRatio="none" viewBox="0 0 800 500">
<title>SVG Modal background</title>
<path id="cd-changing-path-1" d="M-59.9,540.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L864.8-41c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L-59.5,540.6 C-59.6,540.7-59.8,540.7-59.9,540.5z"/>
<path id="cd-changing-path-2" d="M-465.1,287.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L459.5-294c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C-464.9,287.7-465,287.7-465.1,287.5z"/>
<path id="cd-changing-path-3" d="M341.1,797.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L1265.8,216c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L341.5,797.6 C341.4,797.7,341.2,797.7,341.1,797.5z"/>
</svg>
</div>
<div class="cd-modal-content">
<!-- modal content here -->
</div> <!-- cd-modal-content -->
<a href="#0" class="modal-close">Close</a>
</div> <!-- cd-modal -->
<div class="cd-cover-layer"></div> <!-- .cd-cover-layer -->
An additional div.cd-cover-layer
has been used to cover the main content when the modal window is fired (it is positioned between the modal window and the main content of the page).
Adding style
The .cd-modal
window has, initially, visibility: hidden, height: 100% and width: 100% and is in fixed position.
When user clicks the a#modal-trigger
, the visibility of the modal window is changed to visible (using the .modal-is-visible
class).
.cd-modal {
position: fixed;
z-index: 2;
top: 0;
left: 0;
height: 100%;
width: 100%;
visibility: hidden;
transition: visibility 0s 0.6s;
}
.cd-modal.modal-is-visible {
visibility: visible;
transition: visibility 0s 0s;
}
To create the modal background covering effect, we animate the 'd' attribute of the <path>
elements inside the div.cd-svg-bg > svg
(more in the Events handling section).
Our first approach to creating the "masked" text effect consisted in using the SVG foreignObject
to include the modal content into the SVG element. This way we could use the path elements as a reference to cut the text outside the animated background. However, we had several issues, mostly related to browsers compatibility.
That's why we decided to use this simple trick instead: when the modal window is fired, a layer (.cd-cover-layer
) becomes visible, right below the modal background, and, immediately after, the text becomes visible as well. The .cd-cover-layer
and the text have the same color, this way only the text over the blue paths is visible during the animation.
More in details: when a user clicks the a#modal-trigger
, the .modal-is-visible
class is added to the .cd-cover-layer
and the .cd-modal
. This class changes the .cd-cover-layer
opacity from 0 to 1 and its visibility from hidden to visible, so that the .cd-cover-layer
entirely covers the page main content.
.cd-cover-layer {
position: fixed;
z-index: 1;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: #f2f2f2;
visibility: hidden;
opacity: 0;
transition: opacity 0.3s 0.3s, visibility 0s 0.6s;
}
.cd-cover-layer.modal-is-visible {
opacity: 1;
visibility: visible;
transition: opacity 0.3s 0s, visibility 0s 0s;
}
As soon as the .cd-cover-layer
opacity transition is over, the opacity of the .cd-modal-content
is set to 1:
.cd-modal-content {
color: #f2f2f2;
opacity: 0;
transform: translateY(50px);
transition: opacity 0.3s 0s, transform 0.3s 0s;
}
.modal-is-visible .cd-modal-content {
opacity: 1;
transform: translateY(0);
transition: opacity 0.3s 0.3s, transform 0.3s 0.3s;
}
Since the color of the .cd-modal-content
is the same of the .cd-cover-layer
background color, the only visible content will be the one over the blue svg background (which is still animating), while the one over the .cd-cover-layer
won't be visible.
Events handling
To animate the modal background, we animated the 'd'
attribute of the 3 <path>
elements inside the svg.
First, we defined the two steps of our animation, using the same process described in the Animated SVG Hero Slider article (Events handling section).
Once defined the paths, we added to the .cd-svg-bg
a data-stepn
attribute (one for each step) equal to the 'd'
attribute of the defined path (to easily retrieve it with JavaScript).
We then used the animate()
method provided by Snap.svg to animate the path element.
modalTrigger.on('click', function(event){ //modalTrigger = $('a[data-type="cd-modal-trigger"]')
event.preventDefault();
$([modal.get(0), coverLayer.get(0)]).addClass('modal-is-visible'); //modal = $('.cd-modal'), coverLayer = $('.cd-cover-layer')
animateModal(pathsArray, pathSteps, duration, 'open');
});
function animateModal(paths, pathSteps, duration, animationType) {
var path1 = ( animationType == 'open' ) ? pathSteps[1] : pathSteps[0], // pathSteps[n] = $('.cd-svg-bg').data('step'+(n+1));
path2 = ( animationType == 'open' ) ? pathSteps[3] : pathSteps[2],
path3 = ( animationType == 'open' ) ? pathSteps[5] : pathSteps[4];
paths[0].animate({'d': path1}, duration, firstCustomMinaAnimation); //paths[0] = Snap('#cd-changing-path-1')
paths[1].animate({'d': path2}, duration, firstCustomMinaAnimation); //paths[1] = Snap('#cd-changing-path-2')
paths[2].animate({'d': path3}, duration, firstCustomMinaAnimation); //paths[2] = Snap('#cd-changing-path-3')
}