This code creates an elastic sidebar using Material Design. It uses SVG animations and transitions to reveal and hide content smoothly. Clicking contacts triggers animations to open a chat interface. The sidebar slides in and out with a click.
How to Create Elastic SVG Sidebar Using Material Design
1. First of all, load the Google Fonts by adding the following CDN links into the head tag of your HTML document.
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Open+Sans'>
2. After that, create the basic HTML structure for your sidebar interface. Define the necessary elements, including the sidebar container, contacts, chat interface, and any other content areas.
<div class="demo"> <svg class="sidebar" viewBox="0 0 300 500"> <path class="s-path" fill="#fff" d="M0,0 50,0 a0,250 0 1,1 0,500 L0,500" /> </svg> <div class="static"> <div class="static__text">Pull white sidebar to the right</div> </div> <div class="sidebar-content"> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-man.png" alt="" class="contact__photo" /> <span class="contact__name">Ethan Hawke</span> <span class="contact__status online"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-girl.png" alt="" class="contact__photo" /> <span class="contact__name">Natalie Portman</span> <span class="contact__status online"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-man.png" alt="" class="contact__photo" /> <span class="contact__name">Kevin Spacey</span> <span class="contact__status online"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-girl.png" alt="" class="contact__photo" /> <span class="contact__name">Rosamund Pike</span> <span class="contact__status online"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-man.png" alt="" class="contact__photo" /> <span class="contact__name">Robert Redford</span> <span class="contact__status online"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-girl.png" alt="" class="contact__photo" /> <span class="contact__name">Scarlett Johansson</span> <span class="contact__status online"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-man.png" alt="" class="contact__photo" /> <span class="contact__name">Tom Cruise</span> <span class="contact__status"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-girl.png" alt="" class="contact__photo" /> <span class="contact__name">Eva Green</span> <span class="contact__status"></span> </div> <div class="contact"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-man.png" alt="" class="contact__photo" /> <span class="contact__name">Paul Newman</span> <span class="contact__status"></span> </div> <div class="search"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-srch.png" alt="" class="search__img" /> <input type="text" class="search__input" placeholder="Search" /> </div> </div> <div class="chat"> <span class="chat__back"></span> <span class="chat__status">status</span> <div class="chat__person"> <span class="chat__online active"></span> <span class="chat__name">Huehue Huehue</span> </div> <div class="chat__messages"> <div class="chat__msgRow"> <div class="chat__message mine">Such SVG, much Javascript, very CSS!</div> </div> <div class="chat__msgRow"> <div class="chat__message notMine">Wow!</div> </div> <div class="chat__msgRow"> <div class="chat__message notMine">Very elastic! Such easings!</div> </div> <div class="chat__msgRow"> <div class="chat__message mine"> Check out my other <a href="https://codepen.io/suez/public/" target="_blank">pens</a> </div> </div> </div> <input type="text" class="chat__input" placeholder="Your message" /> </div> </div>
3. Now, add the following CSS code between <style> tag or external CSS file to style the sidebar. This includes defining the layout, colors, fonts, and positioning for various components. Customize the CSS style according to your webiste/app’s theme.
*, *:before, *:after { box-sizing: border-box; margin: 0; padding: 0; } html, body { font-size: 62.5%; height: 100%; } button, input { border: 0; outline: none; } body { background: linear-gradient(45deg, #636f85, #6960a0); } .demo { position: absolute; top: 50%; left: 50%; margin-top: -25rem; margin-left: -15rem; width: 30rem; height: 50rem; box-shadow: 0 1rem 5rem rgba(0, 0, 0, 0.3); } .static { height: 100%; font-size: 1.8rem; font-family: "Open Sans", Helvetica, Arial, sans-serif; background: #6D7ADA; } .static:before, .static:after { content: ""; position: absolute; left: 7rem; width: 2rem; height: 2rem; margin-left: -1rem; margin-top: -1rem; border: 2px solid #fff; border-left: none; border-bottom: none; transform: rotate(45deg); -webkit-animation: arrows 1.5s infinite; animation: arrows 1.5s infinite; } .static:before { top: 15rem; } .static:after { top: 35rem; } .static__text { width: 9rem; position: absolute; top: 50%; left: 50%; margin-left: -5rem; transform: translate3d(0, -50%, 0); color: #fff; perspective: 1px; -webkit-backface-visibility: hidden; backface-visibility: hidden; } .sidebar-content { z-index: -1; position: absolute; top: 0; left: 0; width: 20rem; height: 100%; padding-top: 1rem; opacity: 0; transition: opacity 200ms, z-index 0s 0s; background-color: #E9EAF3; overflow: hidden; } .sidebar-content.active { z-index: 2; opacity: 1; } .contact { position: relative; width: 100%; height: 5rem; padding-left: 1.7rem; display: flex; align-items: center; cursor: pointer; overflow: hidden; } .contact__photo { border-radius: 50%; margin-right: 1.5rem; } .contact__name { font-size: 1.2rem; font-family: "Open Sans", Helvetica, Arial, sans-serif; } .contact__status { position: absolute; top: 2.1rem; right: 1.5rem; width: 8px; height: 8px; border: 2px solid #00B570; border-radius: 50%; opacity: 0; transition: opacity 0.3s; } .contact__status.online { opacity: 1; } .search { position: absolute; bottom: 0; left: 0; width: 100%; height: 5.5rem; padding-left: 1.5rem; background: #fff; display: flex; align-items: center; } svg { overflow: visible; } .sidebar { z-index: 1; position: absolute; top: 0; left: 0; display: block; width: 100%; height: 100%; } .s-path { cursor: -webkit-grab; cursor: grab; } .cloned { position: absolute; z-index: 10; transition: top 0.3s, left 0.3s; transition-delay: 0.2s; transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } .cloned.removed { transition: opacity 0.2s 0; opacity: 0; } .chat { display: none; z-index: 5; position: absolute; top: 0; left: 0; width: 100%; height: 100%; padding: 2.5rem 0 5.5rem 2.5rem; transition: opacity 200ms; opacity: 0; } .chat.active { opacity: 1; } .chat.active:before { width: 100%; } .chat:before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 0.5rem; background: #1CC6AE; width: 0; transition: width 0.2s; } .chat__back { position: relative; display: inline-block; width: 2rem; height: 2rem; margin-top: 0.5rem; margin-left: -0.6rem; cursor: pointer; } .chat__back:hover:before { transform: translateX(-0.3rem) rotate(-45deg); } .chat__back:before { content: ""; position: absolute; display: block; top: 0.4rem; left: 0.6rem; width: 1.2rem; height: 1.2rem; border: 2px solid #545675; border-right: none; border-bottom: none; transform: rotate(-45deg); transition: transform 0.3s; } .chat__status { position: absolute; top: 2rem; right: 6.5rem; font-size: 1.2rem; font-family: "Open Sans", Helvetica, Arial, sans-serif; text-transform: uppercase; color: #B1A9A9; } .chat__person { display: inline-block; position: absolute; top: 3rem; right: 6.5rem; font-size: 2rem; font-family: "Open Sans", Helvetica, Arial, sans-serif; color: #36343D; } .chat__online { position: absolute; top: 50%; left: -1.5rem; margin-top: -3px; width: 8px; height: 8px; border: 2px solid #00B570; border-radius: 50%; opacity: 0; transition: opacity 0.3s; } .chat__online.active { opacity: 1; } .chat__messages { position: absolute; top: 7.5rem; left: 2.5rem; width: 27.5rem; height: 37rem; padding-right: 2.5rem; overflow-y: auto; } .chat__msgRow { margin-bottom: 0.5rem; } .chat__msgRow:after { content: ""; display: table; clear: both; } .chat__message { display: inline-block; max-width: 60%; padding: 1rem; font-size: 1.4rem; font-family: "Open Sans", Helvetica, Arial, sans-serif; } .chat__message.mine { color: #2B2342; border: 1px solid #DFDFDF; } .chat__message.notMine { float: right; color: #23244E; background: #E9EAF3; } .chat__input { position: absolute; bottom: 0; left: 0; width: 100%; height: 5.5rem; padding: 1rem 1rem 1rem 4rem; background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/elastic-search.png"); background-repeat: no-repeat; background-position: 1rem 1.5rem; background-color: #E9EAF3; color: #2B2342; font-size: 1.4rem; font-family: "Open Sans", Helvetica, Arial, sans-serif; } .ripple { position: absolute; width: 10rem; height: 10rem; margin-left: -5rem; margin-top: -5rem; background: rgba(0, 0, 0, 0.4); transform: scale(0); -webkit-animation: animRipple 0.3s; animation: animRipple 0.3s; border-radius: 50%; } @-webkit-keyframes animRipple { to { transform: scale(2.5); opacity: 0; } } @keyframes animRipple { to { transform: scale(2.5); opacity: 0; } } @-webkit-keyframes arrows { to { transform: translateX(100%) rotate(45deg); opacity: 0; } } @keyframes arrows { to { transform: translateX(100%) rotate(45deg); opacity: 0; } }
4. Load the jQuery by adding the following script just before closing the body tag:
<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
5. Finally, Implement the JavaScript code provided. This code handles the sidebar animations, interactions with contacts, and the chat interface. It’s responsible for the smooth transitions, sidebar opening/closing, and chat display functionality.
$(document).ready(function() { var $svg = $(".sidebar"), $demo = $(".demo"), $path = $(".s-path"), $sCont = $(".sidebar-content"), $chat = $(".chat"), demoTop = $demo.offset().top, demoLeft = $demo.offset().left, diffX = 0, curX = 0, finalX = 0, frame = 1000 / 60, animTime = 600, sContTrans = 200, animating = false; var easings = { smallElastic: function(t,b,c,d) { var ts = (t/=d)*t; var tc = ts*t; return b+c*(33*tc*ts + -106*ts*ts + 126*tc + -67*ts + 15*t); }, inCubic: function(t,b,c,d) { var tc = (t/=d)*t*t; return b+c*(tc); } }; function createD(top, ax, dir) { return "M0,0 "+top+",0 a"+ax+",250 0 1,"+dir+" 0,500 L0,500"; } var startD = createD(50,0,1), midD = createD(125,75,0), finalD = createD(200,0,1), clickMidD = createD(300,80,0), clickMidDRev = createD(200,100,1), clickD = createD(300,0,1), currentPath = startD; function newD(num1, num2) { var d = $path.attr("d"), num2 = num2 || 250, nd = d.replace(/\ba(\d+),(\d+)\b/gi, "a" + num1 + "," + num2); return nd; } function animatePathD(path, d, time, handlers, callback, easingTop, easingX) { var steps = Math.floor(time / frame), curStep = 0, oldArr = currentPath.split(" "), newArr = d.split(" "), oldLen = oldArr.length, newLen = newArr.length, oldTop = +oldArr[1].split(",")[0], topDiff = +newArr[1].split(",")[0] - oldTop, nextTop, nextX, easingTop = easings[easingTop] || easings.smallElastic, easingX = easings[easingX] || easingTop; $(document).off("mousedown mouseup"); function animate() { curStep++; nextTop = easingTop(curStep, oldTop, topDiff, steps); nextX = easingX(curStep, curX, finalX-curX, steps); oldArr[1] = nextTop + ",0"; oldArr[2] = "a" + Math.abs(nextX) + ",250"; oldArr[4] = (nextX >= 0) ? "1,1" : "1,0"; $path.attr("d", oldArr.join(" ")); if (curStep > steps) { curX = 0; diffX = 0; $path.attr("d", d); currentPath = d; if (handlers) handlers1(); if (callback) callback(); return; } requestAnimationFrame(animate); } animate(); } function handlers1() { $(document).on("mousedown touchstart", ".s-path", function(e) { var startX = e.pageX || e.originalEvent.touches[0].pageX; $(document).on("mousemove touchmove", function(e) { var x = e.pageX || e.originalEvent.touches[0].pageX; diffX = x - startX; if (diffX < 0) diffX = 0; if (diffX > 300) diffX = 300; curX = Math.floor(diffX/2); $path.attr("d", newD(curX)); }); }); $(document).on("mouseup touchend", function() { $(document).off("mousemove touchmove"); if (animating) return; if (!diffX) return; if (diffX < 40) { animatePathD($path, newD(0), animTime, true); } else { animatePathD($path, finalD, animTime, false, function() { $sCont.addClass("active"); setTimeout(function() { $(document).on("click", closeSidebar); }, sContTrans); }); } }); } handlers1(); function closeSidebar(e) { if ($(e.target).closest(".sidebar-content").length || $(e.target).closest(".chat").length) return; if (animating) return; animating = true; $sCont.removeClass("active"); $chat.removeClass("active"); $(".cloned").addClass("removed"); finalX = -75; setTimeout(function() { animatePathD($path, midD, animTime/3, false, function() { $chat.hide(); $(".cloned").remove(); finalX = 0; curX = -75; animatePathD($path, startD, animTime/3*2, true); animating = false; }, "inCubic"); }, sContTrans); $(document).off("click", closeSidebar); } function moveImage(that) { var $img = $(that).find(".contact__photo"), top = $img.offset().top - demoTop, left = $img.offset().left - demoLeft, $clone = $img.clone().addClass("cloned"); $clone.css({top: top, left: left}); $demo.append($clone); $clone.css("top"); $clone.css({top: "1.8rem", left: "25rem"}); } function ripple(elem, e) { var elTop = elem.offset().top, elLeft = elem.offset().left, x = e.pageX - elLeft, y = e.pageY - elTop; var $ripple = $("<div class='ripple'></div>"); $ripple.css({top: y, left: x}); elem.append($ripple); } $(document).on("click", ".contact", function(e) { if (animating) return; animating = true; $(document).off("click", closeSidebar); var that = this, name = $(this).find(".contact__name").text(), online = $(this).find(".contact__status").hasClass("online"); $(".chat__name").text(name); $(".chat__online").removeClass("active"); if (online) $(".chat__online").addClass("active"); ripple($(that),e); setTimeout(function() { $sCont.removeClass("active"); moveImage(that); finalX = -80; setTimeout(function() { $(".ripple").remove(); animatePathD($path, clickMidD, animTime/3, false, function() { curX = -80; finalX = 0; animatePathD($path, clickD, animTime*2/3, true, function() { $chat.show(); $chat.css("top"); $chat.addClass("active"); animating = false; }); }, "inCubic"); }, sContTrans); }, sContTrans); }); $(document).on("click", ".chat__back", function() { if (animating) return; animating = true; $chat.removeClass("active"); $(".cloned").addClass("removed"); setTimeout(function() { $(".cloned").remove(); $chat.hide(); finalX = 100; animatePathD($path, clickMidDRev, animTime/3, false, function() { curX = 100; finalX = 0; animatePathD($path, finalD, animTime*2/3, true, function() { $sCont.addClass("active"); $(document).on("click", closeSidebar); animating = false; }); }, "inCubic"); }, sContTrans); }); $(window).on("resize", function() { demoTop = $demo.offset().top; demoLeft = $demo.offset().left; }); });
That’s all! hopefully, you have successfully created an Elastic SVG Sidebar using Material Design. If you have any questions or suggestions, feel free to comment below.
Similar Code Snippets:
I code and create web elements for amazing people around the world. I like work with new people. New people new Experiences.
I truly enjoy what I’m doing, which makes me more passionate about web development and coding. I am always ready to do challenging tasks whether it is about creating a custom CMS from scratch or customizing an existing system.