HTML5 Tutorial: How to Build a Single Product Page

In this post, we are going to work on a fictional project, creating a single product page to offer iPhone 4S, and in this project we are also going to implement the methods that we have discussed in the previous posts; the <details> element and the negation selector.

Let’s get started.

The HTML5 Markup

First, we need to create an html document with the following markup:

<div class="product">

      <h1>Apple iPhone 4 - 16GB</h1>
      <h4>The most amazing iPhone yet.</h4>

    <img src="">


  <p>The faster dual-core A5 chip. The 8MP camera with all-new optics also shoots 1080p HD video. And introducing Siri. It's the most amazing iPhone yet.</p>

   <summary>Product Features</summary>
        <li>8 mega pixel camera with full 1080p video recording</li>
        <li>Siri voice assitant</li>
        <li>Air Print</li>
        <li>Retina display</li>
        <li>Photo and video geotagging</li>

  <button>Buy Now</button>



We use several new tags from HTML5 spec., like the header, hgroup, figure, section, and one we’ve discussed before; the details and summary tag.

However, we are not going to dig into these tags, not because we are not willing to, but rather these are basic topics that you can find easily elsewhere. So, if you are really new to HTML5, I would recommend you read the following references of those tags; they have explained them comprehensively:

Now let’s see our page’s first appearance.

Well, it looks sensible without any styles. At the very top there is the header, and then comes the section for the image, description and lastly the ‘Buy Now’ button. Now, let’s perk up this page.

The Styles

We will start off by normalizing all default styles using this stylesheet and add a gradient background to the html tag.

