Image Highlighting and Preview with jQuery

In this tutorial we will show you how to highlight and preview images that are integrated in an article or spread over a page. This is a nice way to […]

In this tutorial we will show you how to highlight and preview images that are integrated in an article or spread over a page. This is a nice way to allow users to view a bigger version of an image that is relevant to some context. We will highlight images on a delayed hover and offer a preview mode which will enlarge and center the bigger version of the image on the screen.

Let’s start!

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

The Markup

For the HTML structure we simply need to consider the image and its class. The image can be placed anywhere in your website:

<img src="images/thumbs/1.jpg" alt="images/1.jpg" class="ih_image"/>

We use the alt attribute to add the reference to the bigger image.

We will also add an overlay element before the body ends:

<div id="ih_overlay" class="ih_overlay" style="display:none;"></div>

The structure that we will be creating with the JavaScript will look as follows:

<div id="ih_clone" class="ih_image_clone_wrap">
	<span class="ih_close"></span>
	<img class="preview" src="images/1.jpg">
</div>

This structure will not be placed in our HTML – it will be created dynamically.

Now, let’s take a look at the style.

The CSS

First, we will define the style for the overlay:

.ih_overlay{
	position:fixed;
	top:0px;
	left:0px;
	right:0px;
	bottom:0px;
	background:#000;
	z-index:10;
	opacity:0.9;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=90);
}

The filter property is used for applying transparency in IE. We make the overlay fixed in order to always be shown, even if we scroll the page.

The image that we want to apply our effect to will have the following style:

img.ih_image{
	margin:10px 0px;
	position:relative;
	-moz-box-shadow:1px 1px 4px #000;
	-webkit-box-shadow:1px 1px 4px #000;
	box-shadow:1px 1px 4px #000;
	opacity:0.7;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
}

It’s pretty plain, we just add some box shadow to it.

In our JavaScript we will create a wrapper that contains a clone of the image that we are hovering. It will get the same positions as the current image. That’s why we do not define the top and left here, but dynamically in the JS.

.ih_image_clone_wrap{
	position:absolute;
	z-index:11;
}

We will also add some spans with icons that will either show a magnifying glass, a loading image or a cross. We define all common properties as follows:

.ih_image_clone_wrap span.ih_zoom,
.ih_image_clone_wrap span.ih_loading,
.ih_image_clone_wrap span.ih_close{
	position:absolute;
	top:10px;
	right:10px;
	width:24px;
	height:24px;
	-moz-border-radius:6px;
	-webkit-border-radius:6px;
	border-radius:6px;
	opacity:0.8;
	cursor:pointer;
	-moz-box-shadow:1px 1px 2px #000;
	-webkit-box-shadow:1px 1px 2px #000;
	box-shadow:1px 1px 2px #000;
	z-index:999;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=80);
}

The specific properties for each class, like the background, will be defined as follows:

.ih_image_clone_wrap span.ih_zoom{
	background:#000 url(../icons/zoom.png) no-repeat center center;
}
.ih_image_clone_wrap span.ih_loading{
	background:#000 url(../icons/loader.gif) no-repeat center center;
}
.ih_image_clone_wrap span.ih_close{
	background:#000 url(../icons/close.png) no-repeat center center;
}
.ih_image_clone_wrap img{
	opacity:0.7;
	-moz-box-shadow:1px 1px 10px #000;
	-webkit-box-shadow:1px 1px 10px #000;
	box-shadow:1px 1px 10px #000;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
}

The full sized image that we will load on top of the thumbnail, will have the following style:

.ih_image_clone_wrap img.preview{
	opacity:1;
	position:absolute;
	top:0px;
	left:0px;
}

And now, let’s add some magic!

The JavaScript

In our jQuery function we will start by defining a variable to control the timing of the highlight effect.
When we hover over an image with the specific class we create our div with the class ih_image_clone_wrap and define its position by getting the position of the current image.

/**
* timeout to control the display of the overlay/highlight
*/
var highlight_timeout;

