Here on CodyHouse we’ve published a lot of SVG experiments! What’s really powerful with SVG is the possibility to combine path animations with the clipPath element. Add a touch of CSS transformations and you got a spicy recipe!
Inspiration: Music player animation by Veronika Lykova.
Tool used: Snap.svg
Images: Unsplash
Creating the structure
The HTML structure is composed of three unordered lists: a ul.gallery
and a ul.navigation
for the slider images and navigation, and a ul.caption
for the image captions.
Each list item inside the ul.gallery
is composed of a .svg-wrapper
element wrapping a <svg>
containing a <clipPath>
element (used to change the clipping area of the slide image), an <image>
element (whose clip-path url attribute is the<clipPath>
id), and a <use>
element (whose xlink:href attribute is the<clipPath>
id) used to create the layer covering the slide images not in the center.
<div class="cd-svg-clipped-slider" data-selected="M780,0H20C8.954,0,0,8.954,0,20v760c0,11.046,8.954,20,20,20h760c11.046,0,20-8.954,20-20V20 C800,8.954,791.046,0,780,0z" data-lateral="M795.796,389.851L410.149,4.204c-5.605-5.605-14.692-5.605-20.297,0L4.204,389.851 c-5.605,5.605-5.605,14.692,0,20.297l385.648,385.648c5.605,5.605,14.692,5.605,20.297,0l385.648-385.648 C801.401,404.544,801.401,395.456,795.796,389.851z">
<div class="gallery-wrapper">
<ul class="gallery">
<li class="left">
<div class="svg-wrapper">
<svg viewBox="0 0 800 800">
<title>Animated SVG</title>
<defs>
<clipPath id="cd-image-1">
<path id="cd-morphing-path-1" d="M795.796,389.851L410.149,4.204c-5.605-5.605-14.692-5.605-20.297,0L4.204,389.851 c-5.605,5.605-5.605,14.692,0,20.297l385.648,385.648c5.605,5.605,14.692,5.605,20.297,0l385.648-385.648 C801.401,404.544,801.401,395.456,795.796,389.851z"/>
</clipPath>
</defs>
<image height='800px' width="800px" clip-path="url(#cd-image-1)" xlink:href="img/img-01.jpg"></image>
<use xlink:href="#cd-morphing-path-1" class="cover-layer" />
</svg>
</div> <!-- .svg-wrapper -->
</li>
<li class="selected">
<div class="svg-wrapper">
<svg viewBox="0 0 800 800">
<title>Animated SVG</title>
<defs>
<clipPath id="cd-image-2">
<path id="cd-morphing-path-2" d="M780,0H20C8.954,0,0,8.954,0,20v760c0,11.046,8.954,20,20,20h760c11.046,0,20-8.954,20-20V20 C800,8.954,791.046,0,780,0z"/>
</clipPath>
</defs>
<image height='800px' width="800px" clip-path="url(#cd-image-2)" xlink:href="img/img-02.jpg"></image>
<use xlink:href="#cd-morphing-path-2" class="cover-layer" />
</svg>
</div> <!-- .svg-wrapper -->
</li>
<!-- other slides here -->
</ul>
<nav>
<ul class="navigation">
<li><a href="#0" class="prev">Prev</a></li>
<li><a href="#0" class="next">Next</a></li>
</ul>
</nav>
</div>
<ul class="caption">
<li class="left">Lorem ipsum dolor</li>
<li class="selected">Consectetur adipisicing elit</li>
<!-- other captions here -->
</ul>
</div> <!-- .cd-svg-clipped-slider -->
Adding style
By default, all the list items inside the ul.gallery
have a position absolute, an opacity of zero and are moved to the right and scaled down.
.cd-svg-clipped-slider .gallery li {
/* slider images */
position: absolute;
z-index: 1;
top: 0;
left: 25%;/* (100% - width)/2 */
width: 50%;
height: 100%;
opacity: 0;
transform: translateX(75%) scale(0.4);
transition: opacity .3s, transform .3s ease-in-out;
}
The .selected
class is then used to move the selected image back to the center and to scale it up.
.cd-svg-clipped-slider .gallery li.selected {
/* slide in the center */
position: relative;
z-index: 3;
opacity: 1;
transform: translateX(0) scale(1);
}
The .left
and .right
classes are used to show the preview images on both sides of the selected image; the .left
class is also used to move an image preview to the left.
.cd-svg-clipped-slider .gallery li.left {
/* slides on the left */
transform: translateX(-75%) scale(0.4);
}
.cd-svg-clipped-slider .gallery li.left,
.cd-svg-clipped-slider .gallery li.right {
/* .right -> slide visible on the right */
z-index: 2;
opacity: 1;
}
When a new slide is selected, the <path>
element used to clip the slide image is animated to reveal a different portion of the image (the entire image if the slide is the .selected
one, or just a section for the .left
/.right
images).
The same classes are also used to control the visibility/position of the image captions. By default, all captions are hidden and moved to the right; the class .selected
is used to show the selected caption and move it back to the center, while the .left
class is used to hide it and move it to the left.
.cd-svg-clipped-slider .caption li {
/* slide titles */
position: absolute;
z-index: 1;
top: 0;
left: 0;
text-align: center;
width: 100%;
transform: translateX(100px);
opacity: 0;
transition: opacity .3s, transform .3s ease-in-out;
}
.cd-svg-clipped-slider .caption li.selected {
/* slide visible in the center */
z-index: 2;
position: relative;
transform: translateX(0);
opacity: 1;
}
.cd-svg-clipped-slider .caption li.left {
/* slide hidden on the left */
transform: translateX(-100px);
}
Events handling
To implement this slider we created a svgClippedSlider
object and used the bindEvents
method to attach event handlers for the click to the slider navigation.
function svgClippedSlider(element) {
this.element = element;
this.slidesGallery = this.element.find('.gallery').children('li');
this.slidesCaption = this.element.find('.caption').children('li');
this.slidesNumber = this.slidesGallery.length;
this.selectedSlide = this.slidesGallery.filter('.selected').index();
// ....
this.bindEvents();
}
svgClippedSlider.prototype.bindEvents = function() {
var self = this;
//detect click on one of the slides
this.slidesGallery.on('click', function(event){
if( !$(this).hasClass('selected') ) {
//determine new slide index and show it
var newSlideIndex = ( $(this).hasClass('left') )
? self.showPrevSlide(self.selectedSlide - 1)
: self.showNextSlide(self.selectedSlide + 1);
}
});
}
The showPrevSlide
and showNextSlide
methods take care of showing the selected slide; these functions are used to add/remove the proper classes from the slide images and captions, and to animate the 'd' attribute of the <path>
element inside the <clipPath>
used to clip the slide image.