Advertisement
HTML/CSS

Perfectly Rotate and Mask Thumbnails With CSS3

by

Ever seen a website showcasing image thumbnails that are slightly rotated? It's a simple effect that adds a layer of visual personality. Saying that, if you're not achieving the rotation effect with CSS, you're working too hard! Learn how to do it right!

Republished Tutorial

Every few weeks, we revisit some of our reader's favorite posts from throughout the history of the site. This tutorial was first published in August of 2011.


Introduction

Image galleries with rotated thumbnails are somewhat infrequent, but it's a simple trick to add style to your webpage. However, if not done right, achieving and maintaining this effect can sometimes prove to be a major hassle!

To properly achieve this effect, your first thoughts might turn to creating rotated thumbnails in Photoshop. However, this can prove to be difficult in the long term. Disadvantages to creating rotated thumbnails in this way include:

  • Angle Consistency: If the images are not all rotated at the same angle, the visual consistency of page is lost. This means maintaing a PSD of each individual thumbnail properly rotated at a consistent angle. You may, for example, open your PSD and realize you have forgotten the rotation angle of your thumbnails.
  • CMS Thumbnail Generation:If you are running a CMS (such as Wordpress), your thumbnails are probably being generated automatically. Using the PSD method described above, you'll have to manually create and upload each individual thumbnail in your CMS. Also, if you already have an existing site but want to apply the rotation effect to your thumbnails, you'll have to recreate all thumbnails in Photoshop then re-upload all of them!
  • Long-Term Manageability: Say you've created all your thumbnails slightly rotated, but now you want to realign or redesign your gallery. This means you'll have to regenerate all of your thumbnails. If you've been managing your thumbnails in Photoshop, this means you have to adjust and re-save each individual thumbnail all over again. Ugh.

Wouldn't it be nice if you could perform this little rotation with one line of code? Well you can! Let's learn how.


Step 1: Understanding Our Goal

A brief overview of what we are trying to accomplish reveals the following steps:

  1. Create an image thumbnail in Photoshop (not rotated)
  2. Insert the thumbnail using the img tag
  3. Mask it appropriately using CSS (think Photoshop masks)
  4. Rotate the thumbnail within the mask using CSS3
Example of image thumbnail and mask

To make sure our gallery degrades gracefully, steps 1-3 will be accomplished using CSS. Step 4 (the rotation effect) will be accomplished using CSS3.


Step 2: Understanding Thumbnail Size and Rotation Angle Increases

Before creating our thumbnails, we need to determine how large each thumbnail will appear on screen.

If our thumbnails are too small and we rotate them at too much of an angle, some of the corners will give us an empty space. Like this:

Empyt space in the mask corners

Hence, to properly fill the mask area, we can conclude that the more our thumbnail is rotated the larger it will have to be. In mathematical terms, as the rotation angle of the thumbnail increases, so too must the thumbnail's size (and vice versa).

Increase in rotation means an increase in size
Remember this key: the image thumbnail will always be larger than the image mask (thumbnail size > mask size)

A Warning to Those Repelled by Math

Steps 3-6 describe how to mathematically calculate proportionate sizing for the image mask and thumbnail. Understanding it is not necessary to being able to rotate images with the CSS transform property. Rather, its purpose is to help you understand how to properly determine the sizing of your elements to allow full 360° rotation. This ensures you won't be left with ugly empty corners.


Step 3: Proportionately Equal

To avoid showing empty space in our mask, we must determine ONE of the following:

  • Size of the actual thumbnail
  • Size of the image mask (viewable portion of the thumbnail)

Because the thumbnail and image mask are proportionately equal in size, if we set the size of one we can calculate the size of the other.


Step 4: Determining Dimensions

In this example, we are going to set our image mask size first. By setting the size of our image mask we can use a little math to calculate the thumbnail's size:

  • Determine the size of the image mask: 180x240 pixels
  • Find the length of the diagonal side
    • Use the Pythagorean theorem ( a2 + b2 = c2 )
      • Our first side (a) is 180px
      • Our second side (b) is 240px
      • So, 1802 + 2402 = c2 (diagonal length)
      • 90,000 = c2
      • 300 = c (take the square root of each side)
    • Our diagonal length (c) equals 300
pythagorean theorem

The diagonal length is an important number. To allow the our thumbnail full 360° rotation, its shortest side must equal the image mask's longest side. (Even though you may not need it, provisioning for 360° rotation will allow future changes to your rotation angle without having to resize your thumbnails).

