Dynamic, Proportional Resizing of Images in a Photoset using jzmn.setPhotoset

jzmn.setPhotoset is a javascript function for beautifully resizing images in a photoset, without cropping or aspect-ratio distortion, such that all images in a row are of the same height. jzmn.setPhotoset makes use of percentage widths, so that the photoset can work for all sizes, and can be resized without problem. [Github]

Like most of my coding experiments, it is encapsulated in the jzmn namespace. This largely means nothing.

Basic Usage

The general format of jzmn.setPhotoset is shown below:

window.addEventListener("load",function() {
	jzmn.setPhotoset(element,userOptions);
});

elementrefers to the element node (or nodelist of elements) that contains the photoset, while userOptions is an object containing customizable options for the function (more info below).

jzmn.setPhotoset makes use of img.naturalWidth and naturalHeight to automatically get dimensional information from the images. Because of this, the function is best called inside a window load event handler. However, if the height and width attribute of the images are provided in the markup, jzmn.setPhotoset can be called outside an onload event handler in the following manner:

jzmn.setPhotoset(element,{pData:true, userOptions});

The CSS

jzmn.setPhotoset only sets the widths of the elements in the photoset using javascript. The rest of the styling is delegated to CSS, by means of attaching classes to each photoset elements.

jzmn.setPhotoset provides the following classes for styling hooks:

  • photoset-item - for all elements that are children of the photoset-container.
  • photoset-last-column - for all photoset items that are the last item in their row.
  • photoset-last-row - for all photoset items that are in the last row.

The provided classes can then be utilized as in the following sample CSS (for more information, visit set-photoset-example.css in the github repository):

.photoset-item {
	display: block;
	float: left;
	margin: 5px;
	margin-left: 0;
	margin-top: 0;
}
.photoset-last-column {
	margin-right:0 !important;
}
.photoset-last-column + .photoset-item {
	clear:left;
}
.photoset-last-row {
	margin-bottom:0 !important;
}

Example

Suppose you have a set of five images, which you want to lay out into 2 rows, with 2 images on the first row and the 3 on the second.

<div class="photoset" id="#photoset1">
	<img src="1.png" />
	<img src="2.png" />
	<img src="3.png" />
	<img src="4.png" />
	<img src="5.png" />
</div>

Without jzmn.setPhotoset, this set will look something like the following. Note that the following has been scaled by 50%, because at original scale, it was very tall.

Applying jzmn.setPhotoset:

var photoset = document.querySelector("#photoset1");
jzmn.setPhotoset(photoset,{layout:"23"});

Now it would look like

Multiple Photosets

a single jzmn.setPhotoset function call is capable of serving multiple photosets with different layouts, as long as a data-layout attribute is specified per photoset:

<div class="photoset" id="#photoset1" data-layout="23">
	<img src="1.png" />
	<img src="2.png" />
	<img src="3.png" />
	<img src="4.png" />
	<img src="5.png" />
</div>
<div class="photoset" id="#photoset2" data-layout="121" >
	<img src="6.png" />
	<img src="7.png" />
	<img src="8.png" />
	<img src="9.png" />
</div>

In this case, the javascript code is:

var photosets = document.querySelectorAll(".photoset");
jzmn.setPhotoset(photosets);

If data-layout is not specified for an element in this case, jzmn.setPhotoset won’t do anything to that set.

A Photoset of… not Photos?

jzmn.setPhotoset uses img.naturalWidth and naturalHeight to automatically get dimensional information from the images. If the children of the element is not an img (or if the browser does not support naturalWidth/Height), it might be necessary to explicitly define the dimensions on these children. This could be the case if the images are wrapped in anchor tags.

This is done by defining width and height attributes per child, and setting pData to true in userOptions. Alternatively, user-defined attributes can also be used (such as data-height and data-width, for example, on elements where width and height attributes are not semantically appropriate), as long as the jzmn.setPhotoset function call sets childHeight and childWidth in userOptions to the name of these attributes.

For the following example markup:

<div class="photoset" id="#photoset1" data-layout="12" >
	<a href="1.png" data-height="200" data-width"200">
		<img src="1.png" />
	</a>
	<a href="2.png" data-height="150" data-width"300">
		<img src="2.png" />
	</a>
	<a href="1.png" data-height="200" data-width"150">
		<img src="1.png" />
	</a>
</div>

Using the following javascript code will work:

var photoset = document.querySelector("#photoset1")
jzmn.setPhotoset(photoset,{pData:true, childHeight:'data-height', childWidth: 'data-width'});

Gutters

You can set gutters using the following syntax:

jzmn.setPhotoset(photoset,{gutter:gutterWidth});

where gutterWidth is a string representing the width of the gutter. It can be in px or em, or in fact any expression valid within a css calc() function. This is because, when calculating for the width of photoset items with gutters, calc() is used. If the browser does not support calc(), then the default, percentage only width is still provided.

Note, however, that jzmn.setPhotoset only uses the value passed to it to calculate the widths of the images. To actually set a gutter, one must set the photoset-item’s margin using css:

.photoset-item { 
	margin-top: gutterWidth; 
	margin-left: gutterWidth; 
}

Here is what our first photoset would look like if the pictures had margins of 5px, using the following javascript code:

var photoset = document.querySelector("#example5");
jzmn.setPhotoset(photoset,{gutter:"5px"});

Known Issues

jzmn.setPhotoset’s calculated widths may not be accurate if the images have paddings or borders.