In ecommerce, sales conversion is, perhaps, the single most important measure of a successful site, so ecommerce web developers and designers are wise to focus their code and aesthetics on what will transform a digital window shopper into a paying customer.
One technique is to give potential customers good product information as early as possible in the site hierarchy. To this end, I am going to demonstrate how to use JavaScript to create a "Quick View" effect that will allow site visitors to see detailed product information at the product category page level, even before those shoppers click to see a particular product.
This tutorial is aimed at web designers trying to learn JavaScript or at ecommerce do-it-yourselfers.
HTML and CSS
In a production environment, a site's ecommerce content management system (CMS) should provide the product content on the server side, but, of course, you will need to adjust the CSS, HTML, JavaScript, or server-side script to match class and id names as needed.
For demonstration purposes, I created a very basic product category page example for a hypothetical online house wares retailer.
Here is the HTML markup.
<!doctype html> <html lang="en"> <head> <title>Quick View Demonstration</title> <link type="text/css" rel="stylesheet" href="style.css"> <link rel="icon" type="image/png" href="favicon.png"> </head> <body> <div id="wrapper"> <div id="header"> <img src="header.png" alt="the header image for my demonstration" /> </div><!--end header--> <div class="productStuff"> <div class="product"><img src="product-1.png" alt="Mauviel Copper Dutch Oven, 6 1/2-Qt." class="p-image" /><h3>Mauviel Copper Dutch Oven, 6 1/2-Qt.</h3> <div class="quickview" style="position: absolute; visibility: hidden"><img src="product-1.png" alt="Mauviel Copper Dutch Oven, 6 1/2-Qt." /><h3>Mauviel Copper Dutch Oven, 6 1/2-Qt.</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec neque dolor. Nam tempor, tellus ac bibendum tempor, ipsum nibh tristique lacus, at posuere felis justo porttitor ante. Duis consequat elementum magna, id dapibus nibh. </p></div></div> <div class="product"><img src="product-2.png" alt="Le Creuset Round Dutch Oven, 13 1/4-Qt." class="p-image" /><h3>Le Creuset Round Dutch Oven, 13 1/4-Qt.</h3> <div class="quickview" style="position: absolute; visibility: hidden"><img src="product-2.png" alt="Le Creuset Round Dutch Oven, 13 1/4-Qt." /><h3>Le Creuset Round Dutch Oven, 13 1/4-Qt.</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec neque dolor. Nam tempor, tellus ac bibendum tempor, ipsum nibh tristique lacus, at posuere felis justo porttitor ante. Duis consequat elementum magna, id dapibus nibh. </p></div> </div> <div class="product"><img src="product-3.png" alt="All-Clad Copper Core Round Oven, 4 1/2-Qt." class="p-image" /><h3>All-Clad Copper Core Round Oven, 4 1/2-Qt.</h3> <div class="quickview" style="position: absolute; visibility: hidden"><img src="product-3.png" alt="All-Clad Copper Core Round Oven, 4 1/2-Qt." /><h3>All-Clad Copper Core Round Oven, 4 1/2-Qt.</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec neque dolor. Nam tempor, tellus ac bibendum tempor, ipsum nibh tristique lacus, at posuere felis justo porttitor ante. Duis consequat elementum magna, id dapibus nibh. </p></div></div> <div class="product"><img src="product-4.png" alt="Le Creuset Round Dutch Oven, 7 1/4-Qt." class="p-image" /><h3>Le Creuset Round Dutch Oven, 7 1/4-Qt.</h3> <div class="quickview" style="position: absolute; visibility: hidden"><img src="product-4.png" alt="Le Creuset Round Dutch Oven, 7 1/4-Qt." /><h3>Le Creuset Round Dutch Oven, 7 1/4-Qt.</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec neque dolor. Nam tempor, tellus ac bibendum tempor, ipsum nibh tristique lacus, at posuere felis justo porttitor ante. Duis consequat elementum magna, id dapibus nibh. </p></div></div> </div><!--end productStuff--> <div id="footer"> </div><!--end footer--> </div><!--end wrapper--> <script src="js.js"></script> </body> </html>
In the HTML, you should notice a few important attributes and relationships.
First, notice that each "product" div element contains a nested "quickview" div element.
<div class="product"><img src="product-4.png" alt="Le Creuset Round Dutch Oven, 7 1/4-Qt." class="p-image" /><h3>Le Creuset Round Dutch Oven, 7 1/4-Qt.</h3> <div class="quickview" style="position: absolute; visibility: hidden"><img src="product-4.png" alt="Le Creuset Round Dutch Oven, 7 1/4-Qt." /><h3>Le Creuset Round Dutch Oven, 7 1/4-Qt.</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec neque dolor. Nam tempor, tellus ac bibendum tempor, ipsum nibh tristique lacus, at posuere felis justo porttitor ante. Duis consequat elementum magna, id dapibus nibh. </p></div> </div>
I will use this parent-to-child element relationship to reference the "quickview" div in the JavaScript. I could have placed the "quickview" content elsewhere in the HTML, so long as I understand the relationship between it and the image in the "product" div.
You may also notice that I set some inline styles for the "quickview" div to first remove it from the document flow and next hide it from page visitors. You will note, too, that I gave the first appearance of each image a class name of "p-image."
The style sheet for this page is also simple.
body {margin: 0; padding: 0; background: #FFF4BC; font-family: Segoe UI; color: #505050; }
img {border: none;}
ul {margin: 0; padding:0; }
li {display: inline; list-style: none; padding: 10px; text-align: center;}
#wrapper {margin: 25px auto; padding: 10px 25px; width: 960px; height: 500px; }
.product {float: left; width: 220px; margin: 0; padding: 9px; text-align: center;}
.product h3 {color:#FF732D;}
.p-image {width: 200px; border: #A6332C solid 5px;}
.quickview {width: 300px; margin: 0; padding: 0; background: #fff; text-align: center; border: #35CC9A solid 5px;}
.quickview img {width: 300px; }
.quickview h3 {color:#35CC9A;}
.quickview p {padding: 10px; text-align: left;}
Add the JavaScript Event Listener
With the example product category page marked up and styled, I can start to add the JavaScript.
For my quick view effect, I want additional product information and a larger image to appear when a shopper hovers over one of the visible product images, so I'll start by adding an event listener.
I could add a listener to each of the product images on the page—my example has only four images after all—but in a production environment where there might be 10, 20, or even 50 product images, all of those separate event listeners would be complicated to manage and would slow down page performance significantly.
So I will use event delegation, which allows me to set one event listener and then take an action based on where that event was initiated.
document.onmouseover = quickView;
function quickView(e)
{
if (!e) var e = window.event;
var target = e.target || e.srcElement;
var bWide = window.innerWidth || document.documentElement.clientWidth;
In this brief bit of JavaScript, document.onmouseover = quickview; initiates the event listener, this method is supported by both compliant browsers and Microsoft's Internet Explorer (IE). Thus I'll have no browser compatibility issues with it. When a mouseover event takes place, the quickView function is called.
The quickView function receives the event (e) from the event listener and, in order to support both standards compliant browsers and IE runs a test on the value of e.
if (!e) var e = window.event;
Browsers like Mozilla Firefox, Google Chrome, Opera, and Apple Safari will pass, so to speak, and move on to the next line, while in IE the value of e will be reset to window.event, so that IE can run the script.
Next, I create two more variables, target and bWide, to manage other potential browser compatibility issues. Essentially, these variables give the browser the choice to use the DOM element it understands.
var target = e.target || e.srcElement;
In the code above, target can be either e.target, which World Wide Web Consortium (W3C) compliant browsers understand to represent the element that started the event (or the element the shopper is hovering over), while IE understands that same element as e.srcElement.
Make the Quick View Visible
As mentioned above, I want the appropriate "quickview" div to appear when a shopper hovers over the corresponding product image. So I need some code to locate that "quickview" div, using what I know about the relationship between that div and the product image. In this case, both elements have the same parentNode, the "product" div, and the "quickview" div is that parent's last child.
var dTarg = target.parentNode.lastChild; dTarg.style.visibility = 'visible';
The variable dTarg captures the "quickview" div, and the next line makes the div visible.
The "quickview" div is now visible to the shopper, but it is positioned below the product image it corresponds to.
Positioning the Quick View
I really want to "quickview" div to appear alongside the product image, so I add the following JavaScript.
dTarg.style.top = (target.parentNode.offsetTop - 130) + 'px'; dTarg.style.left = (target.parentNode.offsetLeft + 225) + 'px';
With this script, I am resetting the "quickview" div's top and left attributes. This works because the div is positioned absolutely. Notice that I am using the position of the parentNode, which is the "product" div, to align the "quickview" div.
But there is still a problem. This code always places the "quickview" to the right of the image the shopper is hovering over. This is fine for most of the product images, but with certain screen sizes, the "quickview" div for the last product in the row will be obscured by the browser.
To fix this problem, I add a couple of conditional statements.
var dTarg = target.parentNode.lastChild;
dTarg.style.visibility = 'visible';
dTarg.style.top = (target.parentNode.offsetTop - 130) + 'px';
if (target.parentNode.offsetLeft < (bWide * .5))
{
dTarg.style.left = (target.parentNode.offsetLeft + 225) + 'px';
}
if (target.parentNode.offsetLeft >= (bWide * .5))
{
dTarg.style.left = (target.parentNode.offsetLeft - 297) + 'px';
}
Now the script measures the width of the browser window (bWide). If the position of the "product" div—which you will recall was my reference for positioning the "quickview" div—has an offsetLeft value less than half the width of the browser window, the JavaScript positions the "quickview" div to the right of the product image, but if that offsetLeft value is greater than or equal to half of the width of the browser window, the "quickview" div is positioned to the left of the product image.
Hiding the Quick View
With the code so far, it is possible for a shopper to open of several "quickview" divs at once, obscuring the view of other products on the example product category page.
To solve this problem, I first add a second event listener to identify when the user's mouse pointer is no longer hovering over a product image. This listener is aimed specifically at the target and is only created when a shopper hovers over one of the product images.
target.onmouseout = hideQuickView;
As you can see, this listener initiates a function called, hideQuickView.
function hideQuickView(e)
{
if (!e) var e = window.event;
var target = e.target || e.srcElement;
target.parentNode.lastChild.style.visibility = 'hidden';
}
This function simply resets the "quickview" div's visibility to hidden. Now when a shopper moves the mouse pointer off of the product image the "quickview" div vanishes as quickly as it appeared.
Summing Up
The example is complete. Our JavaScript adds, positions, and removes the quick view as needed and provides a shopper with critical product information earlier in the site hierarchy, without cramming unwanted information onto the product category page.
I hope you enjoyed this brief tutorial, please leave comments below. The complete JavaScript follows.
//Add event listener for onmouseover accommodate both W3C and Microsoft
//Toggle the visibility for the newDiv and position it.
document.onmouseover = quickView;
function quickView(e)
{
if (!e) var e = window.event;
var target = e.target || e.srcElement;
var bWide = window.innerWidth || document.documentElement.clientWidth;
if(target.className == 'p-image')
{
var dTarg = target.parentNode.lastChild;
dTarg.style.visibility = 'visible';
dTarg.style.top = (target.parentNode.offsetTop - 130) + 'px';
if (target.parentNode.offsetLeft < (bWide * .5))
{
dTarg.style.left = (target.parentNode.offsetLeft + 225) + 'px';
}
if (target.parentNode.offsetLeft >= (bWide * .5))
{
dTarg.style.left = (target.parentNode.offsetLeft - 297) + 'px';
}
target.onmouseout = hideQuickView;
}
}
function hideQuickView(e)
{
if (!e) var e = window.event;
var target = e.target || e.srcElement;
target.parentNode.lastChild.style.visibility = 'hidden';
}
