I released a new version (free) (30 – May – 2026). You can check it here
Description: Portfolio Page to Masonry layout


#1. First, you need to change Portfolio Page to Grid: Overlay layout

#2. Use this code to Custom CSS
/* Portfolio Masonry Styles - @tuanphan */
.portfolio-masonry {
animation: fadein 1s 0.15s backwards;
display: block !important;
grid-template-columns: none !important;
}
.portfolio-masonry .grid-item {
margin-bottom: 10px !important;
break-inside: avoid;
transition: all 0.3s ease;
height: auto !important;
position: relative !important;
padding-bottom: 0 !important;
box-sizing: border-box !important;
}
.portfolio-masonry .grid-item:first-child {
margin-top: 0 !important;
}
.portfolio-masonry .grid-item .grid-image {
position: relative !important;
overflow: hidden;
width: 100%;
margin: 0;
line-height: 0;
padding-bottom: 0 !important;
}
.portfolio-masonry .grid-item .grid-image-inner-wrapper {
position: relative !important;
top: auto !important;
left: auto !important;
bottom: auto !important;
right: auto !important;
width: 100% !important;
height: auto !important;
}
.portfolio-masonry .grid-item img {
width: 100% !important;
height: auto !important;
display: block !important;
position: static !important;
object-fit: cover !important;
}
.portfolio-masonry .grid-item .portfolio-overlay,
.portfolio-masonry .grid-item .portfolio-text {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
z-index: 99;
}
.portfolio-masonry .grid-item .portfolio-text {
z-index: 100;
display: flex;
align-content: center;
justify-content: center;
flex-direction: column;
padding: 7%;
text-align: center;
transition: opacity ease 200ms;
}
.portfolio-masonry .grid-item .portfolio-text .portfolio-title {
margin-top: 0;
padding-top: 0;
margin-bottom: 0;
font-size: 20px !important;
}
@keyframes fadein {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 767px) {
.portfolio-masonry {
column-count: 2;
column-gap: 10px;
column-fill: balance;
padding: 0 10px;
}
.portfolio-masonry .grid-item {
margin-bottom: 10px !important;
display: inline-block !important;
width: 100% !important;
}
}
@media (min-width: 768px) {
.portfolio-masonry {
column-count: 3;
column-gap: 10px;
column-fill: balance;
padding: 0 15px;
}
.portfolio-masonry .grid-item {
margin-bottom: 10px !important;
display: inline-block !important;
width: 100% !important;
}
}
.portfolio-masonry#gridThumbs .portfolio-text {
width: calc(~"100% - 40px") !important;
height: calc(~"100% - 40px") !important;
padding: 20px !important;
}
/* END Portfolio Masonry Styles - @tuanphan */

#3. Use this code to Portfolio Page Header Injection
<script>
(function(){function getImageAspectRatio(img){const dimensions=img.getAttribute('data-image-dimensions');if(!dimensions)return 1;const[width,height]=dimensions.split('x').map(d=>parseFloat(d));return height/width}
function initPortfolioMasonry(container,options={}){container.classList.add('portfolio-masonry');const items=[...container.querySelectorAll('.grid-item')];items.forEach((item,index)=>{const img=item.querySelector('img[data-src], img[src]');const wrapper=item.querySelector('.grid-image-inner-wrapper');const gridImage=item.querySelector('.grid-image');if(img&&wrapper){item.style.height='auto';item.style.position='relative';item.style.paddingBottom='0';if(gridImage){gridImage.style.paddingBottom='0'}
wrapper.style.position='relative';wrapper.style.top='auto';wrapper.style.left='auto';wrapper.style.bottom='auto';wrapper.style.right='auto';wrapper.style.width='100%';wrapper.style.height='auto';wrapper.style.paddingBottom='0';img.style.position='static';img.style.width='100%';img.style.height='auto';img.style.objectFit='none';img.style.display='block'}
item.style.animationDelay=(index*0.1)+'s'});if(options.shuffle){const shuffled=items.sort(()=>Math.random()-0.5);shuffled.forEach(item=>container.appendChild(item))}
setTimeout(()=>{items.forEach(item=>{item.style.opacity='1';item.style.transform='translateY(0)'})},100)}
function initPortfolioMasonryPlugin(options={}){const defaultOptions={shuffle:!1,selector:'#gridThumbs, .portfolio-grid-overlay'};const config=Object.assign(defaultOptions,options);let containers=[];let selector=config.selector;if(config.containerIDs){selector=[];config.containerIDs.split(',').forEach(id=>{const cleanId=id.replace(/#|\./,'');if(config.ignoreContainerIDs){selector.push(`:not([id="${cleanId}"])`)}else{selector.push(`[id="${cleanId}"]`)}});if(config.ignoreContainerIDs){selector='.portfolio-grid-overlay'+selector.join('')}else{selector=selector.join(',')}}
containers=[...document.querySelectorAll(selector)];containers.forEach(container=>{if(!container.classList.contains('portfolio-masonry')){initPortfolioMasonry(container,config)}})}
function domReady(callback){if(document.readyState==='interactive'||document.readyState==='complete'){callback()}else{document.addEventListener('DOMContentLoaded',callback)}}
function ajaxReady(callback){const ajaxBody=document.querySelector('body[data-ajax-loader]');if(ajaxBody){const observer=new MutationObserver(mutations=>{if(mutations[0].attributeName==='data-ajax-loader'&&ajaxBody.getAttribute('data-ajax-loader')==='loaded'){callback()}});observer.observe(ajaxBody,{attributes:!0})}else{window.addEventListener('mercury:load',callback)}}
function dynamicDataReady(callback){}
function init(options={}){domReady(()=>initPortfolioMasonryPlugin(options));ajaxReady(()=>initPortfolioMasonryPlugin(options));dynamicDataReady(()=>initPortfolioMasonryPlugin(options));window.addEventListener('load',()=>{setTimeout(()=>initPortfolioMasonryPlugin(options),100)});window.addEventListener('resize',()=>{setTimeout(()=>initPortfolioMasonryPlugin(options),200)})}
window.portfolioMasonry={init};setTimeout(()=>{console.log('Portfolio Masonry: Starting auto init...');init()},100)})()
</script>

#3. To change space between items, change these.