Thumbnails shortest side equals masks's longest side

Step 5: Calculating Thumbnail Dimensions

As you can see, our thumbnail's shortest side must be equal to our mask's longest side. If it's not, we'll be left with empty space. Remember: the thumbnail's size is proportionately greater than the image mask's size.

Proportional relationship between thumbnail and mask

Calculating the thumbnail's size so it properly fits is easy once we know the dimensions of the image mask. We simply take the mask's largest side (the diagonal) and let it equal the shortest side of our thumbnail.

  • Mask's largest side (300) equals thumbnail's shortest side (x)
  • Use the proportionate relationships to find the thumbnail's length
    • 180 : 300 (mask's height : thumbnail's height)
    • 240 : y (mask's length : thumbnail's length)
  • Cross multiply to solve
    • 180y = 72,000
  • y = 400 (thumbnail's length)
Finding y2

We have now determined our mask and thumbnail sizes. We know if our image mask is 180x240px, than the image thumbnail inside that mask must be 300x400px to allow for 360° rotation.

A Happy Note: Because the image mask and thumbnail sizes are proportionately equal, this math would also work if we set our thumbnail size first! We would use the same Pythagorean theorem and proportional relationships to determine the proper sizes.


Step 6: Finally Some HTML

Now that we know all our sizes, let's build our rotated thumbnails by starting with some basic HTML.

<!DOCTYPE html> 
<html>
	<head>
		<title>Rotated Thumbnails with CSS3</title>
		<link rel="stylesheet" href="styles.css" />
	</head>
<body>

<div id="wrapper">

	<h1>Rotated Thumbnails with CSS3</h1>	
	<label>Transform Angle: </label> 
	<input id="rotation_amount" value="15" /> 
	<button>Update</button> 
	<span id="error_message"> Number values only</span> 
	<br />
	
	<a href="1.jpg" class="mask"><img src="1.jpg" /></a>
	<a href="2.jpg" class="mask"><img src="2.jpg" /></a>
	<a href="3.jpg" class="mask"><img src="3.jpg" /></a>
	
	<a href="4.jpg" class="mask"><img src="4.jpg" /></a>
	<a href="5.jpg" class="mask"><img src="5.jpg" /></a>
	<a href="6.jpg" class="mask"><img src="6.jpg" /></a>
	
	<a href="7.jpg" class="mask"><img src="7.jpg" /></a>
	<a href="8.jpg" class="mask"><img src="8.jpg" /></a>
	<a href="9.jpg" class="mask"><img src="9.jpg" /></a>
	
	
	<div style="clear:both;"></div>
	
</div> <!-- #/wrapper -->
</body>
</html>

This basic HTML markup inserts the following:

  • <input> - This will allow the user to change the rotation angle. Also, we set our value attribute to equal the same amount we will initially set in our CSS (15 in this case).
  • <span> - This error message will be hidden from view. Using jQuery, we will show it if the user enters something besides a number in the input box.
  • <img> - These are our thumbnails which can be linked to whatever you please.
  • clear:both - Clears our floated thumbnails
  • class="mask" - The class for our image mask
basic HTML layout

Step 7: CSS Basic Page Styling

Let's apply some basic styling to our page to give it structure and simplicity.

body {
	margin:0; 
	padding:0; 
	background:#eee;
	font-family:Geneva, Lucida Sans, Lucida Grande, Lucida Sans Unicode, Verdana, sans-serif;
}
#wrapper {
	width:840px; 
	margin:0 auto; 
	background:#fff; 
	border:1px solid #ccc; 
	padding:25px; 
	border-top:none;
}
#error_message {
	color:red; 
	display:none;
	font-size:.8em;
}

Note here that we hid our error_message by default as we will toggle it's visibility later on in jQuery.

Add Some CSS3 Effects

Let's add a few more details to enhance our basic styling

#wrapper {
	border-radius:0 0 5px 5px;
	-moz-border-radius:0 0 5px 5px;
	-webkit-border-radius: 0 0 5px 5px; 
	box-shadow:0 0 5px #ccc;
	-moz-box-shadow:0 0 5px #ccc;
	-webkit-box-shadow:0 0 5px #ccc;
}
basic CSS styling

Now we have our content centered with good spacing and some CSS3 effects for enhanced page styling.


Step 8: CSS Styling Image Mask

