<main>
    <div class="device">
        <header>
            <h1><strong>CSS</strong>Presso</h1>
        </header>
        <section>
            <form>            
                <input type="radio" name="coffeeType" id="espresso">
                <input type="radio" name="coffeeType" id="doppio">
                <input type="radio" name="coffeeType" id="macchiatto">
                <input type="radio" name="coffeeType" id="cortado">
                <input type="radio" name="coffeeType" id="cappuccino">
                <input type="radio" name="coffeeType" id="americano">
                <input type="radio" name="coffeeType" id="mocha">
                <input type="radio" name="coffeeType" id="latte">
                <input type="radio" name="coffeeType" id="breve">
                <input type="radio" name="coffeeType" id="mochabreve">
                <input type="radio" name="coffeeType" id="flatwhite">
                <input type="radio" name="coffeeType" id="bombon">
                <div class="coffee-title">                
                    <nav class="coffee-labels">
                        <label for="doppio">
                            <span>Doppio</span>
                            <p>Doppio in espresso is a double shot, extracted using a double coffee filter in the portafilter.</p>
                        </label>
                        <label for="macchiatto">
                            <span>Macchiatto</span>
                            <p>A caffè macchiato, sometimes called espresso macchiato, is an espresso coffee drink with a small amount of milk added, today usually foamed milk.</p>
                        </label>
                        <label for="cortado">
                            <span>Cortado</span>
                            <p>A cortado (from the Spanish verb "cortar" - to cut) is an espresso cut with a small amount of warm milk.</p>
                        </label>
                        <label for="cappuccino">
                            <span>Cappuccino</span>
                            <p>A cappuccino (from the Capuchin friars) is an Italian coffee drink which is traditionally prepared with espresso, hot milk and steamed-milk foam.</p>
                        </label>
                        <label for="americano">
                            <span>Americano</span>
                            <p>A caffè americano is a style of coffee prepared by adding hot water to espresso, giving it a similar strength to, but different flavor from, regular drip coffee.</p>
                        </label>
                        <label for="mocha">
                            <span>Mocha</span>
                            <p>A caffè mocha is based on espresso and hot milk, but with added chocolate, typically in the form of sweet cocoa powder, although many varieties use chocolate syrup.</p>
                        </label>
                        <label for="latte">
                            <span>Latte</span>
                            <p>A caffè latte is a coffee drink made with espresso and steamed milk. The term is Italian for "milk coffee."</p>
                        </label>
                        <label for="breve">
                            <span>Breve</span>
                            <p>A caffè breve is an American variation of a latte: a milk-based espresso drink using steamed half-and-half mixture of milk and cream instead of milk.</p>
                        </label>
                        <label for="mochabreve">
                            <span>Mocha Breve</span>
                            <p>A mocha breve is similar to a caffè breve with an added ounce of cocoa powder or chocolate syrup.</p>
                        </label>
                        <label for="flatwhite">
                            <span>Flat White</span>
                            <p>A flat white is prepared by pouring microfoam (steamed milk with small, fine bubbles and a glossy or velvety consistency) over a single or double shot of espresso.</p>
                        </label>
                        <label for="bombon">
                            <span>Café Bombón</span>
                            <p>A café bombón is a popular Spanish coffee drink made with espresso served with sweetened condensed milk in a 1:1 ratio.</p>
                        </label>
                    </nav>
                </div>
                <a href="#" class="coffee-info" tabindex="1">
                    <div class="coffee-recipe">
                        <div class="recipe-foam">milk foam</div>
                        <div class="recipe-steam">steamed milk</div>
                        <div class="recipe-water">hot water</div>
                        <div class="recipe-half">half &amp; half</div>
                        <div class="recipe-chocolate">chocolate</div>
                        <div class="recipe-crema"></div>
                        <div class="recipe-espresso">espresso</div>
                        <div class="recipe-condensed">condensed milk</div>
                    </div>
                    <div class="coffee-cup">
                        <div class="coffee-steam">
                            <div class="steam"></div>
                            <div class="steam large"></div>
                            <div class="steam"></div>
                        </div>
                        <div class="coffee-ingredients">                      
                            <div class="ingredient-foam"></div>
                            <div class="ingredient-steam"></div>
                            <div class="ingredient-water"></div>
                            <div class="ingredient-half"></div>
                            <div class="ingredient-chocolate"></div>
                            <div class="ingredient-crema"></div>
                            <div class="ingredient-espresso"></div>
                            <div class="ingredient-condensed"></div>
                        </div>
                    </div>
                </a>
                <div class="info-overlay"></div>
                <div class="coffee-controls">
                    
                    <button type="reset">
                        Espresso Menu
                    </button>
                </div>
            </form>
        </section>
    </div>