/**
* user hovers one image:
* create a absolute div with the same image inside,
* and append it to the body
*/
$('img.ih_image').bind('mouseenter',function () {
		var $thumb = $(this);

		var $clone = $('<div />',{
			'id'		: 'ih_clone',
			'className'	: 'ih_image_clone_wrap',
			'html'     	: '<img src="' + $thumb.attr('src') + '" alt="' + $thumb.attr('alt') + '"/><span class="ih_zoom"></span>',
			'style'		: 'top:' + $thumb.offset().top + 'px;left:' + $thumb.offset().left + 'px;'
		});

		var highlight = function (){
			$('#ih_overlay').show();
			$('BODY').append($clone);
		}
		//show it after some time ...
		highlight_timeout = setTimeout(highlight,700);

		/**
		* when we click on the zoom,
		* we display the image in the center of the window,
		* and enlarge it to the size of the real image,
		* fading this one in, after the animation is over.
		*/
		$clone.find('.ih_zoom').bind('click',function(){
			var $zoom = $(this);
			$zoom.addClass('ih_loading').removeClass('ih_zoom');
			var imgL_source = $thumb.attr('alt');

			$('<img class="ih_preview" style="display:none;"/>').load(function(){
				var $imgL = $(this);
				$zoom.hide();
				var windowW = $(window).width();
				var windowH = $(window).height();
				var windowS = $(window).scrollTop();

				$clone.append($imgL).animate({
					'top'			: windowH/2 + windowS + 'px',
					'left'			: windowW/2  + 'px',
					'margin-left'	: -$thumb.width()/2 + 'px',
					'margin-top'	: -$thumb.height()/2 + 'px'
				},400,function(){
					var $clone = $(this);
					var largeW = $imgL.width();
					var largeH = $imgL.height();
					$clone.animate({
						'top'			: windowH/2 + windowS + 'px',
						'left'			: windowW/2  + 'px',
						'margin-left'	: -largeW/2 + 'px',
						'margin-top'	: -largeH/2 + 'px',
						'width'			: largeW + 'px',
						'height'		: largeH + 'px'
					},400).find('img:first').animate({
						'width'			: largeW + 'px',
						'height'		: largeH + 'px'
					},400,function(){
						var $thumb = $(this);
						/**
						* fade in the large image and
						* replace the zoom with a cross,
						* so the user can close the preview mode
						*/
						$imgL.fadeIn(function(){
							$zoom.addClass('ih_close')
								 .removeClass('ih_loading')
								 .fadeIn(function(){
									$(this).bind('click',function(){
										$clone.remove();
										clearTimeout(highlight_timeout);
										$('#ih_overlay').hide();
									});
								$(this).bind('click',function(){
									$clone.remove();
									clearTimeout(highlight_timeout);
									$('#ih_overlay').hide();
								});
							});
							$thumb.remove();
						});
					});
				});
			}).error(function(){
				/**
				* error loading image
				* maybe show a message like
				* 'no preview available'?
				*/
				$zoom.fadeOut();
			}).attr('src',imgL_source);
		});
}).bind('mouseleave',function(){
	/**
	* the user moves the mouse out of an image.
	* if there's no clone yet, clear the timeout
	* (user was probably scolling through the article, and
	* doesn't want to view the image)
	*/
	if($('#ih_clone').length) return;
	clearTimeout(highlight_timeout);
});

/**
* the user moves the mouse out of the clone.
* if we don't have yet the cross option to close the preview, then
* clear the timeout
*/
$('#ih_clone').live('mouseleave',function() {
	var $clone = $('#ih_clone');
	if(!$clone.find('.ih_preview').length){
		$clone.remove();
		clearTimeout(highlight_timeout);
		$('#ih_overlay').hide();
	}
});

And that’s all! We hope you enjoyed this tutorial and find it useful!

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 11

Comments are closed.
  1. wow, its a great…
    like the lightbox trick, but its a hover metode..aw..aw..aw
    always cool and full stylish…
    thanks ^_^’

  2. I love this blog. Grade A in ideas, creativity and inspiring people 🙂

  3. The delayed hover is a little too long but the idea of integrated discreetly preview images is very good.

  4. Awesome. The only thing that would make it better would be to add a 500ms fade in/out on the background.

  5. Can you please email me on how to prevent the mouseout function from stopping the loading of image?

    I want to click on the preview button then mouseout and it will still load the image.

  6. Bug report #1

    $zoom.addClass(‘ih_close’).removeClass(‘ih_loading’).fadeIn(function(){
    $(this).bind(‘click’,function(){
    $clone.remove();
    clearTimeout(highlight_timeout);
    $(‘#ih_overlay’).hide();
    });
    });

    replace to:

    $zoom.addClass(‘ih_close’).removeClass(‘ih_loading’).fadeIn(function(){}).bind(‘click’,function(){
    $clone.remove();
    clearTimeout(highlight_timeout);
    $(‘#ih_overlay’).hide();
    });