Masonry – displaying html blocks as a brickwork
Have you come across websites where blocks of different sizes are displayed in a container, maximizing the use of space?
This kind of display is made possible by the script David DeSandro, called Masonry. You can also see a visual example on the official script website. On the official website, you will find full documentation in English.
Masonry is a JavaScript library that allows for displaying HTML blocks in a compact, stacked manner. The script analyzes the height of each block and arranges it to maximize space utilization.
Perhaps some of you have long been familiar with it and have even used it in your projects, but I encountered it recently for the first time. I cannot say that everyone will easily be able to create any kind of display. However, I believe that anyone can handle basic usage. Understanding how it works is not straightforward, but I cannot say that it is very difficult either. If you have a good understanding of JS, you should be able to create any kind of display. The purpose of this post is to introduce you to Masonry and to make a note of it for myself.
Masonry operates independently without the use of libraries, but it can also be used as a jQuery plugin.
In this post, I will provide a translation of the main page of the official site, which explains how to get started with the script.
Masonry in JavaScript
Masonry Integration
These installation packages from https://masonry.desandro.com contain everything necessary for using Masonry:
- masonry.pkgd.min.js for users;
- masonry.pkgd.js for developers.
Download the js file and integrate it into your website:
<script src="/path/to/masonry.pkgd.min.js"></script>
Or use CDN:
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script> <!-- not minified --> <script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.js"></script>
For WordPress, it is better to integrate using the function wp_enqueue_script():
add_action( 'wp_enqueue_scripts', 'mason_script' );
function mason_script() {
// wp_register_script( 'masonry', 'https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js' );
// The above line is not necessary because in WordPress,
// Masonry is included by default, so you can simply integrate it.
wp_enqueue_script( 'masonry' );
}
HTML
Masonry works with container elements that have the same class "item":
<div id="container"> <div class="item">...</div> <div class="item w2">...</div> <div class="item">...</div> ... </div>
The class can be any, but it is important to define the option itemSelector : '.item' when calling.
CSS
For container blocks, the width needs to be specified. The width should correspond to the container and the columnWidth parameter (column width):
.item { width: 25%; }
.item.w2 { width: 50%; }
Masonry Initialization
To start the script, it needs to be applied to our container. Initializing the script in pure JavaScript is done as follows:
var container = document.querySelector('#container');
var msnry = new Masonry( container, {
// Settings
columnWidth: 200,
itemSelector: '.item'
});
In this case, the instance constructor contains 2 arguments: columnWidth and itemSelector (class of blocks in the container that Masonry will work with). These are not all options; you can see the rest in the documentation or below on this page.
Initialization via HTML
Masonry can be started without using JavaScript, directly from HTML, by specifying the class js_masonry for the container and setting the parameters in the data-masonry-options attribute:
<div id="container" class="js-masonry"
data-masonry-options='{ "columnWidth": 200, "itemSelector": ".item" }'>
Options set in HTML should be in JSON format. Arguments should be in quotes "itemSelector":. Note that the value of the HTML attribute should be in single quotes ' because JSON properties use double quotes ".
Initialization via jQuery
Masonry does not require jQuery, but if you prefer working with jQuery, Masonry works with it as a plugin.
var $container = $('#container');
// Initialization
$container.masonry({
columnWidth: 200,
itemSelector: '.item'
});
To get the instance, use the .data('masonry') method:
var msnry = $container.data('masonry');
Initialization for blocks with images
Since images are loaded separately from the HTML code, applying Masonry to blocks with images usually causes an error - one block overlapping another. This happens because Masonry triggers before the image in the block is loaded, setting the height for the block, and then the image "disrupts" this height. This problem can be solved in several ways:
Method 1
Set the sizes for all images explicitly: width and height in pixels.
Method 2
Attach Masonry processing to the load event. jQuery code:
jQuery(window).load(function(){
jQuery('.masonry').masonry({ columnWidth:310, itemSelector:'.box, .item' });
});
The downside of this method is that you will most likely have to wait for the entire "window" to load: jQuery(window).load. Using load separately for an element is rarely permissible because jQuery will interpret it as an AJAX load function. To avoid this, use the 3rd example.
Method 3
Initialize Masonry after all images have been loaded. To check for image loading, use the additional JS script imagesLoaded. Code:
var container = document.querySelector('#container');
var msnry;
// Initialize Masonry after image loading
imagesLoaded( container, function() {
msnry = new Masonry( container );
});
jQuery code:
var $container = $('#container');
// Initialize Masonry after image loading
$container.imagesLoaded( function() {
$container.masonry();
});
Note: errors may also occur when using additional fonts, so font loading needs to be checked.
Properties
The mandatory properties are: columnWidth and itemSelector. All others can be used as desired:
- itemSelector(string) (mandatory)
- Defines which child element of the container will be used for building the masonry. The element needs to be specified to exclude other container elements used for setting sizes, see
"columnWidth": ".grid-sizer".
Default: none - columnWidth(number/element/selector as a string) (mandatory)
- The width of the column in pixels:
"columnWidth": 60. If a selector or element is set, Masonry will use the width of the specified element:"columnWidth": ".gutter-sizer". Masonry calculates the outer width of blocks, taking into account CSS properties such as border, padding, margin.
Default: none - containerStyle(object)
- CSS styles applied to the container. To cancel the application of Masonry styles to the container, specify
containerStyle: null.
Default: { position: 'relative' } - gutter(number/element/selector as a string)
- The distance between elements, similar to
margin-right. Example: "gutter": 10
Default: 0 - hiddenStyle(object)
- Styles applied to hidden elements.
Default: { opacity: 0, transform: 'scale(0.001)' } - isFitWidth(boolean)
Sets the width of the container equal to the available number of columns, calculated from the width of the container elements. When this option is set, you can center the container using CSS.
Note: this property does not work if the container elements have a width in
%, it needs to be in pixels:width: 120px. Also, thecolumnWidthoption must be set to a fixed value, for example:columnWidth: 120.Default: false
- isInitLayout(boolean)
- Enables adjustment of blocks during initialization. Set to false so that the script does not build the masonry during initialization, allowing you to use methods and add events before processing container elements.
Default: true - isOriginLeft(boolean)
- Controls the horizontal positioning of blocks. By default, blocks are arranged from left to right. Set to false to arrange blocks from right to left.
Default: true - isOriginTop(boolean)
- Controls the vertical positioning of blocks. By default, blocks are arranged from top to bottom. Set to false to arrange blocks from bottom to top.
Default: true - isResizeBound(boolean)
- Links block positioning to window size changes.
Default: true - stamp(element/array of elements/selector string/NodeList)
- Defines which blocks need to be fixed during display. These are special elements to which the masonry effect will not be applied.
"stamp": ".stamp".
Default: none - transitionDuration(string)
- The transition duration (animation speed) when blocks change position or appear. It should be set in a time format for CSS. To cancel all animation, set it to 0:
transitionDuration: 0.
Default: '0.4s' - visibleStyle(object)
- Styles applied when hidden elements are displayed.
Default: { opacity: 1, transform: 'scale(1)' }
Masonry in Pure CSS
Recently, practically all browsers understand the CSS property column-count, see for yourself.
And so, there is no longer a need to integrate JavaScript, and you can create Masonry blocks using pure CSS. Of course, this option is less flexible in settings, but it is much simpler and quicker to set up, and it is easier to understand.
Here's how it works.
We have this HTML code:
<div class="masonry"> <div class="item">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div> <div class="item">...</div> ... <div class="item">...</div> </div>
And we apply these CSS styles for it:
/* Masonry container */
.masonry {
column-count: 4; // how many columns are needed?
column-gap: 1em; // gap between blocks (right or left)
/* the same with necessary prefixes as of March 18, 2016 */
-webkit-column-count: 4; -moz-column-count: 4; column-count: 4;
-webkit-column-gap: 1em; -moz-column-gap: 1em; column-gap: 1em;
}
/* Masonry blocks */
.masonry .item {
display: inline-block; // important!
width: 100%; // important!
margin-bottom: 1em;
background-color: #eee;
}
This option has plenty of downsides
Let's go through the downsides of this method and how it falls short compared to masonry.
-
Browser support, as of today, is excellent.
-
Any animation will need to be written manually.
-
The main downside of column-count and the reason why this method cannot be used instead of masonry in most cases is the direction of the blocks.
If masonry is read horizontally:
1 2 3
4 5 6Then with column-count it's vertical:
1 3 5
2 4 6Using this approach from a chronological point of view is not an option.
-
Dynamically adding elements to the block, for example, with AJAX loading, is confusing... In other words, masonry adds new elements after the current ones and doesn't disturb the current ones, so there's no confusion about what has been added and what hasn't. But with this method, it confuses the elements.
For example, if we have 3 columns and 30 elements - let's say 10 in each column. If we add another 10, they won't be evenly distributed across all 3 columns, without affecting the previous arrangement of elements. They will be added to the HTML, and then the browser will rearrange them. As a result, after dynamically adding elements, there is almost always confusion: what was there and what was added...
Therefore, if you plan to load elements via AJAX, this option should not be considered!