<div class="helper"><p>Use your mouse or finger to drag the credit card</p></div>

<div id="target" class="credit-card">
  <div class="credit-card__header">
    <div class="credit-card__header__logo">
      <img src="data:image/png;base64,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" alt="Citi logo" />
    </div>
    <div class="credit-card__header__type credit-card__header__type--maestro"></div>
  </div>
  <div class="credit-card__iban">
    <span>4112</span>
    <span>1645</span>
    <span>8236</span>
    <span>1134</span>
  </div>
  <div class="credit-card__valid">
    <span class="credit-card__valid__label">Valid thru</span>
    <span class="credit-card__valid__date">06/12</span>
  </div>
  <div class="credit-card__owner">
    <span>Donald Trump</span></div>
</div>
</div>
@import 'bourbon';
@import url('https://fonts.googleapis.com/css?family=Noto+Sans');
@import url('https://fonts.googleapis.com/css?family=Share+Tech+Mono');

$background-color: #3A3A47;
$color-2: #DF3A62;
$color-3: #7E57C2;

body {
  color: white;
  overflow: hidden;
  background: $background-color;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  perspective: 10em;
}

.helper {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  text-align: center;
}

.credit-card {
  transition: transform 500ms $ease-out-expo;
  cursor: move;
  color: white;
  width: 20em;
  font-family: 'Share Tech Mono', monospace;
  border-radius: 1em;
  text-align: left;
  padding: 1em;
  background: #DF3A62;
  background: #7E57C2;
  background: linear-gradient(135deg, $color-2 0%, $color-3 100%);
  position: absolute;
  z-index: 10;
}

.credit-card__header {
  pointer-events: none;
  margin: .5em 0 0 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.credit-card__header__logo {
  pointer-events: none;
  display: inline-block;
  
  img {
    width: 4em;
  }
}

.credit-card__header__type {
  pointer-events: none;
  width: 3em;
  height: 2em;
  display: inline-block;
}

.credit-card__header__type--maestro {
  position: relative;
  
  &:before,
  &:after {
    border-radius: 50%;
    content: '';
    width: 2em;
    height: 2em;
    background: white;
    position: absolute;
  }
  
  &:before {
    opacity: 0.75;
    left: 0;
  }
  
  &:after {
    opacity: 0.4;
    right: 0;
  }
}

.credit-card__iban {
  pointer-events: none;
  margin: 2em 0 0;
  display: flex;
  justify-content: space-between;
  
  > span {
    display: block;
    font-size: 1.8em;
  }
}

.credit-card__valid {
  pointer-events: none;
  margin: 1em 0 0;
  display: flex;
  align-items: center;
  
  &__label {
    font-size: .8em;
    text-transform: uppercase;
    text-align: left;
    display: inline-block;
    height: 2em;
    width: 3em;
  }
  
  &__date {
    margin-left: 1em;
    font-size: 1.2em;
    display: inline-block;
  }
}

.credit-card__owner {
  pointer-events: none;
  margin: 1.5em 0 0;
  > span {
    text-transform: uppercase;
    font-size: 1.4em;
  }
}
View Compiled
const target = document.getElementById('target')

const mousemove = Rx.Observable.fromEvent(document, 'mousemove')
const touchmove = Rx.Observable.fromEvent(document, 'touchmove')

const mousedown = Rx.Observable.fromEvent(target, 'mousedown')
const touchstart = Rx.Observable.fromEvent(target, 'touchstart')

const mouseup = Rx.Observable.fromEvent(document, 'mouseup')
const touchend = Rx.Observable.fromEvent(document, 'touchend')

const mousedrag = mousedown.flatMap(md => {
  const rect = target.getBoundingClientRect()

  const startX = md.offsetX
  const startY = md.offsetY
  
  return mousemove.map(mm => {
    mm.preventDefault()
    
    return {
      left: mm.clientX - startX,
      top: mm.clientY - startY
    }
  }).takeUntil(mouseup)
})

const touchdrag = touchstart.flatMap(ts => {
  const rect = target.getBoundingClientRect()
  
  const startX = ts.targetTouches[0].clientX - rect.left
  const startY = ts.targetTouches[0].clientY - rect.top
  
  return touchmove.map(tm => {
    tm.preventDefault()
    
    return {
      left: tm.targetTouches[0].clientX - startX,
      top: tm.targetTouches[0].clientY - startY
    }
  }).takeUntil(touchend)
})

const drag = Rx.Observable.merge(mousedrag, touchdrag)

const dt = 5

const velocity = drag.throttle(dt).pairwise().map(md => {
  let sx = md[1].left - md[0].left
  let sy = md[0].top - md[1].top
  
  let vx = sx / dt // pixels/milisecond
  let vy = sy / dt
  
  return { vx, vy }
})

velocity.subscribe(vel => {
  let x = vel.vx * 2
  let y = vel.vy * 2
  
  let maxAngle = 7
  
  if (x > maxAngle) x = maxAngle
  if (x < -maxAngle) x = -maxAngle
  if (y > maxAngle) y = maxAngle
  if (y < -maxAngle) y = -maxAngle
  
  target.style.transform = `rotateX(${y}deg) rotateY(${x}deg)`
})

mousedown.subscribe(md => target.style.transformOrigin = `${md.offsetX}px ${md.offsetY}px`)
touchstart.subscribe(ts => target.style.transformOrigin = `${ts.offsetX}px ${ts.offsetY}px`)

drag.subscribe(pos => {
  target.style.top = `${pos.top}px`
  target.style.left = `${pos.left}px`
})

mouseup.subscribe(mo => target.style.transform = 'rotateX(0) rotateY(0)')
touchend.subscribe(te => target.style.transform = 'rotateX(0) rotateY(0)')

// initial position
const rect = target.getBoundingClientRect()
target.style.top = `${(window.innerHeight - rect.height) / 2}px`
target.style.left = `${(window.innerWidth - rect.width) / 2}px`

View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.com/rx@4.1.0/dist/rx.all.min.js