#cart
  %h2 Your Shopping Cart
  %ul.cart-items
  .total
    .subtotalTotal
      Subtotal
      %span $0.00
    .taxes
      Tax
      %span $0.00
    .shipping
      Shipping
      %span $0.00
    .finalTotal
      Total
      %span $0.00
    %a.checkout
      Check Out
    %p.error 
        
.wrap#wrap
  %header
    %a.logo{:href=>"#"}
      Octocat <span class="brandico-github"></span> Outfitters
    %a.cart-link{:href=>"#menu"}
      %span.cart-text.fontawesome-shopping-cart
        %span Cart
      %span.returnToShop &larr; Back        
      %span.cart-quantity.empty 0

        
  %section.shop
  
  %footer
    %p Crafted for the Pattern Rodeo (rodeo-007). Images belong to Github.

    
// Product Templates for Shop & Cart

%script#productTemplate{ type: 'text/template' }
  <div class="product">
  <h1></h1>
  <p></p>
  <div class="button">
  <div class="price"></div>
  <a class="addtocart">
  <div class="add">Add to Cart</div>
  <div class="added">Added!</div>
  </a>
  </div>
  </div>
  
%script#cartItem{ type: 'text/template' }
  <li><div class="cart-product">
  <input class="quantity" value="1">
  </div><div class="cart-description">
  <h3></h3>
  <span class="subtotal"></span>
  </div></li>
View Compiled
@import compass

