Pull Down to Refresh Plane
by Chun
HTML
<div class="popularStoryWrapper">
<div class="popularStory">
<div class="popularStory__top">
<svg class="popularStory__top-svgBg" viewBox="0 0 366 256">
<g class="svgBg__objects">
<path class="svgBg__bg svgBg__bg1" fill="#86D7DB" d="M0,143 88,107 224,153 348,109 366,123 366,256 0,256z" />
<path class="svgBg__bg svgBg__bg2" fill="#3C929A" d="M0,156 106,136 272,172 342,124 366,144 366,256 0,256z" />
<path class="svgBg__bg svgBg__bg3" fill="#416175" d="M0,170 62,160 235,148 305,145 366,153 366,256 0,256z" />
<g class="svgBg__tree svgBg__tree-1 m--left" data-id="1">
<path class="svgBg__tree-leafs svgBg__tree-part" fill="#389296" d="M54,127 C77,127 62,95 54,63 C46,95 31,127 54,127" />
<path class="svgBg__tree-trunk svgBg__tree-part" d="M56,147 Q55,115 54,83 Q53,115 52,146" />
</g>
<g class="svgBg__tree svgBg__tree-2 m--left" data-id="2">
<path class="svgBg__tree-leafs svgBg__tree-part" fill="#389296" d="M67,124 C90,124 75,92 67,59 C59,92 44,124 67,124" />
<path class="svgBg__tree-trunk svgBg__tree-part" d="M69,144 Q68,112 67,80 Q66,112 65,143" />
</g>
<g class="svgBg__tree svgBg__tree-3 m--right" data-id="3">
<path class="svgBg__tree-leafs svgBg__tree-part" fill="#389296" d="M264,129 C287,129 272,97 264,64 C256,97 241,129 264,129" />
<path class="svgBg__tree-trunk svgBg__tree-part" d="M266,149 Q265,117 264,85 Q263,117 262,148" />
</g>
<g class="svgBg__tree svgBg__tree-4 m--right" data-id="4">
<path class="svgBg__tree-leafs svgBg__tree-part" fill="#207277" d="M287,128 C310,128 295,96 287,63 C279,96 264,128 287,128" />
<path class="svgBg__tree-trunk svgBg__tree-part" d="M289,148 Q288,116 287,84 Q286,116 285,147" />
</g>
<g class="svgBg__tree svgBg__tree-5 m--right" data-id="5">
<path class="svgBg__tree-leafs svgBg__tree-part" fill="#389296" d="M313,128 C336,128 321,96 313,63...
CSS
.popularStoryWrapper *, .popularStoryWrapper *:before, .popularStoryWrapper *:after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.popularStoryWrapper {
width:300px;
}
@media (max-width: 768px) {
.popularStoryWrapper {
}
}
body {
background: #EDEFF2;
}
.popularStory {
width: 100%;
height: 25rem;
background: #FFFFFF;
border-radius: 1.2rem;
box-shadow: 0 2rem 2rem rgba(0, 0, 0, 0.15);
overflow: hidden;
}
.popularStory__top {
position: relative;
height: 8.6rem;
padding-bottom: 8px;
background: linear-gradient(#7BCECA, #82D3CB);
overflow: hidden;
}
.popularStory__body {
position: relative;
min-height: 56.8rem;
padding-top: 3rem;
will-change: transform;
}
.pull-down {
position: absolute;
left: 0;
top: 1rem;
width: 100%;
padding-right: 4rem;
text-align: right;
color: rgba(84, 92, 103, 0.6);
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;
transform: rotate(45deg);
animation: arrowAnim 1.5s infinite;
}
.pull-down:before {
left: 8rem;
}
.pull-down:after {
left: 16rem;
}
@keyframes arrowAnim {
to {
transform: translateY(1.3rem) rotate(45deg);
opacity: 0;
}
}
.itemPieces {
position: relative;
}
.itemPieces.padded {
transition: padding 0.3s;
padding-top: 8rem;
}
.itemPiece {
padding: 5px 15px;
user-select: none;
transition: opacity 0.3s;
}
.itemPiece.absPos {
position: absolute;
left: 0;
top: 0;
}
.itemPiece.hidden {
opacity: 0;
}
.itemPiece__icon {
display: inline-block;
vertical-align: top;
width: 4rem;
height: 4rem;
margin-right: 2rem;
border-radius: 50%;
}
.itemPiece__icon.animated {
animation: animateIcon 0.6s forwards;
}
.itemPiece__icon.m--img img {
width: 100%;
}
.itemPiece__name {
line-height: 3rem;
color:...
JavaScript
'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 = $(".popularStory__top");
var $body = $(".popularStory__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 $planeYoRotater = $(".planeYo-rotater");
var $planeYo = $(".planeYo");
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 planeYoMaxDeg = -45; // defines maximum planeYo rotation deg during pull event
var planeYoMaxCoef = planeYoMaxDeg / maxPullDeltaY;
var planeYoChange;
var frame = 1000 / 60; // 60 frames per second
// duration for release animation for all elements, except flying planeYo
var releaseTime = 900;
var animating = false;
var planeYoAnimTime = 3500; // this value must be synced with SASS $planeYoAnimTime
/* 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,
...