정보실

웹학교

정보실

design 애니메이션 풍선 범위 슬라이더

본문

모든 프로젝트에 부드럽게 표시되는 아름답고 간단한 범위의 풍선 풍선 애니메이션. 


https://codepen.io/aaroniker/pen/ZEEWoKj 


HTML :

<div id="slider"></div>


<!-- dribbble -->

<a class="dribbble" href="https://dribbble.com/shots/7515563-Balloon-Slider" target="_blank"><img src="https://cdn.dribbble.com/assets/dribbble-ball-mark-2bd45f09c2fb58dbbfb44766d5d1d07c5a12972d602ef8b32204d28fa3dda554.svg" alt=""></a>


CSS :  

#slider {

  --active: #5628EE;

  --balloon: var(--active);

  --value: #fff;

  --line: #CDD9ED;

  touch-action: none;

  -webkit-user-select: none;

     -moz-user-select: none;

      -ms-user-select: none;

          user-select: none;

  width: 320px;

  height: 2px;

  border-radius: 1px;

  background: var(--line);

  position: relative;

}

#slider .noUi-connects .noUi-connect {

  background: var(--active);

}

#slider .noUi-handle:before, #slider .noUi-handle:after {

  border-radius: 20px;

  -webkit-transform: scale(var(--s));

          transform: scale(var(--s));

  transition: border-radius .3s ease, -webkit-transform .3s ease;

  transition: transform .3s ease, border-radius .3s ease;

  transition: transform .3s ease, border-radius .3s ease, -webkit-transform .3s ease;

}

#slider .noUi-handle:before {

  --s: .5;

  background: var(--active);

}

#slider .noUi-handle:after {

  --s: .2;

  background: #fff;

}

#slider .noUi-handle.noUi-active:before {

  --s: 1;

}

#slider .noUi-handle.noUi-active:after {

  --s: 1;

}

#slider .balloon {

  --o: 0;

  --s: 0;

  --y: 0;

  --r: 0deg;

  width: 52px;

  height: 68px;

  pointer-events: none;

  position: absolute;

  z-index: 5;

  left: -26px;

  bottom: 0;

  -webkit-transform-origin: 50% 100%;

          transform-origin: 50% 100%;

}

#slider .balloon > div {

  width: 52px;

  height: 68px;

  -webkit-transform-origin: 50% 100%;

          transform-origin: 50% 100%;

  opacity: var(--o);

  -webkit-transform: scale(var(--s)) translate(0, var(--y)) rotate(var(--r));

          transform: scale(var(--s)) translate(0, var(--y)) rotate(var(--r));

  transition: opacity .4s ease, -webkit-transform .4s ease;

  transition: transform .4s ease, opacity .4s ease;

  transition: transform .4s ease, opacity .4s ease, -webkit-transform .4s ease;

}

#slider .balloon > div:before, #slider .balloon > div:after {

  content: '';

  display: block;

}

#slider .balloon > div:before {

  width: 52px;

  height: 52px;

  border-radius: 60%;

  border-bottom-left-radius: 480%;

  border-bottom-right-radius: 480%;

  border-top-left-radius: 480%;

  -webkit-transform: rotate(135deg);

          transform: rotate(135deg);

  background: var(--balloon);

}

#slider .balloon > div:after {

  content: attr(data-value);

  font-family: 'Roboto', Arial;

  font-size: 14px;

  font-weight: 500;

  color: var(--value);

  position: absolute;

  left: 0;

  right: 0;

  top: 16px;

  line-height: 24px;

  text-align: center;

}

#slider .balloon > div svg {

  display: block;

  width: 8px;

  height: 6px;

  fill: var(--balloon);

  position: absolute;

  left: 22px;

  bottom: 0;

}

#slider .balloon.active {

  --o: 1;

  --s: 1;

  --y: -36px;

}

#slider * {

  touch-action: none;

  -webkit-user-select: none;

     -moz-user-select: none;

      -ms-user-select: none;

          user-select: none;

  -webkit-tap-highlight-color: transparent;

}

#slider.noUi-state-tap .noUi-connect, #slider.noUi-state-tap .noUi-origin {

  transition: -webkit-transform .3s;

  transition: transform .3s;

  transition: transform .3s, -webkit-transform .3s;

}

#slider .noUi-target {

  position: relative;

}

#slider .noUi-base,

#slider .noUi-connects {

  position: relative;

  z-index: 1;

  width: 100%;

  height: 100%;

}

#slider .noUi-origin,

#slider .noUi-connect {

  position: absolute;

  will-change: transform;

  -webkit-transform-origin: 0 0;

          transform-origin: 0 0;

  top: 0;

  left: 0;

  z-index: 1;

}

#slider .noUi-connects {

  overflow: hidden;

  z-index: 0;

  border-radius: 1px;

}

