본문 바로가기
디자인/디자인 이야기

모바일 드래그 카드 CSS

by 코코리★ 2018. 1. 17.
728x90


Pull down on the cards


마우스를 아래로 드래그하면 카드가 나오는 css




         ->        





Pull to refresh - iPhone X

Pull down on the cards
16:22
Inbox
PAYMENT
Apple store
12 Manchester st., London
-$999
View balance
5m ago
release
PAYMENT
Starbucks
100 Washington st, New York
-$8
View balance
2h ago
CASH WITHDRAWAL
Citi bank
52 Philadelphia st, San Francisco
-$150
View balance
2h ago
INCOMING PAYMENT
PayPal
$40
View balance
yesterday at 14:02



데모 보기 : https://codepen.io/kiyutink/pen/vpravo






HTML





<!DOCTYPE html>

<html lang="en" >


<head>

  <meta charset="UTF-8">

  <title>Pull to refresh - iPhone X</title>

  <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">

<script src="https://use.fontawesome.com/540e0b3a64.js"></script>

  

  

      <link rel="stylesheet" href="css/style.css">


  

</head>


<body>


  <div class="demo">  

  <div class="demo__description">

    Pull down on the cards

  </div>

  <div class="demo__phone">

    <div class="demo__screen-wrapper">

      <div class="demo__screen">

        <div class="demo__indicator demo__indicator--time">16:22</div>

        <div class="demo__indicator demo__indicator--signal">

          <i class="fa fa-signal"></i>

        </div>

        <div class="demo__indicator demo__indicator--battery">

          <i class="fa fa-battery"></i>

        </div>

        <div class="demo__controls">

          <div class="demo__arrow">

            <i class="fa fa-chevron-left"></i>

          </div>

          <div class="demo__caption">Inbox</div>

        </div>


        <div class="demo__card demo__card demo__card--notched">

          <div class="demo__card-frontside">

            <div class="demo__card-type">PAYMENT</div>

            <div class="demo__card-body">

              <div class="demo__card-picture demo__card-picture--apple"></div>

              <div class="demo__card-info">

                <div class="demo__card-caption">Apple store</div>

                <div class="demo__card-description">12 Manchester st., London</div>

              </div>

              <div class="demo__card-money">-$999</div>

            </div>

            <div class="demo__card-bottom">

              <div class="demo__card-button">View balance</div>

              <div class="demo__card-time">5m ago</div>

            </div>

          </div>

          <div class="demo__card-backside">

            <div class="demo__card-release">

              release

            </div>

          </div>

        </div>


        <div class="demo__card demo__card--regular">

          <div class="demo__card-frontside">

            <div class="demo__card-type">PAYMENT</div>

            <div class="demo__card-body">

              <div class="demo__card-picture demo__card-picture--starbucks"></div>

              <div class="demo__card-info">

                <div class="demo__card-caption">Starbucks</div>

                <div class="demo__card-description">100 Washington st, New York</div>

              </div>

              <div class="demo__card-money">-$8</div>

            </div>

            <div class="demo__card-bottom">

              <div class="demo__card-button">View balance</div>

              <div class="demo__card-time">2h ago</div>

            </div>

          </div>

          <div class="demo__card-backside"></div>

        </div>

        <div class="demo__card demo__card--regular">

          <div class="demo__card-frontside">

            <div class="demo__card-type">CASH WITHDRAWAL</div>

            <div class="demo__card-body">

              <div class="demo__card-picture demo__card-picture--citi"></div>

              <div class="demo__card-info">

                <div class="demo__card-caption">Citi bank</div>

                <div class="demo__card-description">52 Philadelphia st, San Francisco</div>

              </div>

              <div class="demo__card-money">-$150</div>

            </div>

            <div class="demo__card-bottom">

              <div class="demo__card-button">View balance</div>

              <div class="demo__card-time">2h ago</div>

            </div>

          </div>

          <div class="demo__card-backside"></div>

        </div>


        <div class="demo__card demo__card--regular">

          <div class="demo__card-frontside">

            <div class="demo__card-type">INCOMING PAYMENT</div>

            <div class="demo__card-body">

              <div class="demo__card-picture demo__card-picture--paypal"></div>

              <div class="demo__card-info">

                <div class="demo__card-caption">PayPal</div>

                <div class="demo__card-description"></div>

              </div>

              <div class="demo__card-money">$40</div>

            </div>

            <div class="demo__card-bottom">

              <div class="demo__card-button">View balance</div>

              <div class="demo__card-time">yesterday at 14:02</div>

            </div>

          </div>

          <div class="demo__card-backside"></div>

        </div>

      </div>

    </div>

    <div class="demo__notch"></div>

  </div>  

