<h1>Shopping Cart</h1>
<div class="shopping-cart">
<div class="column-labels">
<label class="product-image">Image</label>
<label class="product-details">Product</label>
<label class="product-price">Price</label>
<label class="product-quantity">Quantity</label>
<label class="product-removal">Remove</label>
<label class="product-line-price">Total</label>
</div>
<div class="product">
<div class="product-image">
<img src="https://s.cdpn.io/3/dingo-dog-bones.jpg">
</div>
<div class="product-details">
<div class="product-title">Dingo Dog Bones</div>
<p class="product-description">The best dog bones of all time. Holy crap. Your dog will be begging for these things! I got curious once and ate one myself. I'm a fan.</p>
</div>
<div class="product-price">12.99</div>
<div class="product-quantity">
<input type="number" value="2" min="1">
</div>
<div class="product-removal">
<button class="remove-product">
Remove
</button>
</div>
<div class="product-line-price">25.98</div>
</div>
<div class="product">
<div class="product-image">
<img src="https://s.cdpn.io/3/large-NutroNaturalChoiceAdultLambMealandRiceDryDogFood.png">
</div>
<div class="product-details">
<div class="product-title">Nutro™ Adult Lamb and Rice Dog Food</div>
<p class="product-description">Who doesn't like lamb and rice? We've all hit the halal cart at 3am while quasi-blackout after a night of binge drinking in Manhattan. Now it's your dog's turn!</p>
</div>
<div class="product-price">45.99</div>
<div class="product-quantity">
<input type="number" value="1" min="1">
</div>
<div class="product-removal">
<button class="remove-product">
Remove
</button>
</div>
<div class="product-line-price">45.99</div>
</div>
<div class="totals">
<div class="totals-item">
<label>Subtotal</label>
<div class="totals-value" id="cart-subtotal">71.97</div>
</div>
<div class="totals-item">
<label>Tax (5%)</label>
<div class="totals-value" id="cart-tax">3.60</div>
</div>
<div class="totals-item">
<label>Shipping</label>
<div class="totals-value" id="cart-shipping">15.00</div>
</div>
<div class="totals-item totals-item-total">
<label>Grand Total</label>
<div class="totals-value" id="cart-total">90.57</div>
</div>
</div>
<button class="checkout">Checkout</button>
</div>
@import "compass/css3";
/*
I wanted to go with a mobile first approach, but it actually lead to more verbose CSS in this case, so I've gone web first. Can't always force things...
Side note: I know that this style of nesting in SASS doesn't result in the most performance efficient CSS code... but on the OCD/organizational side, I like it. So for CodePen purposes, CSS selector performance be damned.
*/
/* Global settings */
$color-border: #eee;
$color-label: #aaa;
$font-default: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$font-bold: 'HelveticaNeue-Medium', 'Helvetica Neue Medium';
/* Global "table" column settings */
.product-image { float: left; width: 20%; }
.product-details { float: left; width: 37%; }
.product-price { float: left; width: 12%; }
.product-quantity { float: left; width: 10%; }
.product-removal { float: left; width: 9%; }
.product-line-price { float: left; width: 12%; text-align: right; }
/* This is used as the traditional .clearfix class */
.group:before,
.group:after {
content: '';
display: table;
}
.group:after {
clear: both;
}
.group {
zoom: 1;
}
/* Apply clearfix in a few places */
.shopping-cart, .column-labels, .product, .totals-item {
@extend .group;
}
/* Apply dollar signs */
.product .product-price:before, .product .product-line-price:before, .totals-value:before {
content: '$';
}
/* Body/Header stuff */
body {
padding: 0px 30px 30px 20px;
font-family: $font-default;
font-weight: 100;
}
h1 {
font-weight: 100;
}
label {
color: $color-label;
}
.shopping-cart {
margin-top: -45px;
}
/* Column headers */
.column-labels {
label {
padding-bottom: 15px;
margin-bottom: 15px;
border-bottom: 1px solid $color-border;
}
.product-image, .product-details, .product-removal {
text-indent: -9999px;
}
}
/* Product entries */
.product {
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid $color-border;
.product-image {
text-align: center;
img {
width: 100px;
}
}
.product-details {
.product-title {
margin-right: 20px;
font-family: $font-bold;
}
.product-description {
margin: 5px 20px 5px 0;
line-height: 1.4em;
}
}
.product-quantity {
input {
width: 40px;
}
}
.remove-product {
border: 0;
padding: 4px 8px;
background-color: #c66;
color: #fff;
font-family: $font-bold;
font-size: 12px;
border-radius: 3px;
}
.remove-product:hover {
background-color: #a44;
}
}
/* Totals section */
.totals {
.totals-item {
float: right;
clear: both;
width: 100%;
margin-bottom: 10px;
label {
float: left;
clear: both;
width: 79%;
text-align: right;
}
.totals-value {
float: right;
width: 21%;
text-align: right;
}
}
.totals-item-total {
font-family: $font-bold;
}
}
.checkout {
float: right;
border: 0;
margin-top: 20px;
padding: 6px 25px;
background-color: #6b6;
color: #fff;
font-size: 25px;
border-radius: 3px;
}
.checkout:hover {
background-color: #494;
}
/* Make adjustments for tablet */
@media screen and (max-width: 650px) {
.shopping-cart {
margin: 0;
padding-top: 20px;
border-top: 1px solid $color-border;
}
.column-labels {
display: none;
}
.product-image {
float: right;
width: auto;
img {
margin: 0 0 10px 10px;
}
}
.product-details {
float: none;
margin-bottom: 10px;
width: auto;
}
.product-price {
clear: both;
width: 70px;
}
.product-quantity {
width: 100px;
input {
margin-left: 20px;
}
}
.product-quantity:before {
content: 'x';
}
.product-removal {
width: auto;
}
.product-line-price {
float: right;
width: 70px;
}
}
/* Make more adjustments for phone */
@media screen and (max-width: 350px) {
.product-removal {
float: right;
}
.product-line-price {
float: right;
clear: left;
width: auto;
margin-top: 10px;
}
.product .product-line-price:before {
content: 'Item Total: $';
}
.totals {
.totals-item {
label {
width: 60%;
}
.totals-value {
width: 40%;
}
}
}
}
View Compiled
/* Set rates + misc */
var taxRate = 0.05;
var shippingRate = 15.00;
var fadeTime = 300;
/* Assign actions */
$('.product-quantity input').change( function() {
updateQuantity(this);
});
$('.product-removal button').click( function() {
removeItem(this);
});
/* Recalculate cart */
function recalculateCart()
{
var subtotal = 0;
/* Sum up row totals */
$('.product').each(function () {
subtotal += parseFloat($(this).children('.product-line-price').text());
});
/* Calculate totals */
var tax = subtotal * taxRate;
var shipping = (subtotal > 0 ? shippingRate : 0);
var total = subtotal + tax + shipping;
/* Update totals display */
$('.totals-value').fadeOut(fadeTime, function() {
$('#cart-subtotal').html(subtotal.toFixed(2));
$('#cart-tax').html(tax.toFixed(2));
$('#cart-shipping').html(shipping.toFixed(2));
$('#cart-total').html(total.toFixed(2));
if(total == 0){
$('.checkout').fadeOut(fadeTime);
}else{
$('.checkout').fadeIn(fadeTime);
}
$('.totals-value').fadeIn(fadeTime);
});
}
/* Update quantity */
function updateQuantity(quantityInput)
{
/* Calculate line price */
var productRow = $(quantityInput).parent().parent();
var price = parseFloat(productRow.children('.product-price').text());
var quantity = $(quantityInput).val();
var linePrice = price * quantity;
/* Update line price display and recalc cart totals */
productRow.children('.product-line-price').each(function () {
$(this).fadeOut(fadeTime, function() {
$(this).text(linePrice.toFixed(2));
recalculateCart();
$(this).fadeIn(fadeTime);
});
});
}
/* Remove item from cart */
function removeItem(removeButton)
{
/* Remove row from DOM and recalc cart total */
var productRow = $(removeButton).parent().parent();
productRow.slideUp(fadeTime, function() {
productRow.remove();
recalculateCart();
});
}
This Pen doesn't use any external CSS resources.