html {
  height: 100%;
  background: #f3f3f3;
  background: -moz-linear-gradient(top, #f3f3f3 0%, #ffffff 50%);
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f3f3f3), color-stop(50%,#ffffff));
  background: -webkit-linear-gradient(top, #f3f3f3 0%,#ffffff 50%);
  background: -o-linear-gradient(top, #f3f3f3 0%,#ffffff 50%);
  background: -ms-linear-gradient(top, #f3f3f3 0%,#ffffff 50%);
  background: linear-gradient(top, #f3f3f3 0%,#ffffff 50%);
  filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#f3f3f3', endColorstr='#ffffff',GradientType=0 );

Remember that our product elements are all wrapped within a div with the product class. So, here we would like to center the wrapper and set the width to be about 650px.

.wrapper {
  width: 650px;
  margin: auto;
  padding: 25px 0px;

The header section

In the header section we have two headings h1 and h4, so let’s style these elements.

h1, h4 {
  font-family: Helvetica Neue, Arial, sans-serif;
  font-weight: normal;
  margin: 0; 
h1 { 
  font-size: 24pt;
h4 {
  font-size: 16pt;
  color: #aaa; 

And then add a little space at the bottom of the header with a margin.

header {
  margin-bottom: 20px;

If you look at the very right side of the header, there would be a lot whitespace in that side.

So why don’t we also put the Apple logo in there.

header {
  margin-bottom: 20px;
  background: url('../') no-repeat right center; 

The Product Image

Next, float the image to the left and set the image maximum width to 350px.

figure {
  float: left;
figure img {
  max-width: 350px;

Since the image has been pushed to the left, then we will float the description section to the right and set the width to 300px.

section {
  font-family: Tahoma, Arial, sans-serif;
  line-height: 150%;
  float: right;
  width: 300px;
  color: #333;

Now let’s see the result so far.

It starts looking good, but the details tag still doesn’t work yet (except in Chrome), so let’s style the button next.

The Button

For the button styles, we will mimic the one from the Store. And here is all the syntax you need to put in your stylesheet for the button.

button {
  background: #36a9ea;
  background: -moz-linear-gradient(top, #36a9ea 0%, #127fd2 100%);
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#36a9ea), color-stop(100%,#127fd2));
  background: -webkit-linear-gradient(top, #36a9ea 0%,#127fd2 100%);
  background: -o-linear-gradient(top, #36a9ea 0%,#127fd2 100%);
  background: -ms-linear-gradient(top, #36a9ea 0%,#127fd2 100%);
  background: linear-gradient(top, #36a9ea 0%,#127fd2 100%);
  filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#36a9ea', endColorstr='#127fd2',GradientType=0 );
  border: 1px solid #00599d;
  color: #fff;
  padding: 8px 20px;
  -webkit-border-radius: 3px;
  border-radius: 3px;
  -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, .1), inset 0px 1px 0px 0px rgba(250, 250, 250, .3);
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, .1), inset 0px 1px 0px 0px rgba(250, 250, 250, .3);
  text-shadow: 0px 1px 1px #156cc4;
  filter: dropshadow(color=#156cc4, offx=0, offy=1);
  font-size: 10pt; 

button:hover {
  background: #2f90d5;
  background: -moz-linear-gradient(top, #2f90d5 0%, #0351b7 100%);
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#2f90d5), color-stop(100%,#0351b7));
  background: -webkit-linear-gradient(top, #2f90d5 0%,#0351b7 100%);
  background: -o-linear-gradient(top, #2f90d5 0%,#0351b7 100%);
  background: -ms-linear-gradient(top, #2f90d5 0%,#0351b7 100%);
  background: linear-gradient(top, #2f90d5 0%,#0351b7 100%);
  filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#2f90d5', endColorstr='#0351b7',GradientType=0 );

button:active {
  background: #127fd2;
  -webkit-box-shadow: inset 0px 2px 1px 0px rgba(0, 47, 117, .5), 0px 1px 1px 0px rgba(0, 0, 0, 0);
  box-shadow: inset 0px 2px 1px 0px rgba(0, 47, 117, .5), 0px 1px 1px 0px rgba(0, 0, 0, 0); 

Now the button should look better.

Problem in Internet Explorer

As usual IE (Internet Explorer) always causes some trouble; if you open this in any IE lower than 9, the page will remain un-styled.

This is because Internet Explorer does not recognize the new elements (section, header, etc.) so the styles that we’ve specified failst to apply. Thus, in the next step we will work on solving this problem.

Testing Browser Support

In our previous post, we have tackled the browser support for the details element using this polyfill; so that it could work in the unsupported browsers. However, this time we will try different ways of doing it with Modernizr.

From its official website, "Modernizr is an open-source JavaScript library that helps you build the next generation of HTML5 and CSS3-powered websites". Technically, Modernizr will test the browser support for certain new elements and features. If support is not provided, we must then provide a fallback whether it is by giving different styles or providing polyfills. In this case, we will use Modernizr to help us test the details and summary element.

  1. Go to Modernizr and proceed to its download page.

  2. In the download page, Modernizr provides some options to configure the library, so you only have to select certain features you really need for your website. In this case, we need:

    • HTML5Shiv 3.4
    • Add CSS Classes, this feature will automatically insert classes in the html tag.
    • the Modernizr.load,
    • go to the community add-ons box and select elem-details,
    • In the Extensibility section, select Modernizr.addTest.
  3. Generate and download the file.
  4. Link it to your html and reload the page in Internet Explorer. The page should’ve now been styled since Internet Explorer can now recognize the tags.

And, if you view the source or inspect element, you will find the no-details class has been inserted in the html tag; indicating that the browser where we are previewing the page; is currently not supporting details element. @@@@ [ I can’t understand this sentence. ]

We can then create a fallback using this class as the hook, which we will be doing in the next step.

The Fallback

In this step we will provide similar details element functionality for other browsers (excluding Chrome). In the previous post, this step was automatically done using this script, but this time we will create it on our own.

Note: Just reviewing a bit from our previous post; the details element is currently only supported in Chrome browser.

So, let’s start working on the CSS first.

On the summary tag, we change its cursor mode to pointer, so the user will notice that it is clickable.

summary {
  cursor: pointer;
  font-size: 12pt;
  outline: 0; 

To give more spaces at the top and bottom of the details element with a margin.

details { 
  margin: 20px 0px;

By default, the summary tag will have an arrow. But here we would like to replace it with a plus-minus icon.

Note: Before proceeding, I previously have downloaded the icons from this collection by Fugue, download and sprite them into one file.

Let’s add a before pseudo-element and attach the icon as background. Notice that at this point, the background position is at the top which will show the plus icon.

details > summary:before {
  width: 16px;
  height: 16px;
  display: inline-block;
  content: '' !important;
  background: url('../') no-repeat center top;
  margin-right: 5px;
  position: relative;
  top: 2px; 

Then, when the details element is open, the background position will move to the bottom which will show the minus icon.

details[open] > summary:before, > summary:before {
  background: url('../') no-repeat center bottom;

The [open] sign is a selector. In this case, it will select the details open attribute in supporting browser.

Lastly we should hide the arrow that by default is shown in Chrome.

details > summary::-webkit-details-marker { 
  display: none;

Then, let’s see the result in a browser for a while.

The default arrow now has been replaced with our icon, and if you see it in Chrome you’ll already have a toggle effect when you click on it; the icon will change accordingly. But, in other browsers nothing will happen still. So, in the next step we will try to replicate the effect with jQuery.

The toggle effect with jQuery

Before we begin with the jQuery part, I would like to thank Ian Devlin for the inspiration, the script below is actually a slight modification of his.

All right, let’s create a variable to store the summary tag.

var summary = $('details summary');

Then we wrap all the sibling elements of the summary with a div.


And hide that div when the details element does not have the open class.

$('details:not(.open) summary').siblings('div').hide();

When the summary is clicked, we want the hidden div to be shown, and the opposite, when the div is initially open, it would be hidden. {

To make sure that those functions will only be executed in the unsupported browsers, we wrap them inside this conditional statement.

if($('html').hasClass('no-details')) {
  //the code goes here

And below is the code we have:

if ($('html').hasClass('no-details')) {
var summary = $('details summary');

summary.siblings().wrapAll('<div class="slide"></div>');

$('details:not(.open) summary').siblings('div').hide(); { 

Now let’s test it in the browser; the toggle effect should’ve now worked on all browsers, I personally have checked (until Internet Explorer 7).

Tips: Alternatively you can change the .toggle() with .slideToggle() to create a slide effect. Also if you want the detail to be opened initially you can add a class open in the details element.


We have been through all the steps of creating a single product page using HTML5, debugging for unsupported browsers as well as replicate the toggle effect for detail element on our own, so hopefully you can learn a lot from it.

However, I’m aware that I did not explain everything in detail in this post, so if you want to clear something up, feel free to post the question in the comment box below.