Create a tiled Views layout in Drupal 7Create a tiled Views layout in Drupal 7

Categories:
Content management systems are not always known for their ease of layout. Drupal has such a vast array of modules to extend your site, but often times we forget that you can do some really creative things with layouts. Today we're going to look at a javascript plugin called Masonry and how we can use it to build amazing fluid tile layouts. Let's look at what we'll be building:



 

AUTHOR NOTE: The first time I tried to do this I used the contributed modules "Masonry API" and "Masonry Views". Unfortunately they lack a key built in feature needed to produce a flexible tiled layout: the ability to span a block across multiple columns. I suspect that the reason is there isn't a great way of implementing which exact blocks to target within the UI. Therefore I'm going with a manual implementation of Masonry. If you don't need your blocks to span more than 1 column, take a look at Masonry API after you read this.

 

Required modules

- Views

- jQuery Update


Setup Drupal

Install your modules and pop over to /admin/config/development/jquery_update and bump it up to 1.7. Masonry requires jQuery 1.6 or higher to work and Drupal is packaged with 1.4.

Next create a new View, call it whatever you like and make sure you create a new page view. I'm going to use my "Article" content type. My views format will be an unformatted list of teasers as shown. Also make sure to disable Views row classes as shown:



 
Next go to whatever content type you chose to display and add a new field, call it "column span." Make it a select list with the numbers 1 through 5 as the select options, with "1" being selected by default. We are going to use this field to allow us to make blocks that span multiple columns, the number selected being the number they will span.



 
Believe it or not we are done with the Drupal configuration at this point. Point your browser to the actual page with your view on it.


Setup Masonry

Head here and download the latest production version of Masonry. Go to your Drupal theme's folder and throw it in with your other scripts. I usually have a dedicated /scripts directory for these. Next edit your theme .INFO file and add the script. Note if you do not already have a separate generic script file that runs on every page load, create one and add it as well:

scripts[] = scripts/scripts.js
scripts[] = scripts/masonry.pkgd.min.js

 

Open your generic script file and add this to initialize Masonry when the page loads:

 

jQuery(document).ready(function($){
	// --- masonry --- //
	var $container = $('.view-content');
	// initialize
	$container.masonry({
		itemSelector: '.masonry-brick'
	});
});

 

You can customize "$container" to be more specific if you have a lot of views on your site, but it should target the '.view-content' div within your Masonry view. The item selector is something we'll be adding to our content type's template file.


Themeing

By default, Drupal likes to provide wrapper divs around all field content. Usually this is beneficial, but in our case we will need to raw output of the "column span" field for use in our template. You can always copy the field.tpl.php file into your theme's template directory and override it there. Some people prefer to make a separate field template file for every override, but I prefer the following solution:

 

<?php
	//Give a list of fields where you don't want wrapper divs
	$wrapper = 1;
	$currentfield = $element['#field_name'];
	$donotwrap = array(
		'field_column_span',
		'field_some_name'
	);
	if (in_array($currentfield, $donotwrap)){
		$wrapper = 0;
	}
?>
<?php if ($wrapper == 1): ?>
	<div class="<?php print $classes; ?>"<?php print $attributes; ?>>
		<?php if (!$label_hidden): ?>
			<div class="field-label"<?php print $title_attributes; ?>><?php print $label ?>:&nbsp;</div>
		<?php endif; ?>
		<div class="field-items"<?php print $content_attributes; ?>>
			<?php foreach ($items as $delta => $item): ?>
				<div class="field-item <?php print $delta % 2 ? 'odd' : 'even'; ?>"<?php print $item_attributes[$delta]; ?>><?php print render($item); ?></div>
			<?php endforeach; ?>
		</div>
	</div>
<?php endif ?>
<?php 
if ($wrapper == 0){
	foreach ($items as $delta => $item) {
		print render($item);
	}
}
?>
 
The top php code allows you to enter in a list of field names to ignore wrapping in divs. We use a variable to then decide whether a field gets the default treatment or to leave out the wrapper divs.
 
Go into the Views module folder, and in the theme subfolder, grab the "views-view-unformatted.tpl.php" file and copy it to your theme directory as before. You will have to rename this file based on what your View tells you. Open up your View configuration advanced options, click on "theme" and look at the style output. Rename your file according to the second option. In my case:



 
Rescan to make sure you named it correctly. If so, save your view configuration. In your new file, replace the contents with this:

<?php if (!empty($title)): ?>
  <h3><?php print $title; ?></h3>
<?php endif; ?>
<?php foreach ($rows as $id => $row): ?>
 <?php print $row; ?>
<?php endforeach; ?>
 
If you haven't already, create a unique template file for your content type, do so (in my case 'node--article.tpl.php'). At this point flush your Drupal caches to refresh Drupal on all your new template files. In your template add a wrapper div around you node div as follows:

<div class="masonry-brick span-<?php print render($content['field_column_span']); ?>">
  <!--REGULAR NODE CONTENT HERE-->
</div>
 
Lastly we use some CSS. Basically what we do is set a default column width to 20% of the container width so 5 blocks can fit across. We then adjust each column span accordingly to a multiple of that. Feel free to use your own widths. My design allows for fluid width containers, but you could easily use pixels if yours is fixed width.

#page {
  width:90%;
  margin:auto;
}
.masonry-brick { 
  width:20%; 
}
.masonry-brick.span-2 { 
  width:40%; 
}
.masonry-brick.span-3 { 
  width:60%; 
}
.masonry-brick.span-4 { 
  width:100%; 
}
.node-article { 
  padding:10px; 
}
.node-article .inner { 
  background:#ffffff; 
  box-shadow:0 0 5px #999999; 
  height:380px;
  overflow:hidden;
}
.masonry-brick.span-2 .node-article .inner {
  height:780px;
}
.masonry-brick.span-3 .node-article .inner {
  height:380px;
}
.node-article .text { 
  padding:30px; 
}
.node-article img { 
  width:100%; 
  height:100%; 
}
 
And that should do it! Play around with your styling, you can get some really cool results by changing padding and widths around. Happy themeing!

Need a Custom Designed Theme?

If you need a custom designed theme for your business then our designers can work with you to create a unique concept that is consistent with your brand, clearly communicates your value proposition and helps you achieve your goals. >> Click here to contact us and let us know about your needs and we'll analyze and provide you with an estimate for designing and development your custom theme.