Let's apply the image mask to our thumbnails. In our HTML, we wrapped each thumbnail in an anchor tag and gave it a class of mask which we will use in our CSS.

.mask {
	position:relative;
	height:180px;
	width:240px;
	float:left;
	overflow:hidden;
	margin:15px;
	border:5px solid #f6f6f6;
	box-shadow:0 0 1px #000;
	-moz-box-shadow:0 0 1px #000;
	-webkit-box-shadow:0 0 1px #000;
}

Here's a description of the CSS properties we used (and why we used them):

  • position:relative - Our img tags will be positioned absolutely inside our image mask
  • height, width - Earlier we determined our image mask's dimensions. This is where we place those sizes.
  • float:left - Floats our images so they appear in a gallery form.
  • overflow:hidden - As calculated earlier, our thumbnails will be 300x400px. However, we will only show a portion (180x240px) of them. This property acts as mask, hiding the portion of our thumbnails that extends outside the 180x240 dimensions.
  • margin - Space out our images
  • border, box-shadow - This gives us a double border (in supporting browsers). The border property gives us a thick, off-white border around the image while the box-shadow gives us a thin, black border around our thick, off-white border.
thumbnails not rotated

Step 9: CSS Sizing The Thumbnails

Set our thumbnail sizes according to the dimensions we calculated in Step 5.

.mask img {
	height:300px;
	width:400px;
}

Step 10: CSS Centering The Thumbnails

Right now, our thumbnails are positioned relatively (from the top left corner).

thumbnail positioned in the top left

We want our thumbnail to be centered horizontally and vertically within the mask.

thumbnail positioned in the center

To accomplish this, we use the following CSS rules:

.mask img {
	position:absolute;
	margin-top:-150px; /* half the height */
	margin-left:-200px; /* half the width */
	top:50%;
	left:50%;
}

Here's a description of what we did:

  • position:absolute - This positions the thumbnail absolutely within the image mask
  • margin - We set negative margins that are exactly half the height and width of the image (300x400) then set our positioning properties top and left which pull the elements back into perfect center.
thumbnails centered positioning

Step 11: CSS Thumbnail Rotation

We will be using the CSS3 property transform to rotate our elements. So, our CSS will include all the browser prefixes

.mask img {
	-webkit-transform: rotate(15deg);
	-moz-transform:rotate(15deg);
	-o-transform:rotate(15deg);
	-ms-transform:rotate(15deg);
	transform:rotate(15deg);
}

The CSS here is pretty simple. We just place our angle of rotation in parenthesis followed by "deg".

In this example we used 15 as the rotation value, but you could put a different value there. Because we calculated the sizes of our mask and thumbnail properly, we have provisioned room for full 360° rotation! A positive integer rotates the image to the right, a negative integer rotates the image to the left.

thumbnails rotated

Step 12: CSS Image Hover Effect

As an additional effect, we're going to add a simple line of CSS that changes our border color when the user hovers over and image.

