How To Code an HTML5/CSS3 Shopping Cart Webpage Layout

I’ve wanted to put together a frontend web tutorial for a few months now. These types of articles provide an excellent point of reference for new designers who are growing accustomed to popular UI/UX trends. Specifically for designers who aren’t sure where to go on their next project, and may need a small boost of inspiration to get there.

For this tutorial I put together a small agile eCommerce checkout page. The structure itself is centered and running a fixed width to ensure an even layout regardless of the web browser. There are no jQuery animations or dynamic effects, so the layout itself is meant to be a single page running on CSS2/CSS3. Take a peek at my live demo to get an idea of the final product.

html5 css3 frontend webdev tutorial preview screenshot

Live DemoDownload Source Code

Getting Started

I have only included a single external file named styles.css in the document header. This will include a list of typical page resets along with common elements for structuring the cart itself. I chose to write this using an HTML table with the top heading and inner rows for shop products.

  <div id="w">
    <header id="title">
      <h1>HTML5/CSS3 Shopping Cart UI</h1>
    <div id="page">
      <table id="cart">
            <th class="first">Photo</th>
            <th class="second">Qty</th>
            <th class="third">Product</th>
            <th class="fourth">Line Total</th>
            <th class="fifth">&nbsp;</th>

Naturally any table you write in HTML5 should utilize a thead followed by a table row with individual th elements. Every other row in the table should be using td cells, but the heading is a special circumstance. Also these headings will provide the spacing outline for how the table is structured – I’ve created a max width of 600px with 5 columns in total.

These columns break down into a product photo, the order quantity, the product name, the total cost for that item, and a trash can icon to remove any items from the cart with a single click. Each row is set to a fixed width using pixels for the width/height properties. Since the layout isn’t responsive I figured this makes the table sit nicer without any excess spacing.

  <!-- shopping cart contents -->
  <tr class="productitm">
    <!-- -->
    <td><img src="images/design-bundle-pack.png" class="thumb"></td>
    <td><input type="number" value="1" min="0" max="99" class="qtyinput"></td>
    <td>Design Bundle Package</td>
    <td><span class="remove"><img src="images/trash.png" alt="X"></span></td>

I also created a number of items in the list, but the code above is just one example of the first product row. Inside the tbody element each row represents a product item when using the class .productitm. These rows have extra spacing and a border to separate them from each other. Also notice the quantity input uses the numeric type, as opposed to a text field type.

In Google Chrome this gives the user small up/down arrows to quickly update values. Other browsers don’t seem to have this native support just yet. But I’m almost positive there are jQuery plugins out there which can replicate this effect if you need full browser support.

Bottom Row Structure

Looking down towards the very bottom of the table you’ll find the last 3 lines are somewhat different. They contain the shipping+tax costs, then finally the grand total along with a checkout button. This button is styled in a way using open source CSS3 gradients from a CodePen entry. It’s also using a fixed width and height, but can be manually resized or updated to increase the font size or something similar.

  <!-- tax + subtotal -->
  <tr class="extracosts">
    <td class="light">Shipping & Tax</td>
    <td colspan="2" class="light"></td>
  <tr class="totalprice">
    <td class="light">Total:</td>
    <td colspan="2">&nbsp;</td>
    <td colspan="2"><span class="thick">$225.45</span></td>
  <!-- checkout btn -->
  <tr class="checkoutrow">
    <td colspan="5" class="checkout"><button id="submitbtn">Checkout Now!</button></td>

Since this isn’t a real form I used a <button> element in place of a typical submit input. Since these rows do not follow the same structure as the headings I’m including lots of colspan attributes on some of the table cells. This will span over a multitude of cells to better organize the prices so that they’re easier to read.

I find this to be an elegant solution because everything is fairly clear right off the bat. If you needed to add some extra features it wouldn’t be difficult to widen the layout and create more room for the content… or even create more table columns altogether!

CSS Page Styles

I’m using some typical page resets I created from the Eric Meyers template. The page background is called Old Map downloaded from Subtle Patterns. I also worked to include a simple rounded font creating one big bold title and finally settling on Fredoka One through Google Web Fonts.

