Home / Frontend Codes and Demos / CSS Code Demos / Stretchy Tab & Springy Content Slider with bursts
Stretchy Tab & Springy Content Slider with bursts

A slider with a stretchy bubble tab indicator. Container flexes to accommodate size of new article. Now with impact bursts. Shout out to GreenSock's Jack Doyle for an assist on this one. Developed using CSS, HTML and JavaScript. Demo and download options available.

Stretchy Tab & Springy Content Slider with bursts

Stretchy Tab & Springy Content Slider with bursts

A slider with a stretchy bubble tab indicator. Container flexes to accommodate size of new article. Now with impact bursts. Shout out to GreenSock’s Jack Doyle for an assist on this one. Developed using CSS, HTML and JavaScript. Demo and download options available.

Demo Download

Author Craig Roblewsky
Hits
Created SEPTEMBER 16, 2018
License Open
Compatible browsers Chrome, Firefox, Safari

HTML Snippet

<div class="wrap">   <div class="slider"></div>   <svg id="impactBurst" xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 50 50">   <g id="burst" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="4">     <line x1="0" y1="15" x2="40" y2="0" />     <line x1="0" y1="25" x2="40" y2="25" />     <line x1="0" y1="35" x2="40" y2="50" />   </g> </svg>   <ul class="tabs-block">     <li>Alpha</li>     <li>Bravo</li>     <li>Charlie</li>     <li>Delta</li>   </ul> </div> <div class="article-block">   <div class="article">     <h1>Alpha Title</h1>     Lorem ipsum dolor, sit amet consectetur adipisicing elit. Saepe corporis laborum commodi ipsa consectetur blanditiis eum praesentium vero sed, alias totam earum, ut et veniam similique dolor dignissimos autem ad? Eveniet porro quaerat maiores non quibusdam     doloremque ea rerum repellat, sapiente mollitia temporibus neque quas ut odio tempora! Amet, ullam!   </div>   <div class="article">     <h1>Bravo Title</h1>     Lorem ipsum dolor sit amet consectetur, adipisicing elit. Expedita temporibus ab aliquid ipsum cum soluta eos ad molestias neque cumque. Cupiditate laborum nam necessitatibus saepe inventore voluptates soluta? Quisquam, ea!   </div>   <div class="article">     <h1>Charlie Title</h1>     Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est, itaque quae! Cupiditate sed consequatur, delectus magni distinctio quam asperiores amet aliquid architecto animi tenetur sit repudiandae deserunt impedit voluptate, corporis eius nobis sequi     dolore adipisci, illum quae soluta! Quam dolor perspiciatis repellat maxime quae molestiae sint a nam exercitationem ipsum maiores praesentium magnam suscipit excepturi illo minima, illum blanditiis nesciunt? Voluptatem quia at provident ad ipsa ratione,     officia sequi error aliquid, expedita consectetur tempore eius et voluptate debitis praesentium beatae libero minus qui. </br></br>  Sequi dolore dolor quasi voluptatibus dignissimos iste. Eos pariatur sit vitae perspiciatis voluptas, dolorum quam asperiores     tenetur, earum dignissimos ad veniam? Aliquid excepturi dolorum sed adipisci, iure culpa dolor eos itaque, reprehenderit unde praesentium magnam perspiciatis blanditiis?   </div>   <div class="article">     <h1>Delta Title</h1>     Lorem ipsum dolor, sit amet consectetur adipisicing elit. Veritatis rem quidem amet voluptas quo sit beatae, eum adipisci doloribus repellat?   </div> </div>  <div class="colors">   <div class="colorBubble"></div>   <div class="colorBubble"></div>   <div class="colorBubble"></div>   <div class="colorBubble"></div>   <div class="colorBubble"></div>   <div class="colorBubble"></div>   <div class="colorBubble"></div>   <div class="colorBubble"></div> </div>

CSS Code