@import url(https://fonts.googleapis.com/css?family=Lato:400,700)

/* Iconfonts
   ============================ */

@import "http://weloveiconfonts.com/api/?family=fontawesome"
@import "http://weloveiconfonts.com/api/?family=brandico"

[class*="fontawesome-"]:before
  font-family: 'FontAwesome', sans-serif
[class*="brandico-"]:before
  font-family: 'brandico', sans-serif


/* Variables
   ============================ */

$white: #fff
$black: #111
$gray: lighten($black, 25%)

$lightblue: #9cdaf0
$blue: #7cbae6 
$darkblue: darken($blue, 25%)


/* Body
   ============================ */

body
  position: relative
  font-family: 'Lato', sans-serif
  font-weight: 300
  font-size: 1em
  color: darken($white, 20%)
  
/* Header
   ============================ */

header
  width: 100%
  border-bottom: 1px solid $blue
  background: lighten($black, 5%)

  /* Logo */  
  
  a.logo
    margin-left: 1em
    text-transform: uppercase
    text-decoration: none
    color: $blue
    line-height: 4em

    span
      margin: 0 3px 0 3px
      color: $lightblue
      
  /* Cart link */  
  
  a.cart-link
    float: right
    padding-left: 1em
    margin-right: 1em
    border-left: 1px dotted $gray 
    line-height: 4em
    text-decoration: none
    color: $white
    transition: color 150ms ease-out
    
    &:hover
      color: $blue
      
    &:active, .active
      color: $lightblue

  span.cart-text:before
    margin: 5px
    
    > span
      display: block
      
  /* Quantity Notification */  
  
  span.cart-quantity
    position: relative
    top: -2px
    left: 5px
    display: inline-block
    width: 22px
    height: 22px
    border-radius: 50%
    background: #f63
    font-size: .6em
    line-height: 20px
    text-align: center
    color: $white

  /* Quantity Notification hidden when no items*/  
  
  .cart-quantity.empty
    display: none
    
  /* Back button hidden by default */    
  
  .returnToShop
    display: none  

  /* State changes when cart is active */  
  
  a.cart-link.active
    border: 0
    
    /* Cart link gets hidden*/  
    
    span.cart-text
      display: none
      
    span.cart-quantity
      display: none      
      
    /* Back button is displayed */ 
    
    span.returnToShop
      position: absolute
      right: -75px
      display: block
      padding: 0 10px
      background: lighten($black, 5%)
      border-right: 1px dotted lighten($black, 20%)       
      
      
/* Sliding Cart
   ============================ */

.wrap 
  position: relative
  right: 0
  box-shadow: 10px -10px 20px -10px rgba(0,0,0,.8)
  transition: all 200ms ease-out

.wrap.active 
  right: 18em

#cart
  clear: both
  overflow: hidden

.js #cart 
  position: absolute
  top: 0
  right: 0
  width: 18em
  height: 100%

  
/* Footer
   ============================ */

footer
  clear:both
  background: $black
  font-size: .85em
  color: #fff

  p
    margin: 0 1em
    line-height: 3em
    color: $gray

    
/* Shop & Product Items
   ============================ */

section.shop

.product
  position: relative
  z-index: 1
  float: left
  width: 50%
  height: 300px
  overflow: hidden
  background-position: center center
  background-size: cover
  
  /* Hide product descriptions */
  
  > *
    margin: 20px 25px
    opacity: 0
    transition: opacity 200ms ease-out  
  
  /* On hover, adds overlay on top of product image */
  
  &:hover:before
    position: absolute
    z-index: -1
    top: 0
    display: inline-block
    width: 100%
    height: 300px
    background: rgba(0,0,0,.8)
    content: ''

  /* On hover, fade in product descriptions */
  
  > *
    margin: 20px 25px
    opacity: 0
    transition: opacity 200ms ease-out    
  &:hover > *, .active
    opacity: 1

  /* Styles for each shop item */  
  h1
    padding: 15px 0
    border-bottom: 1px dotted darken($white, 50%)
    font-weight: normal
    font-size: 1.6em
    color: $blue

  p
    margin-bottom: 30px
    line-height: 1.5em

  /* "Add to Cart" Buttom with 3D transforms and keyframe animation (Works best in Chrome) */
  
  .button
    position: relative
    display: block
    width: 150px
    height: 50px
    text-align: center
    perspective: 1000px

    .price
      position: absolute
      z-index: 1
      top: 2px
      display: block
      width: 50px
      height: 46px
      border-right: 1px solid $lightblue
      border-radius: 2px 0 0 2px
      background: $white
      line-height: 45px
      color: $gray
      transform: rotateY(0deg) translateZ(25px)

    /* Button magic */    
    
    .addtocart
      position: absolute
      left: 48px
      width: 100%
      height: 100%
      transform-style: preserve-3d
      transform: translateZ( -100px )
      transition: transform 300ms
      cursor: pointer

      > div
        position: absolute
        display: block
        width: 150px
        height: 50px
        border-radius: 0 2px 2px 0 
        line-height: 50px

      > .add
        background: $white
        color: $blue
        transform: rotateY(0deg) translateZ(25px)
        transition: background 150ms ease-out

        &:hover
          background: $blue    
          color: $white        

      > .added
        background: #f63
        color: $white
        transform: rotateX(90deg) translateZ(25px)

      &.active
        animation-name: rotate
        animation-duration: 1s


/* Cart & Cart Items
   ============================ */

#cart
  background: #222

#cart>h2
  height: 64px
  padding-right: 1em
  border-left: 1px dotted $gray 
  border-bottom: 1px solid $blue
  margin: 0
  background: #2d2d2d
  font-weight: normal
  font-size: 1.2em
  text-align: right
  line-height: 64px

/* Styles for each cart item */

.cart-items
  padding: 0  
  
.cart-items > li

  margin: 30px 20px 30px
  border: 1px solid #333  
  background: #202020
  list-style: none
  
.cart-product
  position: relative
  display: inline-block
  height: 75px
  width: 75px
  background-image: url('https://cdn.shopify.com/s/files/1/0051/4802/products/MG_1785_1024x1024.jpg')
  background-size: cover
  vertical-align: top

  input.quantity
    width: 75px
    height: 75px
    padding: 0
    border: 0
    border-right: 1px solid #333
    background: rgba(0,0,0,.5)
    font-size: 2.5em
    line-height: 75px
    text-align: center
    color: $white

.cart-description
  display: inline-block
  height: 75px
  width: 160px
  margin-left: 10px
  text-align: right
  vertical-align: top  

  h3
    margin: 8px
    font-size: 1em
    color: $blue

  .subtotal
    position: relative
    display: inline-block
    margin: 8px    
    font-size: .8em

/* Styling for Total Costs */      

.total
  margin-top: 50px

.total > *
  display: block
  padding-bottom: 10px
  margin: 0 20px 10px 20px
  font-size: .8em
  text-align: left

.total span
  float: right
  text-align: right

.subtotalTotal
  border-bottom: 1px dotted $gray

.shipping
  border-bottom: 1px dotted $gray   

.finalTotal
  font-size: 1em
  color: $blue

a.checkout
  height: 35px
  padding: 0
  margin-top: 30px
  border-radius: 3px
  background: $darkblue
  font-size: 1em
  text-align: center
  text-transform: uppercase
  line-height: 35px
  transition: background 150ms ease-out
  cursor: pointer
  
  &:hover
    background: darken($blue, 15%)
  &.active
    animation-name: shake
    animation-duration: 800ms  
.error
  display: none
  text-align: center
.error:after
  display: block
  font-size: .9em
  text-transform: none
  content: "Sorry, the Octocat is busy!"
    
  
/* Media Queries
   ============================ */

@media (max-width: 720px)
  .product
    width: 100%

@media (max-width: 420px)
  
  /* Hide text in the cart link to save room */
  .cart-text>span
    display: none
    
    
/* Keyframe Animations
   ============================ */
        
@keyframes rotate
  35%
    transform: translateZ(-100px) rotateX(-90deg)
  72%
    transform: translateZ(-100px) rotateX(-90deg)  
  100%
    transform: translateZ(-100px)

@keyframes shake
  0%, 100%
    transform: translateX(0)
  10%, 30%, 50%, 70%, 90%
    transform: translateX(-5px)
  20%, 40%, 60%, 80%
    transform: translateX(5px)    
View Compiled
$(document).ready(function() {

  // Product data to be used in shop and in cart
  var products = {
    'Octocat Mug' : ['Octocat Mug', "The mug you've been dreaming about. One sip from this ceramic 16oz fluid delivery system and you'll never go back to red cups.", 14, 'https://cdn.shopify.com/s/files/1/0051/4802/products/white-mug-1_1024x1024.jpg', 1],
    'Leather Coasters' : ['Leather Coasters', "These coasters roll all of the greatest qualities into one: class, leather, and octocats. They also happen to protect surfaces from cold drinks.", 18, 'https://cdn.shopify.com/s/files/1/0051/4802/products/MG_1934_1024x1024.jpg', 2],  
    'Octopint (Set of 2)' : ['Octopint (Set of 2)', "Set of two heavyweight 16 oz. Octopint glasses for your favorite malty beverage.", 16, 'https://cdn.shopify.com/s/files/1/0051/4802/products/pint_1024x1024.jpg', 3],
    'Blacktocat 2.0 Tee' : ['Blacktocat 2.0 Tee', "Check it. Blacktocat is back with a whole new direction. He's exited stealth mode and is ready for primetime, now with a stylish logo.", 25, 'https://cdn.shopify.com/s/files/1/0051/4802/products/blacktocat-3_1024x1024.jpg', 4],
    'Die Cut Stickers' : ['Die Cut Stickers', "Need a huge Octocat sticker for your laptop, fridge, snowboard, or ceiling fan? Look no further!", 2, 'https://cdn.shopify.com/s/files/1/0051/4802/products/sticker-large_1024x1024.jpg', 5],
    'Pixelcat Shirt' : ['Pixelcat Shirt', "Pixels are your friends. Show your bits in this super-comfy blue American Apparel tri-blend shirt with a pixelated version of your favorite aquatic feline", 25, 'https://cdn.shopify.com/s/files/1/0051/4802/products/8bit-1_1024x1024.jpg?145', 6]
  };  
  
  // Populates shop with items based on template and data in var products
  
  var $shop = $('.shop');
  var $cart = $('.cart-items');
  
  for(var item in products) {
    var itemName = products[item][0],
        itemDescription = products[item][1],
        itemPrice = products[item][2],
        itemImg = products[item][3],
        itemId = products[item][4],
        $template = $($('#productTemplate').html());
    
    $template.find('h1').text(itemName);
    $template.find('p').text(itemDescription);
    $template.find('.price').text('$' + itemPrice);
    $template.css('background-image', 'url(' + itemImg + ')');
    
    $template.data('id', itemId);
    $template.data('name', itemName);
    $template.data('price', itemPrice);
    $template.data('image', itemImg);
    
    $shop.append($template);
  }
  
  // Checks quantity of a cart item on input blur and updates total
  // If quantity is zero, item is removed
  
  $('body').on('blur', '.cart-items input', function() {
    var $this = $(this),
        $item = $this.parents('li');
    if (+$this.val() === 0) {
      $item.remove();
    } else {
      calculateSubtotal($item);
    }
    updateCartQuantity();
    calculateAndUpdate();
  });
  
  // Add item from the shop to the cart
  // If item is already in the cart, +1 to quantity
  // If not, creates the cart item based on template
  
  $('body').on('click', '.product .add', function() {
    var items = $cart.children(),
        $item = $(this).parents('.product'),
        $template = $($('#cartItem').html()),
        $matched = null,
        quantity = 0;
    
    $matched = items.filter(function(index) {
      var $this = $(this);
      return $this.data('id') === $item.data('id');
    });
   
    if ($matched.length) {
      quantity = +$matched.find('.quantity').val() + 1;
      $matched.find('.quantity').val(quantity);
      calculateSubtotal($matched);
    } else {
      $template.find('.cart-product').css('background-image', 'url(' + $item.data('image') + ')');
      $template.find('h3').text($item.data('name'));
      $template.find('.subtotal').text('$' + $item.data('price'));
    
      $template.data('id', $item.data('id'));
      $template.data('price', $item.data('price'));
      $template.data('subtotal', $item.data('price'));
      
      $cart.append($template);
    }
    
    updateCartQuantity();
    calculateAndUpdate();
  });

  // Calculates subtotal for an item
  
  function calculateSubtotal($item) {
    var quantity = $item.find('.quantity').val(),
        price = $item.data('price'),
        subtotal = quantity * price;
    $item.find('.subtotal').text('$' + subtotal);
    $item.data('subtotal', subtotal);
  } 
    
  // Clicking on the cart link opens up the shopping cart
  
  var $cartlink = $('.cart-link'), $wrap = $('#wrap');
  
  $cartlink.on('click', function() {
    $cartlink.toggleClass('active');
    $wrap.toggleClass('active');
    return false;    
	});
  
  // Clicking outside the cart closes the cart, unless target is the "Add to Cart" button 
 
  $wrap.on('click', function(e){
    if (!$(e.target).is('.add')) {
      $wrap.removeClass('active');
      $cartlink.removeClass('active');
    }
  });
 
  // Calculates and updates totals, taxes, shipping
  
  function calculateAndUpdate() {
    var subtotal = 0,
        items = $cart.children(),
        // shipping not applied if there are no items
        shipping = items.length > 0 ? 5 : 0,
        tax = 0;
    items.each(function(index, item) {
      var $item = $(item),
          price = $item.data('subtotal');
      subtotal += price;
    });
    $('.subtotalTotal span').text(formatDollar(subtotal));
    tax = subtotal * .05;
    $('.taxes span').text(formatDollar(tax));
    $('.shipping span').text(formatDollar(shipping));
    $('.finalTotal span').text(formatDollar(subtotal + tax + shipping));
  }

  //  Update the total quantity of items in notification, hides if zero
  
  function updateCartQuantity() {
    var quantities = 0,
        $cartQuantity = $('span.cart-quantity'),
        items = $cart.children();
    items.each(function(index, item) {
      var $item = $(item),
          quantity = +$item.find('.quantity').val();
      quantities += quantity;
    });
    if(quantities > 0){
      $cartQuantity.removeClass('empty');
    } else {
      $cartQuantity.addClass('empty');
    }
    $cartQuantity.text(quantities);
  }
  
 
  //  Formats number into dollar format
     
  function formatDollar(amount) {
    return '$' + parseFloat(Math.round(amount * 100) / 100).toFixed(2);
  }
  
  // Restrict the quantity input field to numbers only
     
  $('body').on('keypress', '.cart-items input', function (ev) {
      var keyCode = window.event ? ev.keyCode : ev.which;
      if (keyCode < 48 || keyCode > 57) {
        if (keyCode != 0 && keyCode != 8 && keyCode != 13 && !ev.ctrlKey) {
          ev.preventDefault();
        }
      }
    });
  
  // Trigger animation on Add to Cart button click
  
  $('.addtocart').on('click', function () {
    $(this).addClass('active');
    setTimeout(function () {
      $('.addtocart').removeClass('active');    
    }, 1000);
  });
  
  // Trigger error animation on Checkout button
  
  $('.checkout').on('click', function () {
    $(this).addClass('active');
    $('.error').css('display', 'block');
    setTimeout(function () {
      $('.checkout').removeClass('active');    
      $('.error').css('display', 'none');      
    }, 1000);
  });    
  
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js