.mask:hover {border-color:#ddd;}

Step 13: jQuery Changing Rotation Value Dynamically

As a little bonus, we are going to allow the user to enter a value in our input box that changes the CSS rotation angle. So first, let's add jQuery at the end of our page right before the closing body tag along with a link to our custom script:

<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
<script src="js.js"></script>

Step 14: jQuery Document Ready

Now let's setup jQuery for when the document is ready:

jQuery(document).ready(function($) {
	// code here
});

Step 15: jQuery Initial Function

We create a function for anytime our "update" button gets clicked.

$('button').click(function() {
	//code here
});

Step 16: jQuery Storing Current Rotation Value

We want to store the CSS numeric value for the current angle of rotation in a variable.

var rotation_angle_value = $('#rotation_amount').val();

This code finds the rotation_amount id (which we assigned to the input) and gets its current value. If you remember, we set the initial value attribute to equal 15 (the same as in our CSS code for the rotation angle).


Step 17: jQuery Using isNaN() Function

We want to make the user's input value our new angle of rotation. However, we want to make sure the user doesn't accidentally enter a non-numeric value. That's where the isNaN() javascript function comes in. isNaN() stands for "is not a number". This function does exactly what its names implies: it checks to see if the value you pass to it "is not a number".

So, we will use the isNaN() function and pass to it our rotation angle value (as entered by the user). If it's not a number, we will display our error message.

//check to see if the user's input value is a number or not
if (isNaN(rotation_angle_value)) { //not a number
	$('#error_message').show();
	//rest of code here
}

Step 18: jQuery Updating New Rotation Angle

If the user's newly entered value is not a number, we've displayed an error message. Now we will use an else statement for when they have entered a numeric value. First we hide the error message.

else {
	$('#error_message').hide();
}

Because the rotation angle is stored multiple times in our CSS (due to the various browser prefixes) we have to update ALL of those values with jQuery. So, what we will do is store the syntax of the CSS value in a variable (with the new angle value). Essentially, we are writing rotate(15deg) and replacing the value of '15' with the value the user input.

var rotation_angle = 'rotate(' + rotation_angle_value + 'deg)';
similar CSS values

Then we create a CSS object with relational values. We define each of our CSS properties (the browser prefixes for transform), then insert the value as the variable we just defined.

var updated_css = {
	'-webkit-transform' : rotation_angle,
	'-moz-transform' : rotation_angle,	
	'-o-transform' : rotation_angle,
	'-ms-transform' : rotation_angle,
	'transform'	: rotation_angle,
}

Now we simply pass that variable storing our CSS properties and values to jQuery to update our CSS!

$('.mask img').css(updated_css);

Step 19: jQuery Final jQuery Code

This is what all our jQuery looks like:

jQuery(document).ready(function($) {
	
	$('button').click(function() {
		//get the rotation angle value
		var rotation_angle_value = $('#rotation_amount').val();
		
		if (isNaN(rotation_angle_value)) { //is not a number
			$('#error_message').show();
		} 
		else { //is a number
			$('#error_message').hide();
			
			//store CSS value syntax with the new rotation angle value
			var rotation_angle = 'rotate(' + rotation_angle_value + 'deg)';
			
			//store CSS properties and values
			var updated_css = {
				'-webkit-transform' :	rotation_angle,
				'-moz-transform'	:	rotation_angle,	
				'-o-transform'		:	rotation_angle,
				'-ms-transform'		:	rotation_angle,
				'transform'			:	rotation_angle,
			}
			
			//update our CSS
			$('.mask img').css(updated_css);
		}
	});
});

Conclusion

I hope you've learned something, above all that committing yourself to non-flexible designs in Photoshop is often avoidable by using CSS3 techniques directly in the browser. Thanks for following along!

Related Posts
  • Web Design
    HTML & CSS
    Build a Dribbble Portfolio Grid With Flexboxgrid and JribbbleFlexboxgrid dribbble
    Flexboxgrid is a new framework which allows you to combine the predictability and common language structure of a grid system with the flexibility and simplicity of flexbox. Today, we will walk through the basics of using Flexboxgrid, and use it to build a simple Dribbble feed. Let's get started!Read More…
  • Web Design
    Complete Websites
    Building the Responsive Timeline Portfolio PagePortfolio thumb
    During this tutorial we will be building the fantastic Timeline Portfolio as seen in an earlier tutorial by Tomas Laurinavicius. We will be using some responsive techniques as well as CSS3 animations, Sass and a little bit of jQuery.Read More…
  • Web Design
    Case Studies
    How They Did It: Typekit's New HomepageTypekit retina
    Typekit recently redesigned their homepage with some new services in mind. When Typekit joined Adobe, they set out to bring us a new way to handle fonts on the web. Not only did they create a fairly simple way to embed fonts on the web, but they have now officially launched a desktop sync option, which allows Creative Cloud subscribers to sync fonts to their computer directly from Typekit. This has been in a beta form for a while now, and provides a much easier route to local fonts than finding them elsewhere!Read More…
  • Web Design
    HTML/CSS
    Finishing Off the Merry Christmas Web App InterfaceXmas build 1 retina
    In this tutorial we will finish off our web app front-end so it all looks perfect and functions nicely on all screen sizes. Last time, we rounded off by styling the message boxes, leaving just the content left to do. Shall we dive right in? Ok!Read More…
  • Web Design
    Email
    Creating a Simple Responsive HTML EmailEmail new rwd thumb
    In this tutorial I will show you how to create a simple responsive HTML email which will work in every email client, including all the new smartphone mail clients and apps. It uses minimal media queries and a fluid width approach to ensure maximum compatibility.Read More…
  • Web Design
    UX
    Implementing the Float Label Form PatternForm float input retina
    Using Matt Smith’s mobile form interaction design as a guide, we will create a stunning form interaction for the web that’s both beautiful and accessible using HTML, CSS and JavaScript.Read More…