* {   box-sizing: border-box; }  body {   padding: 0;   margin: 0;   font-family: "Roboto", sans-serif;   overflow: hidden; }  .wrap {   position: relative;   width: 700px;   margin: auto;   visibility: hidden; }  .slider {   position: absolute;   left: 0;   top: 0;   background: #1bb1a5;   box-shadow: 0 2px 5px -1px rgba(0, 0, 0, 0.3);   border-radius: 100px;   height: 100%; }  .tabs-block {   display: flex;   padding: 0;   flex-direction: row;   border: 1px solid rgba(0, 0, 0, 0.1);   border-radius: 100px;   width: 700px;   height: auto;   margin: 50px auto;   position: relative; }  li {   text-align: center;   margin: 0;   padding: 10px;   flex: auto;   font-size: 18px;   font-weight: 700;   color: #1bb1a5;   position: relative;   cursor: pointer;   list-style: none;   user-select: none; }  h1 {   margin: 0;   padding: 0;   color: #1bb1a5; }  .article-block {   width: 700px;   margin: auto;   overflow: hidden;   box-shadow: 0 10px 12px -12px rgba(0, 0, 0, 0.4) inset;   background: #fff;   border-bottom: 1px solid #1bb1a5;   position: relative;   border-radius: 24px;   visibility: hidden; }  .article {   position: absolute;   padding: 20px;   left: 0;   top: 0;   line-height: 1.5; }  .colorBubble {   width: 24px;   height: 24px;   background-color: black;   border-radius: 100%;   margin: 0 2px;   cursor: pointer; }  .colors {   display: flex;   flex-direction: row;   align-content: center;   align-items: center;   justify-content: center;   margin: 20px auto;   width: 700px;   visibility: hidden; }  #impactBurst {   position: absolute;   height: 100%;   width: auto; }

Javascript snippet

claconsole.clear(); TweenLite.defaultEase = Linear.easeNone; TweenMax.set(".wrap, .article-block, .colors", {autoAlpha:1}); var targets = document.querySelectorAll("li"); var articles = document.querySelectorAll(".article"); var colorArray = ["#1bb1a5", "#94c356", "#e3aa59", "#777", "#a63ba0", "#cf5b21", "#46a4cc", "#000"]; var colorSwatches = document.querySelectorAll(".colorBubble"); var activeTab = 0; var old = 0; var heights = []; var widths = []; var dur = 0.4; var burstDur = 0.2; var animation; var loopStart = 0; var loopEnd = 0; var activeColor = colorArray[0];  for (let i = 0; i < targets.length; i++) {   targets[i].index = i;   heights.push(articles[i].offsetHeight); // get height of each article   widths.push(targets[i].offsetWidth); // get width of each tab   TweenMax.set(articles[i], {top: 0, y:-heights[i]}); // push all articles up out of view   targets[i].addEventListener("click", doCoolStuff); }  // set initial article and position stretchy bubble slider on first tab  TweenMax.set(articles[0], {y:0}); TweenMax.set(".slider", {x:targets[0].offsetLeft, width:targets[0].offsetWidth}); TweenMax.set(targets[0], {color:"#fff"}); TweenMax.set(".article-block", {height:heights[0]}); TweenMax.set("#burst", {stroke:activeColor}); TweenMax.set("line", {drawSVG:0});  function doCoolStuff() {   // check if clicked target is new and if the timeline is currently active   if(this.index != activeTab) {     //if there's an animation in-progress, jump to the end immediately so there aren't weird overlaps.      if (animation && animation.isActive()) {       animation.progress(1);     }     animation = new TimelineMax();     old = activeTab;     activeTab = this.index;     stretch = 0;          if (activeTab > old) {       loopStart = old;       loopEnd = activeTab;       // moving left to right position the impact burst on the right side of target       animation.set("#impactBurst", {x:targets[activeTab].offsetLeft + widths[activeTab], scaleX:1});      } else {       loopStart = activeTab;       loopEnd = old;       // moving right to left position the impact burst on the left side of target and scaleX:-1       animation.set("#impactBurst", {x:targets[activeTab].offsetLeft, scaleX:-1, transformOrigin:"left center"});       // if moving slider bubble right to left, also animate new x position while stretching       animation.to(".slider", dur, {x:targets[activeTab].offsetLeft, ease:Power2.easeIn}, 0);     }     // get total width of all tabs between new and old (inclusive)      for (let i = loopStart; i < loopEnd + 1; i++) {       stretch += widths[i];     }        // stretch the slider bubble to the start of the new target     animation.to(".slider", dur, {width:stretch, ease:Power2.easeIn}, 0);     // animate the lines of the impact burst     animation.fromTo("line", burstDur/3, {drawSVG:"0% 0%"}, {drawSVG:"0% 40%"}, "springBack");     animation.to("line", burstDur/3, {drawSVG:"70% 100%"});     animation.to("line", burstDur/3, {drawSVG:"100% 100%", ease:Sine.easeOut});     // animate bubble slider to clicked target     animation.to(".slider", dur, {x:targets[activeTab].offsetLeft, width:widths[activeTab], ease:Power2.easeOut}, "springBack");     // change text color on old and new tab targets     animation.to(targets[old], dur, {color:activeColor}, "springBack");     animation.to(targets[activeTab], dur, {color:"#fff"}, "springBack");     // slide current article down out of view and then set it to starting position at top     animation.to(articles[old], dur, {y:heights[old], ease:Back.easeIn }, "springBack");     animation.set(articles[old], {y:-heights[old]});     // resize article block to accommodate new content     animation.to(".article-block", dur, {height:heights[activeTab], ease:Power2.easeOut});     // slide in new article     animation.to(articles[activeTab], 1, {y:0, ease: Elastic.easeOut}, "-=0.25");   } }  // just stuff related to the color change swatches down here for (let i = 0; i < colorSwatches.length; i++) {   TweenMax.set(colorSwatches[i], { backgroundColor: colorArray[i] });   colorSwatches[i].index = i;   colorSwatches[i].addEventListener("click", colorChange); }  function colorChange() {   activeColor = colorArray[this.index];   TweenMax.to(".slider", dur, { backgroundColor: activeColor });   TweenMax.to("h1, li", dur, { color: activeColor });   TweenMax.to(targets[activeTab], dur, { color: "#fff" });   TweenMax.to(".article-block", dur, {borderBottom: "1px solid " + activeColor});   TweenMax.to("#burst", dur, {stroke:activeColor}); }

Preview

Stretchy Tab & Springy Content Slider with bursts

About CV

I'm frontend developer

Check Also

Naturalized Checkbox Toggle Switches

This demo is a response to a post by Marcus Connor addressing confusion with checkbox …