</main>
<aside>
  <div class="meta">    
    <h1>CSS-only Coffee App Concept</h1>
    <p>
      Original design by David Khourshid.<br>
      Slightly inspired by Starbucks&reg;.
    </p>
    <p>
      Select an espresso drink and click/tap the cup to see the effect.<br>
      Works best in Chrome, Safari, and Firefox.
    </p>
    <p>Coffee details from <a href="http://wikipedia.org">Wikipedia</a>.</p>
  </div>
</aside>
@import "compass/css3";

@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700);
@import url(https://fonts.googleapis.com/css?family=Noto+Serif:400,400italic);

$device-width: 264px * 1.5;
$device-height: 544px * 1.5;

$header-height: 3rem;

$color-bg: #515866;
$color-app: #3b3b3b;
$color-header: #e34a36;
$color-device: #dcdfe6;
$color-device-border: white;
$color-device-part: #a1a5b3;

$color-text-dark: #333;
$color-text-light: white;

$color-cup: $color-text-light;
$color-accent: #e34a36;

$animation-easing: cubic-bezier(0.645, 0.045, 0.355, 1);

$coffee-types: (
  'doppio': ('espresso': 2, 'crema': 0.3),
  'macchiatto': ('espresso': 2, 'crema': 0.3, 'foam': 0.5),
  'cortado': ('espresso': 2, 'crema': 0.3, 'foam': 1),
  'cappuccino': ('espresso': 2, 'crema': 0.3, 'foam': 2, 'steam': 2),
  'americano': ('espresso': 2, 'crema': 0.3, 'water': 3),
  'mocha': ('espresso': 2, 'crema': 0.3, 'chocolate': 2, 'steam': 1),
  'latte': ('espresso': 2, 'crema': 0.3, 'steam': 3, 'foam': 0.1),
  'breve': ('espresso': 2, 'crema': 0.3, 'half': 3),
  'mochabreve': ('espresso': 2, 'crema': 0.3, 'half': 2, 'chocolate': 2),
  'flatwhite': ('espresso': 2, 'crema': 0.3, 'steam': 4),
  'bombon': ('condensed': 2, 'espresso': 2, 'crema': 0.3),
);

$ingredients: (
  'foam': ('color': #fdfdfd),
  'steam': ('color': #f0eada),
  'half': ('color': #f0eada),
  'water': ('color': #c7dfdf),
  'espresso': ('color': #4d211d),
  'chocolate': ('color': #71471c),
  'crema': ('color': #ac6d44),
  'condensed': ('color': #f0eada)
);

$coffee-type-height: 3rem;
$coffee-cup-height: 200px;
$coffee-cup-width: $coffee-cup-height;
$coffee-info-height: $coffee-cup-height * 2;
$rule-width: $coffee-cup-height / 2;
$recipe-cup-offset: 0.4 * $device-width;

@mixin clearfix {
  &:before, &:after {
      content: " ";
      display: table;
  }
  &:after { clear: both; }
}

.coffee-title {
  height: 3rem;
  overflow: visible;
  z-index: 20;
}

.coffee-info {
  outline: none;
  padding: 1rem;
  transition: transform 0.5s $animation-easing;

  &, + .info-overlay {
    display: block;
    height: calc(#{$coffee-cup-height} + 2rem);
    width: 100%;
    position: absolute;
    top: 35%;
  }

  + .info-overlay {
    pointer-events: none;
  }

  &:focus {
    transform: translateX($recipe-cup-offset);

    .coffee-recipe {
      opacity: 1;
      transform: translateX(-$recipe-cup-offset);
    }

    + .info-overlay {
      pointer-events: auto;
    }
  }
}

.coffee-cup {
  width: $coffee-cup-height;
  height: $coffee-cup-height;
  border-style: solid;
  border-color: $color-cup;
  border-width: 0.5rem;
  // border-top-width: 0;
  margin: auto;
  animation: cup-inactive 0.5s $animation-easing both;
  transition: opacity 0.5s $animation-easing;
  opacity: 0;

  &:after {
    content: '';
    display: block;
    position: absolute;
    height: $coffee-cup-height / 3;
    width: $coffee-cup-height / 4;
    border-width: 0.6rem;
    border-color: white;
    border-style: solid;
    left: 100%;
    border-radius: 0 50% 50% 0;
    top: $coffee-cup-height / 5;
    transform: skewY(-15deg);
    border-left-width: 0;
  }

  border-bottom-left-radius: $coffee-cup-width * .375;
  border-bottom-right-radius: $coffee-cup-width * .375;
  border-top-left-radius: 0.5rem;
  border-top-right-radius: 0.5rem;
}

.coffee-ingredients {
  position: absolute;
  left: 0;
  height: auto;
  width: calc(100% - 1rem);
  margin: 0.5rem;
  bottom: 0;
  overflow: hidden;

  transition-duration: 1s;
  transition-delay: 0.5s;
  transition-timing-function: $animation-easing;
  transition-property: opacity, transform;
  transform: scaleY(0);
  opacity: 0;
  transform-origin: bottom;

  border-bottom-left-radius: calc(#{$coffee-cup-width} * .375 - 1rem);
  border-bottom-right-radius: calc(#{$coffee-cup-width} * .375 - 1rem);

  border-left: 1px solid rgba($color-cup, 0.5);
  border-right: 1px solid rgba($color-cup, 0.5);
  background-color: rgba($color-cup, 0.5);
}

.coffee-recipe {
  position: absolute;
  left: 0;
  bottom: 2rem;
  height: auto;
  width: 100%;
  color: white;
  padding: 0 calc(#{$recipe-cup-offset} - 1rem) 0 1rem;
  opacity: 0;
  transition-duration: 0.5s;
  transition-property: transform, opacity;
  transition-timing-function: $animation-easing;
  transform: translateX($recipe-cup-offset);
}

[class^="recipe-"] {
  white-space: nowrap;
  overflow-x: hidden;
  opacity: 0;
  top: 0.5rem;
  transition-property: height;
  transition-delay: 1s;

  &:not(.recipe-crema) { min-height: 2.5rem; }
  
  &.recipe-crema { overflow: hidden; }

  &:before {
    position: absolute;
    top: 1rem;
    font-weight: 700;
    font-size: small;
    font-variant: small-caps;
    line-height: 1.4;
  }

  &:after {
    content: '';
    display: inline-block;
    border-bottom: 1px dotted $color-text-light;
    width: 100%;
    transform: scaleX(2);
    transform-origin: left bottom;
    margin: 0 0.5rem;
  }
}

[class^="ingredient-"] {
  width: 100%;
  margin-bottom: 1px;
  height: 0;
  transition-property: height;
  transition-delay: 1s;

  &:after {
    margin-top: 1rem;
  }
}

@each $ingredient-key, $ingredient-info in $ingredients {
  $ingredient-color: map-get($ingredient-info, 'color');

  .ingredient-#{$ingredient-key} {
    background-color: $ingredient-color;
    color: $ingredient-color;
  }
}

@for $ingredient-index from 1 through length($ingredients) {
  [class^="ingredient-"]:nth-child(#{$ingredient-index}n) {
    z-index: (length($ingredients) - $ingredient-index + 1) * 10;
  }
}

.coffee-labels {
  animation: coffee-labels-active 0.5s 0.5s $animation-easing both;

  label {
    display: block;
    height: $coffee-type-height;
    line-height: $coffee-type-height;
    text-align: center;
    text-transform: uppercase;
    font-weight: 700;
    padding: 0 1rem;
    animation: coffee-type-active 1s $animation-easing both;
    transition-property: opacity;
    transition-duration: 0.5s;
    transition-timing-function: $animation-easing;
    transition-delay: 0.5s;
    opacity: 1;
    pointer-events: auto;

    p {
      font-family: 'Noto Serif', sans-serif;
      font-style: italic;
      transition: all 0.5s $animation-easing;
      transition-property: transform, opacity;
      transition-duration: 0.5s;
      transition-timing-function: $animation-easing;
      transition-delay: 0;
      line-height: 1.4;
      font-size: 1rem;
      font-weight: normal;
      color: $color-text-light;
      opacity: 0;
      text-transform: none;
      transform: translateY(50%);
    }

    span {
      display: inline-block;
      font-size: 2rem;
      color: $color-text-light;

      &:after {
        content: '';
        position: absolute;
        display: block;
        top: 100%;
        left: calc(50% - #{$rule-width / 2});
        width: $rule-width;
        height: 1px;
        background: $color-accent;
        opacity: 0;
      }
    }
  }
}

[name="coffeeType"]:checked {
  ~ .coffee-info {
    [class^="ingredient-"], [class^="recipe-"] {
      transition-delay: 0;
      display: none;
    }

    .coffee-cup {
      opacity: 1;
    }
  }

  ~ .coffee-title label {
    animation: coffee-type-inactive 1s $animation-easing both;
    transition-delay: 0s;
    opacity: 0;
    pointer-events: none;
  }

  ~ .coffee-controls {
    transition-delay: 0.5s;
    transform: translateY(0);
    opacity: 1;

    [type="reset"] {
      opacity: 1;
    }
  }
}

@each $coffee-type, $coffee-recipe in $coffee-types {
  ##{$coffee-type}:checked {
    ~ .coffee-title label {
      &[for="#{$coffee-type}"] {
        animation: none;
        opacity: 1;

        p {
          opacity: 1;
          transform: translateY(0);
          transition-delay: 0.5s;
        }

        span:after {
          animation: coffee-rule-active 1s 0.5s $animation-easing both;
        }
      }
    }

    ~ .coffee-info {
      .coffee-cup {
        animation: cup-active 2s $animation-easing;
      }

      .coffee-ingredients {
        animation: ingredients-active 2s $animation-easing;
        transform: scaleY(1);
        opacity: 1;
      }

      @each $ingredient, $amount in $coffee-recipe {
        .ingredient-#{$ingredient}, .recipe-#{$ingredient} {
          display: block;
          height: calc(1/6.3 * (#{$coffee-cup-height} - 2rem) * #{$amount});
        }

        .recipe-#{$ingredient} {
          transition-delay: 0;
          transition-duration: 0.5s;
          transition-timing-function: $animation-easing;
          transition-property: opacity;
          opacity: 1;
          &:before { content: '#{$amount * 30}ml'; }
        }
      }
    }
  }
}

.coffee-steam {
  position: absolute;
  height: 10rem;
  width: 100%;
  bottom: 100%;
  left: 0;
}
.steam {
  width: 1rem;
  height: 1rem;
  color: rgba($color-text-light, 0.3);
  position: absolute;
  bottom: 0;
  animation: steam-active 3s ease-out infinite;
  filter: blur(0.5rem);

  @for $index from 1 through 3 {
    &:nth-child(#{$index}n) {
      left: calc(50% - #{($index - 2) * 1.5rem});
    }
  }

  &:before { content: "~"; transform: rotate(90deg) scaleX(15) scaleY(10); display: block; }

  &.large {
    animation-delay: 0.5s;

    &:before { transform: rotate(90deg) scaleX(20) scaleY(15); }
  }
}

form {
  height: 100%;
  width: 100%;
}

@keyframes steam-active {
  0% {
    transform: translateY(1rem);
    opacity: 0;
  }
  16% {
    opacity: 1;
  }
  100% {
    transform: translateY(-5rem);
    opacity: 0;
  }
}

@keyframes coffee-type-inactive {
  0% {
    height: $coffee-type-height;
  }
  50% {
    height: $coffee-type-height;
  }
  100% {
    height: 0;
  }
}

@keyframes coffee-type-active {
  0% {
    height: 0;
  }
  50% {
    height: $coffee-type-height;
  }
  100% {
    height: $coffee-type-height;
  }
}

@keyframes coffee-rule-active {
  50% {
    opacity: 0;
    transform: scaleX(0);
  }
  100% {
    opacity: 1;
    transform: scaleX(1);
  }
}

@keyframes cup-active {
  0% {
    transform: translateX(-2 * $coffee-cup-width);
  }
  100% {
    transform: translateX(0);
  }
}

@keyframes cup-inactive {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(2 * $coffee-cup-width);
  }
}

@keyframes coffee-labels-active {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

.coffee-controls {
  transition: all 0.5s 0 $animation-easing;
  display: block;
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: auto;
  padding: 2rem;
  text-align: center;
  font-size: 1rem;
  transform: translateY(100%);
  opacity: 0;
}

[type="reset"] {
  transition: all 0.5s $animation-easing;
  display: block;
  position: relative;
  bottom: 0;
  margin-left: auto;
  margin-right: auto;
  appearance: none;
  -moz-appearance: none;
  background: transparent;
  color: $color-text-light;
  border: 1px solid currentColor;
  padding: 1rem 2rem;
  font-size: 0.8rem;
  text-transform: uppercase;
  font-weight: 700;
  opacity: 0;

  &:hover {
    color: $color-app;
    background: $color-text-light;
  }
}

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

input[type="radio"] {
  height: 0;
  visibility: hidden;
}

html, body {
  font-family: Lato, sans-serif;
  font-weight: 300;
  line-height: 1;
  background-color: $color-bg;
  width: 100%;
  height: 100%;
  margin: 0;
}

aside, main {
  width: 50%;
  height: $device-height;
  float: left;
  padding: 0 2rem;
  margin: 2rem 0;
}

.meta {
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.2rem;
  p, a { color: rgba(255, 255, 255, 0.5); }
  h1 {
    font-size: 3rem;
    line-height: 1.2;
    font-weight: 300;
    color: $color-text-light;
  }
  p { line-height: 1.4; }
  
  a:hover {
    color: rgba(255, 255, 255, 0.7);
  }
}

.device {
  position: absolute;
  right: 2rem;
  height: $device-height;
  width: $device-width;
  padding: 90px 10px;
  border: 5px solid $color-device-border;
  border-radius: 60px;
  background-color: $color-device;
  box-shadow: 0 0 50px 10px rgba(0,0,0,0.1);
  
  &, * { user-select: none; }
  
  &:before, &:after {
    content: '';
    position: absolute;
    z-index: 2;
  }
  
  &:before {
    width: 20%;
    height: 10px;
    top: 40px;
    left: 40%;
    border-radius: 10px;
    background-color: $color-device-part;
  }
  
  &:after {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    border: solid 5px lighten($color-device-part, 10%);
    left: calc(50% - 25px);
    bottom: 15px;
  }
  
  header {
    height: $header-height;
    background-color: $color-header;

    h1 {
      margin: 0;
      line-height: $header-height;
      text-align: center;
      font-size: 1.3rem;
      font-weight: 300;
      color: $color-text-light;
      letter-spacing: 1px;
      text-transform: uppercase;
    }
  }
  
  section {
    height: calc(100% - #{$header-height});
    width: 100%;
    overflow: hidden;
    background-color: $color-app;
  }
}
View Compiled
// Oops, forgot the JavaScript again.

// The point of these concepts is to push the limits of CSS and realize what its capabilities and limitations are before implementing JavaScript for stateful interaction.
// Then, we can truly have separation of concerns without being tempted to use JavaScript for everything.

// Also, click event handlers and state management *should* always be done in JavaScript. =)

// Twitter: @davidkpiano
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js