Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

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

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

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

              
                <a href="https://youtu.be/UbOCO7TOl00" target="_blank" data-keyframers-credit style="color: #FFF"></a>
<script src="https://codepen.io/shshaw/pen/QmZYMG.js"></script>

<div id="app" data-current-planet="mercury">

  <nav class="planet-nav">
    <svg viewBox="0 20 400 400" xmlns="http://www.w3.org/2000/svg">

<!--       <defs> -->
        <path 
            id="navPath" 
            d="M10,200 C30,-28 370,-28 390,200"
            fill="none" />
<!--       </defs> -->

      <text>
        <textPath href="#navPath" startOffset="0" font-size="10">
          <tspan>Mercury</tspan>
          <tspan>Venus</tspan>
          <tspan>Earth</tspan>
          <tspan>Mars</tspan>
          <tspan>Jupiter</tspan>
          <tspan>Saturn</tspan>
          <tspan>Uranus</tspan>
          <tspan>Neptune</tspan>
        </textPath>
      </text>

    </svg>
  </nav>

  <div class="planet" data-planet="mercury" data-active>
    <div class="planet-title">
      <h1>Mercury</h1>
      <p class="planet-description">Tiny and close to the sun.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        3.13
      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        0.9
      </div>
      <div class="detail" data-detail="hours">
        10
      </div>
    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/1_mercury.jpg" />
    </figure>
  </div>

  <div class="planet" data-planet="venus">
    <div class="planet-title">
      <h1>Venus</h1>
      <p class="planet-description">A planet of razors and tennis players.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        4.13
      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        0.2
      </div>
      <div class="detail" data-detail="hours">
        20
      </div>
    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/2_venus.jpg" />
    </figure>
  </div>

  <div class="planet" data-planet="earth">
    <div class="planet-title">
      <h1>Earth</h1>
      <p class="planet-description">Voted best planet in the Solar System by all organisms.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        5.13
      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        7.3
      </div>
      <div class="detail" data-detail="hours">
        30
      </div>
    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/3_earth.jpg" />
    </figure>
  </div>

  <div class="planet" data-planet="mars">
    <div class="planet-title">
      <h1>Mars</h1>
      <p class="planet-description">Future Site of Elon Musk's AirBnB.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        6.13
      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        1.1
      </div>
      <div class="detail" data-detail="hours">
        40
      </div>
    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/4_mars.jpg" />
    </figure>
  </div>

  <div class="planet" data-planet="jupiter">
    <div class="planet-title">
      <h1>Jupiter</h1>
      <p class="planet-description">Twice as massive as the other planets combined.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        11.13
      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        1.8
      </div>
      <div class="detail" data-detail="hours">
        50
      </div>
    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/5_jupiter.jpg" />
    </figure>
  </div>

  <div class="planet" data-planet="saturn">
    <div class="planet-title">
      <h1>Saturn</h1>
      <p class="planet-description">This planet sponsored by Zales.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        9.13
      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        7.3
      </div>
      <div class="detail" data-detail="hours">
        60
      </div>
    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/6_saturn.jpg" />
    </figure>
  </div>

  <div class="planet" data-planet="uranus">
    <div class="planet-title">
      <h1>Uranus</h1>
      <p class="planet-description">Hey, stop laughing. It's not funny.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        11.13
      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        1.8
      </div>
      <div class="detail" data-detail="hours">
        50
      </div>    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/7_uranus.jpg" />
    </figure>
  </div>


  <div class="planet" data-planet="neptune">
    <div class="planet-title">
      <h1>Neptune</h1>
      <p class="planet-description">A planet for pirates; just narrowly made the cut when scientists decided nine planets was too many.</p>
    </div>

    <div class="planet-details">
      <div class="detail" data-detail="tilt" data-postfix="°">
        31.03      </div>
      <div class="detail" data-detail="gravity" data-postfix="𝗑">
        8.9      </div>
      <div class="detail" data-detail="hours">
        10
      </div>
    </div>

    <figure class="planet-figure">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/8_neptune.jpg" />
    </figure>
  </div>
</div>
              
            
!

CSS

              
                @import url('https://fonts.googleapis.com/css?family=DM+Sans:400,700&display=swap');

:root {
  --duration: .8s;
  --half-duraiton: calc( var(--duration) / 2 );
  --ease: cubic-bezier(.7, 0, .3, 1);
}

*, *:before, *:after {
  box-sizing: border-box;
  position: relative;
}

html, body {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}

body {
  background: black;
  color: white;
  font-family: 'DM Sans', sans-serif;
}