#slider .noUi-connects .noUi-connect {

  width: 100%;

  height: 100%;

}

#slider .noUi-handle {

  -webkit-backface-visibility: hidden;

          backface-visibility: hidden;

  position: absolute;

  outline: none;

  cursor: pointer;

  width: 40px;

  height: 40px;

  left: 12px;

  top: -19px;

}

#slider .noUi-handle:before, #slider .noUi-handle:after {

  content: '';

  position: absolute;

}

#slider .noUi-handle:before {

  left: 0;

  top: 0;

  width: 40px;

  height: 40px;

}

#slider .noUi-handle:after {

  left: 2px;

  top: 2px;

  width: 36px;

  height: 36px;

}

#slider .noUi-origin {

  left: auto;

  right: 0;

  height: 0;

  width: 10%;

}


html {

  box-sizing: border-box;

  -webkit-font-smoothing: antialiased;

}


* {

  box-sizing: inherit;

}

*:before, *:after {

  box-sizing: inherit;

}


body {

  min-height: 100vh;

  display: flex;

  font-family: 'Roboto', Arial;

  justify-content: center;

  align-items: center;

  background: #F5F9FF;

}

body .dribbble {

  position: fixed;

  display: block;

  right: 20px;

  bottom: 20px;

}

body .dribbble img {

  display: block;

  height: 28px;

}




JS : 

let slider = document.getElementById('slider'),

    balloon,

    balloonTransform,

    balloonReset;


noUiSlider.create(slider, {

    start: 60,

    connect: 'lower',

    range: {

        min: 0,

        max: 100

    }

});


if(!balloon) {


    let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');

    svg.setAttribute('viewBox', '0 0 8 6');

    let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');

    path.setAttribute('d','M3.19770784,0.400189793 L0.183732919,4.48916968 C-0.132777702,4.91857125 -0.0301446804,5.51531196 0.41297019,5.82202737 C0.58019429,5.93777661 0.780561067,6 0.986063367,6 L7.01401322,6 C7.55855868,6 8,5.57222019 8,5.04452705 C8,4.84538453 7.93578945,4.65121861 7.81634366,4.48916968 L4.80236874,0.400189793 C4.48585812,-0.0292117777 3.87005999,-0.128668564 3.42694512,0.178046844 C3.33840792,0.239330552 3.2609487,0.314392601 3.19770784,0.400189793 Z');

    svg.appendChild(path);


    let inner = document.createElement('div');


    inner.appendChild(svg);


    balloon = document.createElement('div');

    balloon.classList.add('balloon');

    balloon.appendChild(inner);


    slider.getElementsByClassName('noUi-base')[0].appendChild(balloon);


    balloonTransform = new Proxy({

        r: 0

    }, {

        set(target, key, value) {

            target[key] = value;

            balloon.style.setProperty('--r', target.r + 'deg');

            return true;

        },

        get(target, key) {

            return target[key];

        }

    });


}


var timestamp = null,

    lastX = null,

    startedMoving = false,

    moved = false;


slider.noUiSlider.on('start', function() {

    let percent = this.get() / this.options.range.max * 100;

    balloon.classList.add('active');

    balloon.childNodes[0].dataset.value = Math.round(this.get());

    TweenMax.to(balloon, 0, {

        x: this.target.offsetWidth * percent / 100,

        scale: .75 + .25 * percent / 100

    });

    balloonReset = setInterval(() => {

        if(!moved && startedMoving) {

            TweenMax.to(slider.getElementsByClassName('noUi-handle')[0], .3, {

                css: {

                    scale: 1

                }

            });

            balloonTransform.r = 0;

            startedMoving = false;

        }

        moved = false;

    }, 20);

});


slider.noUiSlider.on('slide', function() {

    let percent = this.get() / this.options.range.max * 100;

    balloon.childNodes[0].dataset.value = Math.round(this.get());

    if(timestamp === null) {

        timestamp = Date.now();

        lastX = this.get();

        return;

    }

    var now = Date.now(),

        speedX = Math.round((this.get() - lastX) / (now - timestamp) * 160),

        speedX = speedX > 10 ? 10 : speedX < -10 ? -10 : speedX;


    balloonTransform.r = speedX * -2;


    startedMoving = true;

    moved = true;


    TweenMax.to(balloon, 1.4, {

        x: this.target.offsetWidth * percent / 100,

        scale: .75 + .25 * percent / 100,

        ease: Elastic.easeOut.config(1, .6)

    });


    TweenMax.to(slider.getElementsByClassName('noUi-handle')[0], .3, {

        css: {

            scale: .9

        }

    });


    timestamp = now;

    lastX = this.get();

});


slider.noUiSlider.on('end', function() {

    balloon.classList.remove('active');

    clearInterval(balloonReset);

});








  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

페이지 정보

조회 8회 ]  작성일19-11-30 22:36

웹학교