Equal Height Divi Blog Grid
How do I make the blog grid equal height? This is a very common question for Divi users setting up the Blog module. There are no other tutorials on this, so as always we though we should provide a great solution for this need. So in this tutorial, I will show you how to equalize the Divi Blog module grid height.
There is already a solution provided by Elegant Themes in their chat support help docs here: Blog Module equal height grid “boxes” with JavaScript. So credit goes to them for the original code, but we have improved it greatly and also will explain it much better than they do. We also include some bonus snippets, such as aligning the buttons to the bottom.
▶️ Please watch the video above to get all the exciting details! 👆
Add A Custom CSS Class To The Blog Module
Before getting to the actual code snippet, we first need to go to the Blog module that we want to make equal height and add a custom CSS class. This CSS class will allow us to target any particular Blog module where you want the equal height effect to take place, and will not affect any others. To add this, go to the Blog module settings to the Advanced tab and open the CSS ID & Classes toggle. There you should add the class “pa-blog-equal-height” to the CSS Class input field. This same class will then be used in the code snippet below to match and link the code to this module.
Add The jQuery Code
Now we come to the big part of the tutorial, the code that does all the work. This is jQuery and it is at first glance a bigger than usual snippet, but I will explain all of it clearly down below. For now, go ahead and get the code added to your website.
Where To Paste The jQuery Code
1. Divi Assistant
If you are using our Divi Assistant plugin, simply paste the code in the jQuery tab in the custom code window in the Divi Visual Builder.
2. Child Theme
If you are using a child theme, paste this code into the scripts.js file (don't forget to remove the <script> tags at the beginning and end). If you don't have a child theme, you can generate a child theme directly on your site or download our free child theme.
3. Divi Theme Options Integration
Otherwise, paste this code in your Divi>Theme Options>Integrations tab in the "Add code to the < head > of your blog" code area.
If you need help understanding where to paste the code, please check out our complete guide about where to add custom code In Divi.
<script>
(function ($) {
var pa_equalize_button_height = "true";
if (pa_equalize_button_height == "false") {
function pa_equalize_blog_post_height(blog) {
var articles = blog.find('article');
var heights = [];
articles.each(function () {
var height = 0;
height += ($(this).find('.et_pb_image_container, .et_main_video_container').length != 0) ? $(this).find('.et_pb_image_container, .et_main_video_container').outerHeight(true) : 0;
height += $(this).find('.entry-title').outerHeight(true);
height += ($(this).find('.post-meta').length != 0) ? $(this).find('.post-meta').outerHeight(true) : 0;
height += ($(this).find('.post-content').length != 0) ? $(this).find('.post-content').outerHeight(true) : 0;
heights.push(height);
});
var max_height = Math.max.apply(Math, heights);
articles.each(function () {
$(this).height(max_height);
});
}
} else {
function pa_equalize_blog_post_height(blog) {
var articles = blog.find('article');
var heights = [];
var btnheights = [];
articles.each(function () {
var height = 0;
var btnheight = 0;
var basebtnmargin = 20;
height += ($(this).find('.et_pb_image_container, .et_main_video_container').length != 0) ? $(this).find('.et_pb_image_container, .et_main_video_container').outerHeight(true) : 0;
height += $(this).find('.entry-title').outerHeight(true);
height += $(this).find('.post-meta').outerHeight(true);
height += $(this).find('.post-content').outerHeight(true);
btnheight += ($(this).find('.et_pb_image_container, .et_main_video_container').length != 0) ? $(this).find('.et_pb_image_container, .et_main_video_container').outerHeight(true) : 0;
btnheight += $(this).find('.entry-title').outerHeight(true);
btnheight += $(this).find('.post-meta').outerHeight(true);
btnheight += $(this).find(".post-content p").outerHeight(true);
btnheight += basebtnmargin;
heights.push(height);
btnheights.push(btnheight);
});
var max_height = Math.max.apply(Math, heights);
var max_btn_height = Math.max.apply(Math, btnheights);
articles.each(function () {
$(this).height(max_height);
var eachheight = 0;
var eachbasebtnmargin = 20;
eachheight += ($(this).find('.et_pb_image_container, .et_main_video_container').length != 0) ? $(this).find('.et_pb_image_container, .et_main_video_container').outerHeight(true) : 0;
eachheight += $(this).find('.entry-title').outerHeight(true);
eachheight += $(this).find('.post-meta').outerHeight(true);
eachheight += $(this).find(".post-content p").outerHeight(true);
eachheight += eachbasebtnmargin;
var requiredbtnmargin = (max_btn_height - eachheight) + eachbasebtnmargin;
$(this).find(".more-link").css("margin-top", requiredbtnmargin + "px");
});
}
}
$(document).ready(function () {
$(window).resize(function () {
if ($(this).width() >= 768) {
$(".pa-blog-equal-height article").each(function () {
$(this).removeClass("pa-auto-height");
$(this).find(".more-link").removeClass("pa-auto-margin");
})
$('.pa-blog-equal-height').each(function () {
pa_equalize_blog_post_height($(this));
});
$('.pa-blog-equal-height').each(function () {
var pa_blog = $(this);
pa_equalize_blog_post_height(pa_blog);
var observer = new MutationObserver(function (mutations) {
pa_equalize_blog_post_height(pa_blog);
});
var config = {
subtree: true,
childList: true
};
observer.observe(pa_blog[0], config);
});
$(document).ajaxComplete(function () {
$('.pa-blog-equal-height').imagesLoaded().then(function () {
$('.pa-blog-equal-height').each(function () {
pa_equalize_blog_post_height($(this));
});
});
});
$.fn.imagesLoaded = function () {
var $imgs = this.find('img[src!=""]');
var dfds = [];
if (!$imgs.length) {
return $.Deferred().resolve().promise();
}
$imgs.each(function () {
var dfd = $.Deferred();
dfds.push(dfd);
var img = new Image();
img.onload = function () {
dfd.resolve();
};
img.onerror = function () {
dfd.resolve();
};
img.src = this.src;
});
return $.when.apply($, dfds);
}
} else {
$(".pa-blog-equal-height article").each(function () {
$(this).addClass("pa-auto-height");
$(this).find(".more-link").addClass("pa-auto-margin");
})
}
});
});
})(jQuery);
</script>
jQuery Code Explanation
I’ll do my best to explain what is happening in simple terms. You can totally skip this, but if you are wanting to understand it a little, read on.
Line 3
This line of code determines if you want to align the read more buttons to the bottom, or not. If this value if set to “true” then it will do some height calculations and align the buttons to the bottom, and if it is set to “false” then it will not.
Lines 5-71
This part of the code snippet controls the main equal height effect and is based on the true or false value in line 3. It includes two functions, one that equalizes the blog posts heights and aligns the read more button and one that just equalizes the blog heights. The effects will take place whenever the browser screen size changes.
If the value in line 3 is set to true, then the code will equalize both the blog post height and also align the read more button to the bottom.
If the value in line 3 is set to false, then the code will only equalize the blog post heights and not affect the button alignment.
In summary, this section of the code is doing the following things:
- It saves all the information about each of the blog posts in the Blog module.
- It processes the information and calculates the height of each post.
- It checks all of the heights and compares them to find the tallest one.
- It applies that same value to all the other posts.
- It adjusts the button top margin to make it aligned to the bottom (depending on true or false)
Lines 72-79
This part of the code snippet is used to limit the equal height affect to screen sizes that are only Desktop and Tablet devices 768px and above. There is no need to apply the effect on smaller screens since there is only one column of the blog module. If we did not add this part, it would look bad on Phone. This works by removing the two classes “pa-auto-height” and “pa-auto-margin” from the code so that the equal height effect does not apply on Phone.
Lines 85-100
This part of the code snippet is checking and observing each of the various elements of the individual posts inside the Blog module. If any slightest possible change occurs in any element of the module, it will run the function to equalize the heights or align the button margin.
Lines 102-136
This part of the code snippet is used to make sure that all of this works properly when ajax pagination is used. It checks to make sure the featured image is fully loaded and the ajax is finished running, then it applies the equal height function.
Lines 137-144
This part of the code snippet adds the custom CSS for screen sizes below 768px. This works by adding the two classes “pa-auto-height” and “pa-auto-margin” to the code so that we can adjust the equal height effect and button margin top on Phone.
Add The CSS Code
There are two snippets of CSS code that can be added next.
If you are using our free Divi child theme, place this snippet into the style.css file. Otherwise, place this in your Divi>Theme Options>Custom CSS code box. If you need help, check out our complete guide on Where To Add Custom Code In Divi.
.pa-blog-equal-height .pa-auto-height {
height: auto !important;
}
.pa-blog-equal-height .pa-auto-margin {
margin-top: 20px !important;
}
In the jQuery snippet, we have added the custom class “pa-auto-height” which we will use now in the first part of the CSS snippet to remove the equalize height effect for screens below 768px.
We have also added the custom class “pa-auto-margin” which we will use in the second part of the CSS snippet to remove the automatic margin change and to provide a static margin-top value to all the buttons below 768px instead. You can change the value of margin as per your liking.
NOTE: In the jQuery snippet, there are two variables defined as “basebtnmargin” and “eachbasebtnmargin.” Both the margins are set to the value of 20. By default, Divi adds the margin-top of 20px to the more link button. If you happen to have changed the margin of the button in the design settings to some custom value then you need to update that same value in both of these variables in the jQuery for accurate results.
Alternative Method B: CSS Grid
After posting this, some people asked why we did not just use CSS Grid for this. It’s a fair question, but we did consider it and feel the above JavaScript method is usually better. Allow me to explain.
Considerations Before Choosing This Method
There are actually many reasons for me, but you are welcome to hold a different opinion. But for my followers, I provide what I feel is the best solution overall for them based on many factors and considerations. In this case, those are as follows:
1. The CSS Grid method requires the Blog module to be set to the Fullwidth layout which has less/limited design settings in the module, which means users will be forced to add more CSS to replace the missing design settings, which they may not know how to do.
2. The CSS Grid method requires the Blog module to be set to the Fullwidth layout which is not compatible with all other tutorial tricks and snippets for the Grid layout and this could break their layout and design.
3. The CSS Grid method loses the live Visual Builder preview, which can confuse users, looks bad, and also makes the page extremely long when working in the builder and is overall pretty hectic.
4. The CSS Grid properties are not recognized by the Divi Custom CSS editors and they throw errors. Even though these are false positives, they can alarm users, make them feel like the code broken, or that they are doing something wrong
5. The CSS Grid method requires you to manually set the number of columns and rows for different screen sizes. This is not easy for beginners and will be very confusing.
How To Use The CSS Grid Method
You can proceed by adding the CSS class “pa-blog-equal-height” to the blog module just like we showed with the JS method above.
Make sure you set the Blog layout to Fullwidth instead of Grid.
After that, you can just add the following CSS to your website.
.pa-blog-equal-height .et_pb_ajax_pagination_container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 1fr;
column-gap: 0.8em
}
.pa-blog-equal-height .et_pb_ajax_pagination_container article {
padding: 1em;
border-radius: 10px;
border: 2px solid blue
}
.pa-blog-equal-height .et_pb_ajax_pagination_container div {
grid-column: 1 / -1;
}
.pa-blog-equal-height .et_pb_post div.post-content a.more-link {
position: absolute;
bottom: 30px
}
.pa-blog-equal-height .post-content {
padding-bottom: 4.5em;
}
@media all and (max-width: 980px) {
.pa-blog-equal-height .et_pb_ajax_pagination_container {
grid-template-columns: repeat(2, 1fr);
}
}
@media all and (max-width: 768px) {
.pa-blog-equal-height .et_pb_ajax_pagination_container {
grid-template-columns: repeat(1, 1fr);
}
}
Hello! I was curious, would this tutorial work for a custom ACF Archive Loop built with Divi Machine? It is essentially the same as a blog module, but the posts are Custom Fields. The module is the Archive Loop from Divi Machine. Please let me know, Thank you!
Hi Paul,
That would be completely different code, so that would need to be something provided by their plugin.
Fantastic as always team. I’ve used this a number of times now and it works a treat. The only issue I’m having is when I use it in a library item which is then added as a shortcode inside divi tabs module.
When swapping between the tabs, the query is made to show the posts and then they flicker between being all squashed up to their final correct display.
Has anyone ever experienced this and can recommend anything that can be done to either (a) load and organise the posts before showing them or (b) stop it from occurring in the first place?
Hi Tim!
The code is not optimized for such customization for now. We’ll look further and update it. To check the setup, can you please share the URL of the page?
Yes, we will also look to provide another guide for Blog module under different such modules.
Hi Hemant
Sorry I didn’t see your reply until now. No the site isn’t live yet so I can’t share a url with you. I didn’t want to create a support ticket as it’s not a bug per se just a display anomaly that could be exaggerated on slower connection speeds.
Essentially I think I’ll want to perform all the calculations for the equal height whilst hiding the blog module and then display it. I should be able to do this with a css visible call before and after I think.
Hey there, i a using the jquery script and had a problem when positioning the .post-meta absolute. The script made all blog post have a height as if the .post-meta was still there and considered its height. When i positioned the .post-meta relativ in web development tools, it matched perfectly.
Well i went the easy road for now and asked ChatGPT to give me a solution, and it seems to work, so i’ll leave it here.
(function ($) {
var pa_equalize_button_height = “true”;
if (pa_equalize_button_height == “false”) {
function pa_equalize_blog_post_height(blog) {
var articles = blog.find(“article”);
var heights = [];
articles.each(function () {
var height = 0;
height +=
$(this).find(“.et_pb_image_container, .et_main_video_container”)
.length != 0
? $(this)
.find(“.et_pb_image_container, .et_main_video_container”)
.outerHeight(true)
: 0;
height += $(this).find(“.entry-title”).outerHeight(true);
height +=
$(this).find(“.post-content”).length != 0
? $(this).find(“.post-content”).outerHeight(true)
: 0;
heights.push(height);
});
var max_height = Math.max.apply(Math, heights);
articles.each(function () {
$(this).height(max_height);
});
}
} else {
function pa_equalize_blog_post_height(blog) {
var articles = blog.find(“article”);
var heights = [];
var btnheights = [];
articles.each(function () {
var height = 0;
var btnheight = 0;
var basebtnmargin = 20;
height +=
$(this).find(“.et_pb_image_container, .et_main_video_container”)
.length != 0
? $(this)
.find(“.et_pb_image_container, .et_main_video_container”)
.outerHeight(true)
: 0;
height += $(this).find(“.entry-title”).outerHeight(true);
height += $(this).find(“.post-content”).outerHeight(true);
btnheight +=
$(this).find(“.et_pb_image_container, .et_main_video_container”)
.length != 0
? $(this)
.find(“.et_pb_image_container, .et_main_video_container”)
.outerHeight(true)
: 0;
btnheight += $(this).find(“.entry-title”).outerHeight(true);
btnheight += $(this).find(“.post-content p”).outerHeight(true);
btnheight += basebtnmargin;
heights.push(height);
btnheights.push(btnheight);
});
var max_height = Math.max.apply(Math, heights);
var max_btn_height = Math.max.apply(Math, btnheights);
articles.each(function () {
$(this).height(max_height);
var eachheight = 0;
var eachbasebtnmargin = 20;
eachheight +=
$(this).find(“.et_pb_image_container, .et_main_video_container”)
.length != 0
? $(this)
.find(“.et_pb_image_container, .et_main_video_container”)
.outerHeight(true)
: 0;
eachheight += $(this).find(“.entry-title”).outerHeight(true);
eachheight += $(this).find(“.post-content p”).outerHeight(true);
eachheight += eachbasebtnmargin;
var requiredbtnmargin = max_btn_height – eachheight + eachbasebtnmargin;
$(this)
.find(“.more-link”)
.css(“margin-top”, requiredbtnmargin + “px”);
});
}
}
$(document).ready(function () {
$(window).resize(function () {
if ($(this).width() >= 768) {
$(“.pa-blog-equal-height article”).each(function () {
$(this).removeClass(“pa-auto-height”);
$(this).find(“.more-link”).removeClass(“pa-auto-margin”);
});
$(“.pa-blog-equal-height”).each(function () {
pa_equalize_blog_post_height($(this));
});
$(“.pa-blog-equal-height”).each(function () {
var pa_blog = $(this);
pa_equalize_blog_post_height(pa_blog);
var observer = new MutationObserver(function (mutations) {
pa_equalize_blog_post_height(pa_blog);
});
var config = {
subtree: true,
childList: true,
};
observer.observe(pa_blog[0], config);
});
$(document).ajaxComplete(function () {
$(“.pa-blog-equal-height”)
.imagesLoaded()
.then(function () {
$(“.pa-blog-equal-height”).each(function () {
pa_equalize_blog_post_height($(this));
});
});
});
$.fn.imagesLoaded = function () {
var $imgs = this.find(‘img[src!=””]’);
var dfds = [];
if (!$imgs.length) {
return $.Deferred().resolve().promise();
}
$imgs.each(function () {
var dfd = $.Deferred();
dfds.push(dfd);
var img = new Image();
img.onload = function () {
dfd.resolve();
};
img.onerror = function () {
dfd.resolve();
};
img.src = this.src;
});
return $.when.apply($, dfds);
};
} else {
$(“.pa-blog-equal-height article”).each(function () {
$(this).addClass(“pa-auto-height”);
$(this).find(“.more-link”).addClass(“pa-auto-margin”);
});
}
});
});
})(jQuery);
Thanks for sharing the code here. Let me know if you need any further assistance.
Every problem I run into with Divi and Google an answer I always end up here! Thanks!
That’s awesome William! Be sure to let me know any future ideas when you don’t show up here!
Please ignore my last comment. I found the issue, I didn’t realise that we need to add the CSS code at the very bottom of the post. I thought this was just for the 2nd method, but this appears to enable to “read more” to line up for the 1st method as well. Also, this doesn’t work if enough elements are selected to show, for some reason. So I selected one then hid it with CSS, and it then seemed to work!
Hi Corine!
I’m not able to access the page due to coming soon mode enabled. Can you please disable it so that I can check further? Also, can you please check if there is any JS error in console?
Hi Nelson – I can’t seem to get the Read More to align at the bottom, and I also can’t seem to find where I can adjust the padding of the blogs. I was able to get the Read More to align by adding position: absolute, but that puts them outside of the background of the blog. Any ideas on what I need to address this?
Here’s what I’m working on if you care to have a look. It’s the 3-blog grid toward the bottom of the page.
https://hballpdev.wpengine.com/
Hello Sean!
I looked at the website. In both the desktop and mobile views, it works fine.
On the tablet view, only I can see the issue. Could you please go to the WordPress Dashboard > Divi > Theme Options > Custom CSS Panel and place the code given below :
@media (min-width: 768px) and (max-width: 980px){
.pa-blog-equal-height .et_pb_ajax_pagination_container article {
padding: 1em !important;
position: relative !important;
}
.pa-blog-equal-height .et_pb_ajax_pagination_container div {
grid-column: 1 / -1 !important;
}
.pa-blog-equal-height .et_pb_post div.post-content a.more-link {
position: absolute !important;
bottom: 10px !important;
}
.pa-blog-equal-height .post-content {
padding-bottom: 4.5em !important;
}
}
Let me know how it goes.
Hi Nelson – I needed to add this to bottom align the read mores:
@media screen and (min-width: 981px) {
.et_pb_module.et_pb_blog_grid_wrapper .more-link {
position: absolute;
bottom: 31px;
left: 0;
right: 0;
width: 16vw;
margin: auto;
}
.et_pb_module.et_pb_blog_grid_wrapper .et_pb_post {
position: relative;
}
.et_pb_module.et_pb_blog_grid_wrapper .post-content {
padding-bottom: 80px;
}
}
Hi, Great tutorial as always, but I can’t quite get it to work. I created a template for news articles and copied the CSS, Javascript, and CSS code to their appropriate places as described in the tutorial, but it appears that only the blog heights are being made equal. The buttons are not lining up as expected, even though line 3 of the javascript code is set to ‘true’.
Additionally, on tablet versions, there is a larger gap between blogs 1 and 2 than blogs 2 and 3.
https://myevopt.com/mbta-and-enel-x-selects-microgrid-labs-for-bus-electrification/ under “RECENT EVOPT NEWS”
Hi Reed,
Thank you for addressing the issue. We will check where the issue is coming from and will get back on this.
Hi Nelson,
Very useful snippet thanks!
It works for me except that the read more button does not align to the bottom whether line three is set to true or false.
I don’t know enough about JS to figure out what could be wrong though.
At first I used a code module on the page that has my blog module for the JS and I added the CSS to my page CSS, so not using the integration or Divi’s theme options CSS.
Then I tried it your recommended way and I still can’t get the read more to align to the bottom of the post block.
Any idea as to why I would be struggling with this?
Hi Hurri
Could you please share the URL of the page where you are facing this issue for me to investigate further?
Hi Hemant,
I have the same issue as Hurri, my buttons do not align at the bottom.
https://uwin.sybergrupe.co.za/uwin-blog/
Please can you assist?
Hi Amelia,
Thank you for addressing the issue. We will check where this issue is coming from and get back on this.