Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                style.
  /* prevent FOUC */
  .muddle {
    opacity: 0;
  }

.flex-center-children.vh-1.padding-1
  #sample-card.card
    .close-button X
    #sample-button.button More info
    #sample-paragraph.muddle 
      | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia voluptatum id at laborum inventore ex non, magnam fugiat, consequatur fugit, vero quisquam qui fuga soluta ullam iure voluptatibus. Ab, nihil.

              
            
!

CSS

              
                @import "bourbon";

body {
  font-family: 'Ubuntu condensed';
}

.vh-1 {
  height: 100vh;
}

.padding-1 {
  padding: 2em;
  box-sizing: border-box;
}

.flex-center-children {
  @include display(flex);
  @include flex-direction(column);
  @include align-items(center);
  @include justify-content(center);
  @include perspective(1000px);
}

#sample-card {
  @include transform(translateZ(-800px) scale(0.7));
}

.card {
  @include display(flex);
  @include align-items(center);
  @include perspective(1000px);
  position: relative;
  box-shadow: 0 0 8px 0 #444;
  background-color: #36C;
  color: white;
  text-align: center;
  width: 100%;
  max-width: 350px;
  padding: 2em 3em;
  font-size: 1.2em;
  cursor: pointer;
}

.card:hover {
  // box-shadow: 0 0 15px 0 rgba(black, 0.7);
}

.muddle {
  line-height: 1.4
}

.muddle-word {
  display: inline-block;
  opacity: 0;
  user-select: none;
}

.button {
  @include position(absolute, 0 0 0 0);
  @include display(flex);
  @include align-items(center);
  @include justify-content(center);
  font-size: 2.5em;
  z-index: 1;
  user-select: none;
}

.close-button {
  @include position(absolute, 0 0 null null);
  opacity: 0;
  background-color: white;
  border-radius: 50%;
}
              
            
!

JS

              
                let card = document.querySelector('#sample-card')
let button = document.querySelector('#sample-button')
let paragraph = document.querySelector('#sample-paragraph')
let words = paragraph.innerText.split(' ')
let wordsMarkedUp = words.map(word => {
  return `<div class="muddle-word">${word}</div>
  <span> </span>`
})

let viewWidth = window.innerWidth
let viewHeight = window.innerHeight
let midX = viewWidth / 2
let midY = viewHeight / 2

function setDimensions() {
  viewWidth = window.innerWidth
  viewHeight = window.innerHeight
  midX = viewWidth / 2
  midY = viewHeight / 2
}

window.addEventListener('resize', setDimensions)

paragraph.innerHTML = wordsMarkedUp.join('')
paragraph.style.opacity = 1

let wordNodes = paragraph.querySelectorAll('.muddle-word')

function zoomOut(node, reverse = false) {
  let visible = { opacity: 1, z: 0 }
  let hidden = { opacity: 0, z: -1000 }
  let start = reverse ? hidden : visible
  let end = reverse ? visible : hidden
  node.style.transform = transform(start)
  node.style.opacity = start.opacity
  return new TWEEN.Tween(start)
    .to(end, 300)
    .onUpdate(function() {
      node.style.transform = transform(this)
      node.style.opacity = Math.min(this.opacity, 1)
    })
    .easing(TWEEN.Easing.Elastic.Out)
    .start()
}

function zoomIn(node, reverse = false) {
  let contracted = { opacity: 0, z: -800, depth: 8, s: 0.7 }
  let expanded = { opacity: 1, z: 0, depth: 10, s: 1 }
  let start = reverse ? expanded : contracted
  let end = reverse ? contracted : expanded
  let opacityMax = 0
  node.style.transform = transform(start);
  node.style.opacity = start.opacity;
  node.style.boxShadow = `0 0 ${start.depth}px 0 #444`
  return new TWEEN.Tween(start)
  .to(end, 600)
  .onUpdate(function() {
    node.style.transform = transform(this)
    node.style.boxShadow = `0 0 ${this.depth}px 0 #444`
    // Only ever *increase* opacity (for elastic/bounce)
    if (this.opacity > opacityMax && !reverse) {
      node.style.opacity = Math.min(this.opacity, 1)
      opacityMax = Math.min(this.opacity, 1)
    }
  })
  .easing(TWEEN.Easing.Elastic.Out)
  .start()
}

let staggerTweens

function staggerZoom(nodeList, reverse = false) {
  if (staggerTweens) {
    staggerTweens.forEach((t) => {
      t.stop()
    })
  }
  let tweens = []
  for (var i = 0; i < nodeList.length; i++) {
    let node = nodeList[i]
    let hidden = { opacity: 0, y: (Math.random() * -50), z: -200 }
    let visible = { opacity: 1, y: 0, z: 0 }
    let start = reverse ? visible : hidden
    let end = reverse ? hidden : visible
    let opacityMin = 1
    node.style.transform = transform(0, start.y, start.z)
    node.style.opacity = start.opacity
    tweens.push(new TWEEN.Tween(start)
      .to(end,500 + (20 * i))
      .onUpdate(function() {
        node.style.transform = transform(this)
        // Only ever *decrease* opacity
        if (this.opacity < opacityMin && reverse) {
          node.style.opacity = Math.max(this.opacity, 0)
          opacityMin = Math.max(this.opacity, 0)
        } else if (!reverse) {
          node.style.opacity = this.opacity
        }
      })
      .easing(TWEEN.Easing.Elastic.Out)
      .delay(20)
      .start()
    )
  }
  staggerTweens = tweens
}

function metricOrZero(val, metric) {
  return `${val}${val === 0 ? '' : metric}`
}

function degreeValue(val) {
  return metricOrZero(val, 'deg')
}

function pixelValue(val) {
  return metricOrZero(val, 'px')
}

function transform(values) {
  return `${translate3d(values)} ${rotate3(values)} ${scale(values)}`
}

function scale(values) {
  return `scale(${values.s || 1})`
}

function rotate3(values) {
  let x = degreeValue (values.rx || 0)
  let y = degreeValue (values.ry || 0)
  let z = degreeValue (values.rz || 0)
  return `rotateX(${x}) rotateY(${y}) rotateZ(${z})`
}

function translate3d(values) {
  let x = pixelValue (values.x || 0)
  let y = pixelValue (values.y || 0)
  let z = pixelValue (values.z || 0)
  return `translate3d(${x}, ${y}, ${z})`
}

let cardExpanded = false

card.addEventListener('click', () => {
  zoomIn(card, cardExpanded)
  zoomOut(button, cardExpanded)
  staggerZoom(wordNodes, cardExpanded)
  cardExpanded = !cardExpanded
})

requestAnimationFrame(animate)
function animate(time) {
  requestAnimationFrame(animate)
  TWEEN.update(time)
}
              
            
!
999px

Console