LOADING...

Preview

Pen ID
Unlock Campus Themeforest adv

 

Code
Pull down
CSS
*, *:before, *:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  font-size: 62.5%;
}
@media (max-width: 768px) {
  html, body {
    font-size: 50%;
  }
}

body {
  background: #EDEFF2;
}

.demo {
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -18.3rem;
  margin-top: -23.5rem;
  width: 36.6rem;
  height: 47rem;
  background: #FFFFFF;
  border-radius: 1.2rem;
  box-shadow: 0 2rem 2rem rgba(0, 0, 0, 0.15);
  overflow: hidden;
}
.demo__top {
  position: relative;
  height: 18.6rem;
  background: -webkit-linear-gradient(#7BCECA, #82D3CB);
  background: linear-gradient(#7BCECA, #82D3CB);
  overflow: hidden;
}
.demo__body {
  position: relative;
  min-height: 56.8rem;
  padding-top: 5rem;
  will-change: transform;
}

.pull-down {
  position: absolute;
  left: 0;
  top: 1rem;
  width: 100%;
  font-size: 2rem;
  text-align: center;
  color: rgba(84, 92, 103, 0.6);
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  pointer-events: none;
}
.pull-down:before, .pull-down:after {
  content: "";
  position: absolute;
  top: 0;
  width: 1rem;
  height: 1rem;
  border: 1px solid rgba(84, 92, 103, 0.6);
  border-left: none;
  border-top: none;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
  -webkit-animation: arrowAnim 1.5s infinite;
          animation: arrowAnim 1.5s infinite;
}
.pull-down:before {
  left: 11rem;
}
.pull-down:after {
  left: 25rem;
}

@-webkit-keyframes arrowAnim {
  to {
    -webkit-transform: translateY(1.3rem) rotate(45deg);
            transform: translateY(1.3rem) rotate(45deg);
    opacity: 0;
  }
}

@keyframes arrowAnim {
  to {
    -webkit-transform: translateY(1.3rem) rotate(45deg);
            transform: translateY(1.3rem) rotate(45deg);
    opacity: 0;
  }
}
.items {
  position: relative;
}
.items.padded {
  -webkit-transition: padding 0.3s;
  transition: padding 0.3s;
  padding-top: 8rem;
}

.item {
  height: 8rem;
  padding: 2rem 2.5rem;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  -webkit-transition: opacity 0.3s;
  transition: opacity 0.3s;
}
.item.absPos {
  position: absolute;
  left: 0;
  top: 0;
}
.item.hidden {
  opacity: 0;
}
.item__icon {
  display: inline-block;
  vertical-align: top;
  width: 4rem;
  height: 4rem;
  margin-right: 2rem;
  border-radius: 50%;
}
.item__icon.animated {
  -webkit-animation: animateIcon 0.6s forwards;
          animation: animateIcon 0.6s forwards;
}
.item__icon.m--img img {
  width: 100%;
}
.item__name {
  font-size: 2rem;
  line-height: 4rem;
  color: #545C67;
}

@-webkit-keyframes animateIcon {
  20% {
    -webkit-transform: scaleY(0.7);
            transform: scaleY(0.7);
  }
  40% {
    -webkit-transform: scaleY(0.9);
            transform: scaleY(0.9);
  }
  60% {
    -webkit-transform: scaleY(0.6);
            transform: scaleY(0.6);
  }
  80% {
    -webkit-transform: scaleY(1.1);
            transform: scaleY(1.1);
  }
  100% {
    -webkit-transform: scaleY(1);
            transform: scaleY(1);
  }
}

@keyframes animateIcon {
  20% {
    -webkit-transform: scaleY(0.7);
            transform: scaleY(0.7);
  }
  40% {
    -webkit-transform: scaleY(0.9);
            transform: scaleY(0.9);
  }
  60% {
    -webkit-transform: scaleY(0.6);
            transform: scaleY(0.6);
  }
  80% {
    -webkit-transform: scaleY(1.1);
            transform: scaleY(1.1);
  }
  100% {
    -webkit-transform: scaleY(1);
            transform: scaleY(1);
  }
}
.plane-cont {
  position: absolute;
  left: 1.7rem;
  top: -2.8rem;
  width: 5.6rem;
  height: 5.6rem;
  background: #5DB2DF;
  border-radius: 50%;
  box-shadow: 0 0.3rem 0.3rem rgba(0, 0, 0, 0.3);
}

.plane-rotater {
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -1rem;
  margin-top: -1.3rem;
  width: 2.8rem;
  height: 2.6rem;
}

.plane.fly {
  -webkit-animation: planeFly 3.5s forwards;
          animation: planeFly 3.5s forwards;
}

@-webkit-keyframes planeFly {
  28% {
    -webkit-transform: translate(55rem, 13rem) rotate(20deg) scale(0.7);
            transform: translate(55rem, 13rem) rotate(20deg) scale(0.7);
  }
  35% {
    -webkit-transform: translate(45rem, -8rem) rotate(-160deg) scale(0.5);
            transform: translate(45rem, -8rem) rotate(-160deg) scale(0.5);
  }
  85% {
    -webkit-transform: translate(-15rem, -4rem) rotate(-180deg) scale(0.7);
            transform: translate(-15rem, -4rem) rotate(-180deg) scale(0.7);
  }
  90% {
    -webkit-transform: translate(-15rem, 0) rotate(0deg);
            transform: translate(-15rem, 0) rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(0deg);
            transform: rotate(0deg);
  }
}

@keyframes planeFly {
  28% {
    -webkit-transform: translate(55rem, 13rem) rotate(20deg) scale(0.7);
            transform: translate(55rem, 13rem) rotate(20deg) scale(0.7);
  }
  35% {
    -webkit-transform: translate(45rem, -8rem) rotate(-160deg) scale(0.5);
            transform: translate(45rem, -8rem) rotate(-160deg) scale(0.5);
  }
  85% {
    -webkit-transform: translate(-15rem, -4rem) rotate(-180deg) scale(0.7);
            transform: translate(-15rem, -4rem) rotate(-180deg) scale(0.7);
  }
  90% {
    -webkit-transform: translate(-15rem, 0) rotate(0deg);
            transform: translate(-15rem, 0) rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(0deg);
            transform: rotate(0deg);
  }
}
.svgBg__bg {
  -webkit-transform-origin: 183px 256px;
          transform-origin: 183px 256px;
}
.svgBg__tree-trunk {
  fill: #1E5E65;
}
.svgBg__tree-part {
  -webkit-transform-origin: inherit;
          transform-origin: inherit;
}
.svgBg__tree-1 {
  -webkit-transform-origin: 54px 147px;
          transform-origin: 54px 147px;
  opacity: 0.7;
}
.svgBg__tree-1 .svgBg__tree-part {
  -webkit-transform: scale(0.35, 0.44);
          transform: scale(0.35, 0.44);
}
.svgBg__tree-2 {
  -webkit-transform-origin: 67px 144px;
          transform-origin: 67px 144px;
  opacity: 0.7;
}
.svgBg__tree-2 .svgBg__tree-part {
  -webkit-transform: scale(0.56, 0.65);
          transform: scale(0.56, 0.65);
}
.svgBg__tree-3 {
  -webkit-transform-origin: 264px 149px;
          transform-origin: 264px 149px;
}
.svgBg__tree-3 .svgBg__tree-part {
  -webkit-transform: scale(0.58, 0.65);
          transform: scale(0.58, 0.65);
}
.svgBg__tree-4 {
  -webkit-transform-origin: 287px 148px;
          transform-origin: 287px 148px;
}
.svgBg__tree-4 .svgBg__tree-part {
  -webkit-transform: scale(0.8, 1);
          transform: scale(0.8, 1);
}
.svgBg__tree-5 {
  -webkit-transform-origin: 313px 148px;
          transform-origin: 313px 148px;
}
.svgBg__tree-5 .svgBg__tree-part {
  -webkit-transform: scale(0.5, 0.61);
          transform: scale(0.5, 0.61);
}

/*
font awesome icon slicing effect from https://codepen.io/suez/pen/KpwEeg
*/
.icon-box {
  position: relative;
  display: inline-block;
  vertical-align: top;
  width: 4rem;
  height: 4rem;
  background: #0c0c0c;
  overflow: hidden;
  font-size: 0;
  text-decoration: none;
  border-radius: 50%;
}
.icon-box:before {
  content: "";
  position: absolute;
  left: 16.66667%;
  top: 0;
  margin-left: -1px;
  width: 2px;
  height: 0.6rem;
  background: #fff;
  -webkit-transition: -webkit-transform 0.5s;
  transition: -webkit-transform 0.5s;
  transition: transform 0.5s;
  transition: transform 0.5s, -webkit-transform 0.5s;
  -webkit-transform: rotate(-30deg) translate(0.33333rem, -1rem);
          transform: rotate(-30deg) translate(0.33333rem, -1rem);
}
.icon-box:hover:before {
  -webkit-animation: slice 0.5s;
          animation: slice 0.5s;
}
.icon-box__inner {
  position: relative;
  display: inline-block;
  vertical-align: top;
  overflow: hidden;
  width: 50%;
  height: 100%;
  -webkit-transform: rotate(-30deg);
          transform: rotate(-30deg);
  font-size: 2.4rem;
  color: #fff;
}
.icon-box__inner .fa {
  position: absolute;
  top: 50%;
  -webkit-transform: translate(-50%, -50%) rotate(30deg);
          transform: translate(-50%, -50%) rotate(30deg);
}
.icon-box__inner.m--left {
  -webkit-transform-origin: 100% 50%;
          transform-origin: 100% 50%;
}
.icon-box__inner.m--left .fa {
  left: 100%;
}
.icon-box__inner.m--right {
  -webkit-transform-origin: 0 50%;
          transform-origin: 0 50%;
  -webkit-transition: -webkit-transform 0.5s;
  transition: -webkit-transform 0.5s;
  transition: transform 0.5s;
  transition: transform 0.5s, -webkit-transform 0.5s;
}
.icon-box:hover .icon-box__inner.m--right {
  -webkit-transition: -webkit-transform 0.5s 0.1s;
  transition: -webkit-transform 0.5s 0.1s;
  transition: transform 0.5s 0.1s;
  transition: transform 0.5s 0.1s, -webkit-transform 0.5s 0.1s;
  -webkit-transform: rotate(-30deg) translate(0.2rem, 0.4rem);
          transform: rotate(-30deg) translate(0.2rem, 0.4rem);
}
.icon-box__inner.m--right .fa {
  left: 0;
}

@-webkit-keyframes slice {
  to {
    -webkit-transform: rotate(-30deg) translate(0.33333rem, 7rem);
            transform: rotate(-30deg) translate(0.33333rem, 7rem);
  }
}

@keyframes slice {
  to {
    -webkit-transform: rotate(-30deg) translate(0.33333rem, 7rem);
            transform: rotate(-30deg) translate(0.33333rem, 7rem);
  }
}
JS
'use strict';

window.requestAnimFrame = (function() {
  return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {
    window.setTimeout(callback, 1000 / 60);
  };
})();

$(document).ready(function() {

  var $top = $(".demo__top");
  var $body = $(".demo__body");
  var $bg1 = $(".svgBg__bg1");
  var $bg2 = $(".svgBg__bg2");
  var $bg3 = $(".svgBg__bg3");
  // jQuery have problems with getting svg elements attrs, so I'm using vanillaJS
  var $trees = [].slice.call(document.querySelectorAll(".svgBg__tree"));
  var $treeParts = [].slice.call(document.querySelectorAll(".svgBg__tree-part"));
  var $leftTrees = $(".svgBg__tree.m--left");
  var $rightTrees = $(".svgBg__tree.m--right");
  var $planeRotater = $(".plane-rotater");
  var $plane = $(".plane");
  var isDesktop = window.matchMedia("(min-width: 769px)").matches;
  var topH = (isDesktop) ? 186 : 149;
  var bg1change, bg2change, bg3change;
  var bg1max = (isDesktop) ? 10 : 8;
  var bg2max = (isDesktop) ? 22 : 18;
  var bg3max = (isDesktop) ? 44 : 35;
  var pullDeltaY;
  var maxPullDeltaY = (isDesktop) ? 70 : 56;
  var treesData = {};
  var treeMaxX = (isDesktop) ? 18 : 14;
  var treeMaxCoef = treeMaxX / maxPullDeltaY;
  var treeChange;
  var planeMaxDeg = -45; // defines maximum plane rotation deg during pull event
  var planeMaxCoef = planeMaxDeg / maxPullDeltaY;
  var planeChange;
  var frame = 1000 / 60; // 60 frames per second
  // duration for release animation for all elements, except flying plane
  var releaseTime = 900;
  var animating = false;
  var planeAnimTime = 3500; // this value must be synced with SASS $planeAnimTime
  
  /* You can find these easing functions on this site
  http://timotheegroleau.com/Flash/experiments/easing_function_generator.htm
  Also, you can customize them with generator,
  like i customized this elasticBig easing, to heavily shake these trees
  */
  var easings = {
    elastic: 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);
    },
    elasticBig: function(t,b,c,d) {
      var ts = (t/=d)*t;
      var tc = ts*t;
      return b+c*(21*tc*ts + -150*ts*ts + 250*tc + -150*ts + 30*t);
    },
    inCubic: function(t,b,c,d) {
      var tc = (t/=d)*t*t;
      return b+c*(tc);
    }
  };
  
  /* store clones in object */
  var cloneCounter = 1;
  var $items = $(".items");
  var clones = {
    clone1: $(".item-1").clone(),
    clone2: $(".item-2").clone(),
    clone3: $(".item-3").clone()
  };
  
  /* Applies class with padding transition, which shifts content down,
  then it's prepends clone with 0 opacity and absolute position (0,0).
  Then this clone fades in and padding class being removed from $items and
  absolute position removed from inserted clone
  */
  function insertNewClone() {
    var $clone = clones["clone"+cloneCounter];
    $clone.addClass("absPos hidden");
    $items.prepend($clone).addClass("padded");
    $clone.css("top");
    $clone.removeClass("hidden");
    $clone.find(".item__icon").addClass("animated");
    cloneCounter++;
    if (cloneCounter > 3) cloneCounter = 1;
    setTimeout(function() {
      $items.removeClass("padded");
      $clone.removeClass("absPos");
    }, 300);
  };
  
  /* This looks messy, but basically I'm storing tree parts paths D attributes as arrays
  and X&Y coordinates of middle points.
  */
  function storeTreeCoords() {
    var treeId, treeObj, trunkTop, leafsTop;
    
    $trees.forEach(function($tree) {
      treeId = $tree.getAttribute("data-id");
      treesData["tree"+treeId] = {};
      treeObj = treesData["tree"+treeId];
      treeObj.isRight = $tree.classList.contains("m--right");
      treeObj.$treeTrunk = $tree.querySelector(".svgBg__tree-trunk");
      treeObj.$treeLeafs = $tree.querySelector(".svgBg__tree-leafs");
      treeObj.trunkInitArrD = treeObj.$treeTrunk.getAttribute("d").split(" ");
      treeObj.leafsInitArrD = treeObj.$treeLeafs.getAttribute("d").split(" ");
      trunkTop = treeObj.trunkInitArrD[2];
      leafsTop = treeObj.leafsInitArrD[3];
      treeObj.trunkInitX = +trunkTop.split(",")[0];
      treeObj.leafsInitX = +leafsTop.split(",")[0];
      treeObj.trunkInitY = +trunkTop.split(",")[1];
      treeObj.leafsInitY = +leafsTop.split(",")[1];
    });
  };
  
  storeTreeCoords();
  
  /* Each tree consists of two parts - trunk and leafs. 
  Both of these parts created with two quadratic bezier curves (left and right sides).
  Trunk created with C curve, leafs with Q curve. Here you can find good explanation about them:
  http://tutorials.jenkov.com/svg/path-element.html
  Basically, I'm just changing middle point X coordinate of each part
  and it's affects both curves, so this looks like I'm magically tilt these trees
  */
  function tiltTrees(x) {
    var treeId, treeObj, trunkArr, leafsArr, changeX;

    $trees.forEach(function($tree) {
      treeId = $tree.getAttribute("data-id");
      treeObj = treesData["tree"+treeId];
      trunkArr = treeObj.trunkInitArrD.slice();
      leafsArr = treeObj.leafsInitArrD.slice();
      changeX = (treeObj.isRight) ? x : -x;
      
      trunkArr[2] = (treeObj.trunkInitX + changeX/2) + "," + treeObj.trunkInitY;
      leafsArr[3] = (treeObj.leafsInitX + changeX) + "," + treeObj.leafsInitY;

      treeObj.$treeTrunk.setAttribute("d", trunkArr.join(" "));
      treeObj.$treeLeafs.setAttribute("d", leafsArr.join(" "));
    });
  };
  
  /* Moving mountains and tree  elements with transform translateY
  transform-origin's hardcoded for each element in css and scales with viewBox
  */
  function moveBgs() {
    $bg1.css({"-webkit-transform": "translate3d(0,"+bg1change+"px, 0)",
              "transform": "translate3d(0,"+bg1change+"px, 0)"});
    $bg2.css({"-webkit-transform": "translate3d(0,"+bg2change+"px, 0)",
              "transform": "translate3d(0,"+bg2change+"px, 0)"});
    $bg3.css({"-webkit-transform": "translate3d(0,"+bg3change+"px, 0)",
              "transform": "translate3d(0,"+bg3change+"px, 0)"});
    $leftTrees.css({"-webkit-transform": "translate3d(0,"+bg2change+"px, 0)",
                    "transform": "translate3d(0,"+bg2change+"px, 0)"});
    $rightTrees.css({"-webkit-transform": "translate3d(0,"+bg3change+"px, 0)",
                     "transform": "translate3d(0,"+bg3change+"px, 0)"});
  };
  
  function checkMaxBgValues() {
    if (bg1change > bg1max) bg1change = bg1max;
    if (bg2change > bg2max) bg2change = bg2max;
    if (bg3change > bg3max) bg3change = bg3max;
  };
  
  // applies changes for all elements
  function applyChanges(topY) {
    $top.css("height", topH + topY + "px");
    moveBgs();
    tiltTrees(treeChange);
    $planeRotater.css({"-webkit-transform": "rotate("+planeChange+"deg)",
                       "transform": "rotate("+planeChange+"deg)"});
  };
  
  /* calculates numbers for applyChanges function, when
  you are using mousemove/touchmove pull event
  */
  function pullChange(y) {
    if (y < 0) y = 0;
    if (y > maxPullDeltaY) y = maxPullDeltaY;
    bg1change = bg2change = bg3change = y;
    checkMaxBgValues();
    treeChange = y * treeMaxCoef;
    planeChange = y * planeMaxCoef;
    
    applyChanges(y);
  };
  
  /* calculates numbers for applyChanges function, when
  release event is fired
  */
  function releaseChange(props) {
    bg1change = bg2change = bg3change = props.bgY;
    checkMaxBgValues();
    treeChange = props.treeVal * treeMaxCoef;
    planeChange = props.planeDeg * planeMaxCoef;
    
    applyChanges(props.topY);
  };
  
  function release() {
    // number of frames, which you need to animate with requestAnimationFrame
    var steps = Math.floor(releaseTime / frame);
    var curStep = 0;
    var topY, bgY, treeVal, planeDeg;
    var y = pullDeltaY;
    if (y > maxPullDeltaY) y = maxPullDeltaY;
    var releasePlane = y >= maxPullDeltaY/2;
    animating = true; // prevents from pull event during animation
    // if you pulled more than 1/2 of maxPullDeltaY - starts the plane flight animation
    if (releasePlane) {
      $plane.addClass("fly"); // adds class to plane with keyframes animation
      setTimeout(function() {
        // when animation is over, allow pull events, remove keyframes class and add new clone
        animating = false;
        $plane.removeClass("fly");
        insertNewClone();
      }, planeAnimTime);
    }
    
    /* this function fires each available frame,
    until animation will be over (curStep > steps)
    */
    function animate() {
      curStep++;
      // applies different easings for different groups of elements
      topY = easings.elastic(curStep, y, 0 - y, steps);
      bgY = easings.elastic(curStep, y, 0 - y, steps);
      treeVal = easings.elasticBig(curStep, y, 0 - y, steps);
      planeDeg = easings.inCubic(curStep, y, 0 - y, steps);
      
      releaseChange({topY: topY, bgY: bgY, treeVal: treeVal, planeDeg: planeDeg});
      
      if (curStep > steps) {
        pullDeltaY = 0;
        // if pulled less than 1/2 of maxPullDeltaY - allow pull event earlier
        if (!releasePlane) animating = false;
        return;
      }
      requestAnimFrame(animate);
    }
    animate();
  };
  
  /* On mousedown/touchstart, attaches mousemove/touchmove events
  for dynamic pull change events. When mouseup/touchend event fired -
  runs release function and removes move/end events
  */
  $(document).on("mousedown touchstart", ".demo__body", function(e) {
    if (animating) return; // prevents from pulling during the release animation
    var startY =  e.pageY || e.originalEvent.touches[0].pageY;
    
    $(document).on("mousemove touchmove", function(e) {
      var y = e.pageY || e.originalEvent.touches[0].pageY;
      pullDeltaY = (y - startY) / 1.5; // slightly slow pull event for better experience
      if (!pullDeltaY) return; // prevents from rapid click events
      pullChange(pullDeltaY);
    });

    $(document).on("mouseup touchend", function() {
      $(document).off("mousemove touchmove mouseup touchend");
      if (!pullDeltaY) return; // prevents from rapid click events
      release();
    });
  });
  
  // source - http://davidwalsh.name/javascript-debounce-function
  function debounce(func, wait, immediate) {
    var timeout;
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      var callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) func.apply(context, args);
    };
  };
  
  /* redifine max values for desktop/mobile
  all other things scales with rem units and viewBox
  */
  var resizeFn = debounce(function() {
    isDesktop = window.matchMedia("(min-width: 769px)").matches;
    topH = (isDesktop) ? 186 : 149;
    bg1max = (isDesktop) ? 10 : 8;
    bg2max = (isDesktop) ? 22 : 18;
    bg3max = (isDesktop) ? 44 : 35;
    maxPullDeltaY = (isDesktop) ? 70 : 56;
    treeMaxX = (isDesktop) ? 18 : 14;
  }, 100);
  
  $(window).on("resize", resizeFn);
  

});

Description

Based on Zee Young dribbble - https://dribbble.com/shots/2067564-Replace
Term
Mon, 11/27/2017 - 21:26

Related Codes

Pen ID
Pen ID
Pen ID
Square Adv