</div>

  <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>


  


    <script  src="js/index.js"></script>





</body>


</html>







CSS




*, *:before, *:after {

  -webkit-box-sizing: border-box;

          box-sizing: border-box;

  margin: 0;

  padding: 0;

}


.demo {

  display: -webkit-box;

  display: -ms-flexbox;

  display: flex;

  -webkit-box-orient: vertical;

  -webkit-box-direction: normal;

      -ms-flex-direction: column;

          flex-direction: column;

  -webkit-box-align: center;

      -ms-flex-align: center;

          align-items: center;

  -webkit-box-pack: center;

      -ms-flex-pack: center;

          justify-content: center;

  padding: 20px;

  font-family: 'Open Sans', sans-serif;

  background-color: #FECA45;

}

.demo__description {

  font-size: 20px;

  padding-bottom: 20px;

}

.demo__phone {

  position: relative;

  width: 305.25px;

  height: 633px;

  padding-top: 1px;

  background-color: #120d30;

  border-radius: 40px;

}

.demo__notch {

  position: absolute;

  top: 12px;

  left: 74.25px;

  height: 22.5px;

  width: 156.75px;

  background-color: #120d30;

  border-radius: 0 0 15px 15px;

}

.demo__screen {

  position: relative;

  height: 609px;

  width: 281.25px;

  padding-top: 25px;

  background: -webkit-gradient(linear, left top, left bottom, from(#4a3972), to(#5e4a9d));

  background: linear-gradient(#4a3972, #5e4a9d);

  border-radius: 30px;

  cursor: -webkit-grab;

  cursor: grab;

  -webkit-user-select: none;

     -moz-user-select: none;

      -ms-user-select: none;

          user-select: none;

  -webkit-perspective: 700px;

          perspective: 700px;

}

.demo__screen-wrapper {

  position: relative;

  height: 609px;

  width: 281.25px;

  margin-top: 11px;

  margin-left: 12px;

  overflow: hidden;

  border-radius: 30px;

}

.demo__indicator {

  position: absolute;

  top: 2.5px;

  font-size: 13.5px;

  color: white;

}

.demo__indicator--time {

  left: 18.75px;

}

.demo__indicator--signal {

  right: 45px;

}

.demo__indicator--battery {

  font-size: 14.25px;

  right: 16.5px;

}

.demo__controls {

  position: relative;

  display: -webkit-box;

  display: -ms-flexbox;

  display: flex;

  -webkit-box-pack: center;

      -ms-flex-pack: center;

          justify-content: center;

  padding: 6.25px 0;

  font-size: 18.75px;

  color: white;

}

.demo__arrow {

  position: absolute;

  left: 12.5px;

}

.demo__card {

  position: relative;

  margin: 9px;

  height: 142.5px;

  width: calc(100% - 18px);

  font-size: 17.5px;

  border-radius: 5px;

  -webkit-transform-style: preserve-3d;

          transform-style: preserve-3d;

}

.demo__card--notched {

  position: absolute;

  top: 0;

  -webkit-transform: rotateX(180deg) scale(0.6) translateY(175px);

          transform: rotateX(180deg) scale(0.6) translateY(175px);

}

.demo__card--processing {

  position: absolute;

  top: 0;

  -webkit-transform: translateY(62.5px);

          transform: translateY(62.5px);

}

.demo__card-frontside {

  position: absolute;

  top: 0;

  width: 100%;

  height: 100%;

  padding-top: 9px;

  padding-bottom: 4.5px;

  background-color: white;

  border-radius: 5px;

  -webkit-backface-visibility: hidden;

          backface-visibility: hidden;

}

.demo__card-backside {

  display: -webkit-box;

  display: -ms-flexbox;

  display: flex;

  -webkit-box-pack: center;

      -ms-flex-pack: center;

          justify-content: center;

  -webkit-box-align: end;

      -ms-flex-align: end;

          align-items: flex-end;

  position: absolute;

  top: 0;

  width: 100%;

  height: 100%;

  color: white;

  background: -webkit-gradient(linear, left top, left bottom, color-stop(50%, #120d30), to(#211858));

  background: linear-gradient(#120d30 50%, #211858);

  border-radius: 25px;

  -webkit-transform: rotateX(180deg);

          transform: rotateX(180deg);

  -webkit-backface-visibility: hidden;

          backface-visibility: hidden;

}

.demo__card-release {

  padding: 5px;

  opacity: 0;

  -webkit-transition: opacity 0.2s ease;

  transition: opacity 0.2s ease;

}

.demo__card-type {

  padding-left: 18px;

  font-size: 12.5px;

  color: #aaa;

}

.demo__card-body {

  display: -webkit-box;

  display: -ms-flexbox;

  display: flex;

  -webkit-box-align: center;

      -ms-flex-align: center;

          align-items: center;

  padding-left: 18px;

  padding-right: 18px;

  padding-top: 9px;

  padding-bottom: 9px;

}

.demo__card-picture {

  width: 50px;

  height: 50px;

  -ms-flex-negative: 0;

      flex-shrink: 0;

  border-radius: 50%;

  background-size: contain;

  background-repeat: no-repeat;

  background-position: center;

}

.demo__card-picture--starbucks {

  background-image: url(https://kiyutink.github.io/logos/starbucks.svg);

}

.demo__card-picture--citi {

  background-image: url(https://kiyutink.github.io/logos/citi.png);

}

.demo__card-picture--paypal {

  background-image: url(https://kiyutink.github.io/logos/paypal.svg);

}

.demo__card-picture--apple {

  background-image: url(https://kiyutink.github.io/logos/apple.png);

}

.demo__card-info {

  width: 70%;

  margin-left: 9px;

  margin-right: 9px;

}

.demo__card-caption {

  width: 100%;

  font-weight: 700;

}

.demo__card-description {

  min-height: 37.5px;

  font-size: 13.75px;

}

.demo__card-money {

  font-size: 17.5px;

  font-weight: 700;

}

.demo__card-bottom {

  display: -webkit-box;

  display: -ms-flexbox;

  display: flex;

  -webkit-box-pack: justify;

      -ms-flex-pack: justify;

          justify-content: space-between;

  border-top: 1px solid #ddd;

}

.demo__card-button {

  padding-top: 4.5px;

  padding-left: 18px;

  color: #6b6281;

  cursor: pointer;

}

.demo__card-time {

  padding-top: 9px;

  padding-right: 18px;

  font-size: 12.5px;

  color: #ddd;

}


.animation {

  -webkit-transition: -webkit-transform 0.5s cubic-bezier(0.55, 0.26, 0.12, 1.19);

  transition: -webkit-transform 0.5s cubic-bezier(0.55, 0.26, 0.12, 1.19);

  transition: transform 0.5s cubic-bezier(0.55, 0.26, 0.12, 1.19);

  transition: transform 0.5s cubic-bezier(0.55, 0.26, 0.12, 1.19), -webkit-transform 0.5s cubic-bezier(0.55, 0.26, 0.12, 1.19);

}


.short-animation {

  -webkit-transition: -webkit-transform .2s ease;

  transition: -webkit-transform .2s ease;

  transition: transform .2s ease;

  transition: transform .2s ease, -webkit-transform .2s ease;

}




JS

$(document).ready(function() { 

  const SCALE = 4;

  const ANIMATION_DURATION = 500;

  const QUICK_ANIMATION_DURATION = 200;

  const DRAG_LIMIT = 375;

  

  let initialMouseY;

  let lastTranslateValue = 0;

  let diff = 0;

  let busy = false;

  let cardsCreated = 0;

  let $notched = $('.demo__card--notched');

  let $controls = $('.demo__controls');

  let $cards = $('.demo__card');

  let $regularCards = $('.demo__card--regular');

  let $timeIndicator = $('.demo__indicator--time');  

  

  const codepenCard = {

    type: 'LINK',

    imageUrl: 'https://kiyutink.github.io/logos/codepen.png',

    caption: '<a class="demo__profile-link" href="https://codepen.io/kiyutink/" target="_blank">My codepen</a>',

    description: 'Check out my other pens',

    time: 'just now'

  }

  

  const twitterCard = {

    type: 'LINK',

    imageUrl: 'https://kiyutink.github.io/logos/twitter.jpg',

    caption: '<a class="demo__profile-link" href="https://twitter.com/kiyutin_k" target="_blank">My twitter</a>',

    description: 'Follow me',

    time: 'just now'

  }

  

  const dribbbleCard = {

    type: 'LINK',

    imageUrl: 'https://kiyutink.github.io/logos/dribbble.png',

    caption: '<a class="demo__profile-link" href="https://dribbble.com/shots/4089014-Pull-To-Refresh-iPhone-X" target="_blank">Dribble shot</a>',

    description: 'By Saptarshi Prakash',

    time: 'just now'

  }

  

  setCurrentTime();

  setInterval(setCurrentTime, 60 * 1000);  

  

  function setCurrentTime() {

    const curDate = new Date();

    let hours = curDate.getHours() + '';

    if (hours.length <= 1)

      hours = 0 + hours;

    let minutes = curDate.getMinutes() + '';

    if (minutes.length <= 1)

      minutes = 0 + minutes;

    $timeIndicator.text(`${hours}:${minutes}`);

  }

  

  

  $(document).on('mousedown', '.demo__screen', e => {

    e.preventDefault();

    if (busy) return;

    initialMouseY = e.clientY;

    

    $(document).on('mousemove', scrollCards);

  });

  

  function scrollCards(e) {

    diff = e.clientY - initialMouseY;

    if (diff < 0) 

      return;

     

    if (diff < DRAG_LIMIT / SCALE) 

      $notched.find('.demo__card-release').css('opacity', 0);    

      

    if (diff > DRAG_LIMIT / SCALE) {

      diff = DRAG_LIMIT / SCALE;

      $notched.find('.demo__card-release').css('opacity', 0.6);

    }

    

    $notched.css('transform', `scale(0.6) rotateX(180deg) translateY(${700 / SCALE - diff}px)`)

    $regularCards.css('transform', `translateY(${diff + lastTranslateValue}px)`);

  }

  

  function makeCard(cardDetails) {    

    return `

      <div class="demo__card demo__card demo__card--notched">

        <div class="demo__card-frontside">

          <div class="demo__card-type">${cardDetails.type}</div>

          <div class="demo__card-body">

            <div class="demo__card-picture" style='background-image: url(${cardDetails.imageUrl});'></div>

            <div class="demo__card-info">

              <div class="demo__card-caption">${cardDetails.caption}</div>

              <div class="demo__card-description">${cardDetails.description}</div>

            </div>            

          </div>

          <div class="demo__card-bottom">

              <div class="demo__card-button">View balance</div>

              <div class="demo__card-time">${cardDetails.time}</div>

          </div>

        </div>

        <div class="demo__card-backside">

            <div class="demo__card-release">

              release

            </div>

        </div>

      </div>

`;

  }

  

  

  $(window).on('mouseup', () => {

    $(document).off('mousemove', scrollCards);

    lastTranslateValue = diff + lastTranslateValue;

    if (lastTranslateValue >= DRAG_LIMIT / SCALE) {

      busy = true;

      const animatedCard = $('.demo__card--notched');

      $cards.addClass('animation');

      setTimeout(() => {

        $cards.removeClass('animation');

        animatedCard.addClass('demo__card--regular').removeClass('demo__card--processing');

        $regularCards = $('.demo__card--regular');

        $regularCards.css('transform', 'none');

        busy = false;

      }, ANIMATION_DURATION);

      

      $regularCards.css('transform', `translateY(${605 / SCALE}px)`);

      $notched.css('transform', '').removeClass('demo__card--notched').addClass('demo__card--processing');

      

      if (cardsCreated >= 4)

        cardsCreated = 0;

      

      switch (cardsCreated) {

        case 0:

          $controls.after(makeCard(codepenCard));

          break;

        case 1:

          $controls.after(makeCard(twitterCard));

          break;

        case 2:

          $controls.after(makeCard(dribbbleCard));

          break;

        case 3:

          $controls.after(makeCard({

            type: 'PAYMENT',

            caption: 'Kirill Kiyutin',

            imageUrl: 'https://kiyutink.github.io/profile-pic.jpg',

            description: 'Moscow, Russia',            

            time: 'just now'

          }));

          break;

      }

      

      cardsCreated ++;

      

      $notched = $('.demo__card--notched');

      $cards = $('.demo__card');

    }

    

    else {

      if (busy)

        return;

      $cards.addClass('short-animation');

      setTimeout(() => {        

        $cards.removeClass('short-animation');

      }, QUICK_ANIMATION_DURATION);

      $notched.css('transform', `rotateX(180deg) scale(0.6) translateY(${700 / SCALE}px)`);

      $regularCards.css('transform', 'none');      

    }

    diff = 0;

    lastTranslateValue = 0;

  });  

});























728x90

댓글