img { max-width: 100%; }

// ---------------------

#app {
  height: 100%;
  width: 100%;

  display: grid;
  grid-template-columns: 1;
  grid-template-rows: 1fr 1fr;
}

.planet {
  grid-column: 1;
  grid-row: 1 / -1;
  overflow: hidden;
  height: 100%;
  width: 100%;
  display: grid;
  grid-template-columns: 10% 40% 40% 10%;
  grid-template-rows: 10% 1fr 1fr;
  grid-template-areas: 
    "header header header header"
    "x title details y"
    "x planet photos photos";

  > .planet-title {
    display: block;
    grid-area: title;
  }

  > .planet-figure {
    grid-column: 1 / -1;
    grid-row: planet; 
    padding: 0;
    margin: 0 auto;
    position: relative;
    
    img { 
      margin-bottom: -50%;
    }

    &::after {
      content: '';
      position: fixed;
      bottom: 0%;
      top: 0%;
      width: 100%;
      left: 0;
      background: linear-gradient(to top, rgba(#000,.7) 0%, transparent 30%);
      z-index: 2;
    }
  }

  > .planet-details {
    grid-area: details;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
  }

}

.detail {
  font-size: 5vmin;
  width: 3em;
  font-weight: 400;
  display: flex;
  margin-left: .4em;
  flex-shrink: 0;
  align-self: start;

  &:after {
    content: attr(data-postfix); 
  }

  &:before {
    display: block;
    position: absolute;
    top: 100%;
    margin-top: 1rem;
    font-size: .75rem;
    text-transform: uppercase;
    opacity: 0.6;
    letter-spacing: 1px;
  }

  &[data-detail="hours"]:before {
    content: 'Hours'
  }

  &[data-detail="gravity"]:before {
    content: 'gravity'
  }
  &[data-detail="tilt"]:before {
    content: 'tilt'
  }
}

h1, h2 {
  margin: 0;
}

/* ---------------------------------- */

.planet {
  visibility: hidden;
  // opacity: 0;
  transition: visibility 0.01s linear var(--duration);

  // > * { transition: opacity var(--duration) var(--ease); }

  &[data-active] {
    visibility: visible;
    opacity: 1;
    transition-delay: 0s;
  }
  
  /* ---------------------------------- */

  .planet-title {
    .word { overflow: hidden; }
    .char { 
      transform: translateY(100%);
      transition: transform var(--duration) var(--ease);
      transition-delay: calc( var(--char-index) * .1s );
    }
  }

  &[data-active] {
    .planet-title .char {
      transform: translateY(0%);
      transition-delay: calc(
        (var(--duration)/2) + 
        (var(--char-index) * .1s)
      );   
    }
  }
  
  /* ---------------------------------- */
  
  .planet-description {
    visibility: hidden;
    opacity: 0;
    transform: translateY(1em);
    transition: 
      transform var(--duration) var(--ease),
      opacity var(--duration) linear, 
      visibility 0.01s linear var(--duration);
  }
  
  
  &[data-active] {
    .planet-description {
      opacity: 1;
      transform: translateY(0);
      visibility: visible;
      transition-delay: 
        var(--duration), 
        var(--duration),
        0s;
    }
  }
  
  /* ---------------------------------- */

  .planet-details {
    visibility: hidden;
  }

  &[data-active] {
    .planet-details {
      opacity: 1;
      transform: translateY(0);
      visibility: visible;
      transition-delay: 0s;
    }
  }

  .planet-figure {
    opacity: 0;
    transition: opacity var(--duration) var(--ease);
  }

  &[data-active] {
    .planet-figure {
      opacity: 1;
    }
  }

}

/* ---------------------------------- */

#app { overflow: hidden; }

.planet-nav {
  grid-column: 1;
  grid-row: 2;
  pointer-events: none;
  z-index: 10;
  display: flex;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;

  svg { 
    display: block; 
    width: auto;
    height: auto;
    min-width: 100%;
    max-width: none;
    min-height: 100vh;
    margin-bottom: -50%;
    @media (max-width: 600px) {
      margin-bottom: -55%;
    }
  }

  tspan {
    cursor: pointer;
    fill: #FFF;
    pointer-events: auto;
    opacity: 0;
    transition: opacity var(--duration) linear; 

    &[x] {
      opacity: 0.6;
    }

    &:hover,
    &:focus {
      opacity: 1;
    }
  }

  svg {
    // border: solid 1px red;
    transform-origin: center center;
    --length: 7;
    --range: 160deg;

    transform: rotate( calc( 
      (var(--active,0) / var(--length))
      * (-1 * var(--range))
      + (var(--range) / 2)
    ));

    transition: transform var(--duration) var(--ease);
  }

  tspan { cursor: pointer; }
}

              
            
!

JS

              
                console.clear();

Splitting({ target: '.planet-title h1', by: 'chars' });

const elApp = document.querySelector('#app');

const elPlanets = Array.from(document.querySelectorAll('[data-planet]'))
  .reduce((acc, el) => {
    const planet = el.dataset.planet;
    
    acc[planet] = el;
    
    return acc;
  }, {});

const planetKeys = Object.keys(elPlanets);

function getDetails(planet) {
  // tilt, gravity, hours
  const details = Array.from(elPlanets[planet]
    .querySelectorAll(`[data-detail]`))
    .reduce((acc, el) => {
      acc[el.dataset.detail] = el.innerHTML.trim();
      
      return acc;
    }, { planet });
  
  return details;
}

// ...........

let currentPlanetIndex = 0;
let currentPlanet = getDetails('mercury');

function selectPlanet(planet) {
  const prevPlanet = currentPlanet;
  const elActive = document.querySelector('[data-active]');
  
  delete elActive.dataset.active;
  
  const elPlanet = elPlanets[planet];
  
  elPlanet.dataset.active = true;
  currentPlanet = getDetails(elPlanet.dataset.planet)
  
  console.log(prevPlanet, currentPlanet);
  
  const elHoursDetail = elPlanet.querySelector('[data-detail="hours"]')
  animate.fromTo({
    from: +prevPlanet.hours,
    to: +currentPlanet.hours
  }, value => {
    elHoursDetail.innerHTML = Math.round(value);
  })
  
  const elTiltDetail = elPlanet.querySelector('[data-detail="tilt"]')
  animate.fromTo({
    from: +prevPlanet.tilt,
    to: +currentPlanet.tilt
  }, value => {
    elTiltDetail.innerHTML = (value).toFixed(2);
  })
  
  const elGravityDetail = elPlanet.querySelector('[data-detail="gravity"]')
  
  animate.fromTo({
    from: +prevPlanet.gravity,
    to: +currentPlanet.gravity
  }, value => {
    elGravityDetail.innerHTML = (value).toFixed(1);
  })
}

function selectPlanetByIndex(i) {
  currentPlanetIndex = i;
  elApp.style.setProperty('--active',i);
  selectPlanet(planetKeys[i]);
}

// document.body.addEventListener('click', () => {
//   currentPlanetIndex = (currentPlanetIndex + 1) % planetKeys.length;
  
//   selectPlanet(planetKeys[currentPlanetIndex]);
// });


/* ---------------------------------- */

function animate(duration, fn) {
  const start = performance.now();
  const ticks = Math.ceil(duration / 16.666667);
  let progress = 0; // between 0 and 1, +/-
  
  function tick(now) {
    if (progress >= 1) {
      fn(1);
      return;
    }
    
    const elapsed = now - start;
    progress = elapsed / duration;
    
    // callback
    fn(progress); // number between 0 and 1
    
    requestAnimationFrame(tick); // every 16.6666667 ms
  }
  
  tick(start);
}

function easing(progress) {
  return (1 - Math.cos(progress * Math.PI)) / 2
}

const animationDefaults = {
  duration: 1000,
  easing
}

animate.fromTo = ({
  from,
  to,
  easing,
  duration
}, fn) => {
  easing = easing || animationDefaults.easing;
  duration = duration || animationDefaults.duration;
  
  const delta = +to - +from;
  
  return animate(duration, progress => fn(from + easing(progress) * delta));
}


/* ---------------------------------- */

const svgNS = 'http://www.w3.org/2000/svg';
const elSvgNav = document.querySelector('.planet-nav svg');

const elTspans = [...document.querySelectorAll('tspan')];;
const length = elTspans.length - 1;

elSvgNav.style.setProperty('--length',length);

// Getting the length for distributing the text along the path
const elNavPath = document.querySelector('#navPath');
const elLastTspan =  elTspans[length];
const navPathLength = elNavPath.getTotalLength() - elLastTspan.getComputedTextLength();

elTspans.forEach( (tspan,i) => {
  let percent = i / length;
  
  tspan.setAttribute('x', percent * navPathLength);
  tspan.setAttributeNS(svgNS, 'x', percent * navPathLength);
  
  tspan.addEventListener('click', (e)=>{
    e.preventDefault();
    selectPlanetByIndex(i);
  });
  
});

              
            
!
999px

Console