@import url(;

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
  outline: none;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
html { overflow-y: scroll; }
body {
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: 62.5%;
  line-height: 1;
  color: #414141;
  background: #caccf7 url('bg.png'); /* */
  padding: 25px 0;

::selection { background: #bdc0e8; }
::-moz-selection { background: #bdc0e8; }
::-webkit-selection { background: #bdc0e8; }

br { display: block; line-height: 1.6em; } 

article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
ol, ul { list-style: none; }

input, textarea { 
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  outline: none; 

blockquote, q { quotes: none; }
blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
strong, b { font-weight: bold; }
em, i { font-style: italic; }

table { border-collapse: collapse; border-spacing: 0; }
img { border: 0; max-width: 100%; }

h1 {
  font-family: 'Fredoka One', Helvetica, Tahoma, sans-serif;
  color: #fff;
  text-shadow: 1px 2px 0 #7184d8;
  font-size: 3.5em;
  line-height: 1.1em;
  padding: 6px 0;
  font-weight: normal;
  text-align: center;

This is all pretty easy to understand but not everyone is a supporter of total resets. Bootstrap doesn’t use tremendous blocks of resets and keeps more to a standard baseline – ultimately it’s your call as a developer. Now the title and page itself have been broken down into smaller divs contained inside the outer wrapper.

#title {
  display: block;
  width: 100%;
  background: #95a6d6;
  padding: 10px 0;
  -webkit-border-top-right-radius: 6px;
  -webkit-border-top-left-radius: 6px;
  -moz-border-radius-topright: 6px;
  -moz-border-radius-topleft: 6px;
  border-top-right-radius: 6px;
  border-top-left-radius: 6px;

#page {
  display: block;
  background: #fff;
  padding: 15px 0;
  -webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.4);
  -moz-box-shadow: 0 2px 4px rgba(0,0,0,0.4);

Box shadows and other properties are used for a more elegant look. Designers are lucky that modern-day trends have evolved around CSS3 so that we can move away from repeating background images for shadows or rounded corners.

The Shopping Cart

Playing around with the table was a somewhat annoying process. Using border-box will redefine how content is structured internally, along with how margins & padding will be applied. My table also uses border-collapse for resetting as much default functionality as possible.

/** cart table **/
#cart {
  display: block;
  border-collapse: collapse;
  margin: 0;
  width: 100%;
  font-size: 1.2em;
  color: #444;
#cart thead th {
  padding: 8px 0;
  font-weight: bold;

#cart thead th.first {
  width: 175px;
#cart thead th.second {
  width: 45px;
#cart thead th.third {
  width: 230px;
#cart thead th.fourth {
  width: 130px;
#cart thead th.fifth {
  width: 20px;

#cart tbody td {
  text-align: center;
  margin-top: 4px;

tr.productitm {
  height: 65px;
  line-height: 65px;
  border-bottom: 1px solid #d7dbe0;

I’ve chosen to create individual classes for each of the columns in the header. The only purpose is to give them a fixed width setting that will not change, regardless of each internal cell’s contents. All this content is centered within each cell to provide a natural-looking space between each row. Products in the cart use a row height of 65px along with a line-height of this same value. Now we have text that is centered vertically and horizontally no matter what complete width is being applied to the document.

.remove {
  cursor: pointer;
  position: relative;
  right: 12px;
  top: 5px;

.light {
  color: #888b8d;
  text-shadow: 1px 1px 0 rgba(255,255,255,0.45);
  font-size: 1.1em;
  font-weight: normal;
.thick {
  color: #272727;
  font-size: 1.7em;
  font-weight: bold;

/** submit btn **/
tr.checkoutrow {
  background: #cfdae8;
  border-top: 1px solid #abc0db;
  border-bottom: 1px solid #abc0db;
td.checkout {
  padding: 12px 0;
  padding-top: 20px;
  width: 100%;
  text-align: right;

I wanted to use light text for the labels to keep visitors focused on the important text. This is also why you’ll notice a bright blue background appended to the tax+shipping row. This is similar in the row with the submit button and it makes everything easier to skim from a distance.

All of the button styles can be found on CodePen along with some additional button colors. I’ve merely updated the text to be larger and easier to read with an internal text shadow.

#submitbtn {
  width: 150px;
  height: 35px;
  outline: none;
  border: none;
  border-radius: 5px;
  margin: 0 0 10px 0;
  font-size: 1.3em;
  letter-spacing: 0.05em;
  font-family: Arial, Tahoma, sans-serif;
  color: #fff;
  text-shadow: 1px 1px 0 rgba(0,0,0,0.2);
  cursor: pointer;
  overflow: hidden;
  border-bottom: 1px solid #0071ff;
  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #66aaff), color-stop(100%, #4d9cff));
  background-image: -webkit-linear-gradient(#66aaff, #4d9cff);
  background-image: -moz-linear-gradient(#66aaff, #4d9cff);
  background-image: -o-linear-gradient(#66aaff, #4d9cff);
  background-image: linear-gradient(#66aaff, #4d9cff);
#submitbtn:hover {
  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4d9cff), color-stop(100%, #338eff));
  background-image: -webkit-linear-gradient(#4d9cff, #338eff);
  background-image: -moz-linear-gradient(#4d9cff, #338eff);
  background-image: -o-linear-gradient(#4d9cff, #338eff);
  background-image: linear-gradient(#4d9cff, #338eff);
#submitbtn:active {
  border-bottom: 0;
  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #338eff), color-stop(100%, #4d9cff));
  background-image: -webkit-linear-gradient(#338eff, #4d9cff);
  background-image: -moz-linear-gradient(#338eff, #4d9cff);
  background-image: -o-linear-gradient(#338eff, #4d9cff);
  background-image: linear-gradient(#338eff, #4d9cff);
  -webkit-box-shadow: inset 0 1px 3px 1px rgba(0,0,0,0.25);
  -moz-box-shadow: inset 0 1px 3px 1px rgba(0,0,0,0.25);
  box-shadow: inset 0 1px 3px 1px rgba(0,0,0,0.25);

Using CSS3 gradients in backgrounds can give your layout a modern look that isn’t always possible with regular CSS2 properties. The button’s active state also appends an inner shadow into the button, appearing to sink down into the page itself. I hope these CSS examples can provide some inspiration when building a newer style layout. Also try browsing through CodePen in some free time – you may be surprised at the quality of code snippets you can find there.

html5 css3 frontend webdev tutorial preview screenshot

Live DemoDownload Source Code


There are probably 1001 different ways to create a checkout/shopping cart webpage. It’s given me deeper insight towards frontend web development, and how tutorials like this can become a prominent learning tool. Feel free to download a copy of my source code and try building a similar cart into your own eCommerce project. Additionally if you have any questions or comments about the article you can share with us in the post discussion area below.