Skip to content

Instantly share code, notes, and snippets.

@AllThingsSmitty
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AllThingsSmitty/b3ff1ea0735540bb5310 to your computer and use it in GitHub Desktop.
Save AllThingsSmitty/b3ff1ea0735540bb5310 to your computer and use it in GitHub Desktop.
CSS-only coffee app concept with data-driven Sass
<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>
@import url(http://fonts.googleapis.com/css?family=Lato:300,400,700);
@import url(http://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);
&: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;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment