One of the biggest challenges in building a random post section for static sites is keeping it lightweight, flexible, and SEO-friendly. If your randomization relies solely on client-side JavaScript, you may lose crawlability. On the other hand, hardcoding random posts can make your site feel repetitive. This article explores how to use JSON data and lazy loading together to build a smarter, faster, and fully responsive random post section in Jekyll.
Why JSON-Based Random Posts Work Better
When you separate content data (like titles, URLs, and images) into JSON, you get a more modular structure. Jekyll can build this data automatically using _data or collection exports. You can then pull a random subset each time the site builds or even on the client side, with minimal code.
- Modular content: JSON allows you to reuse post data anywhere on your site.
- Faster builds: Pre-rendered data reduces Liquid loops on large sites.
- Better SEO: You can still output structured HTML from static data.
In other words, this approach combines the flexibility of data files with the performance of static HTML.
Step 1: Generate a JSON Data File of All Posts
Create a new file inside your Jekyll site at _data/posts.json or _site/posts.json depending on your workflow. You can populate it dynamically with Liquid as shown below.
[
{% for post in site.posts %}
{
"title": "{{ post.title | escape }}",
"url": "{{ post.url | relative_url }}",
"image": "{{ post.image | default: '/photo/default.png' }}",
"excerpt": "{{ post.excerpt | strip_html | strip_newlines | truncate: 120 }}"
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
This JSON file will serve as the database for your random post feature. Jekyll regenerates it during each build, ensuring it always reflects your latest content.
Step 2: Display Random Posts Using Liquid
You can then use Liquid filters to sample random posts directly from the JSON file:
{% assign posts_data = site.data.posts | sample: 6 %}
<section class="random-grid">
{% for post in posts_data %}
<a href="{{ post.url }}" class="random-item">
<img src="{{ post.image }}" alt="{{ post.title }}" loading="lazy">
<h4>{{ post.title }}</h4>
<p>{{ post.excerpt }}</p>
</a>
{% endfor %}
</section>
The sample filter ensures each build shows a different set of random posts. Since it’s static, Google can fully index and crawl all content variations over time.
Step 3: Add Lazy Loading for Speed
Lazy loading defers the loading of images until they are visible on the screen. This can dramatically improve your page load times, especially on mobile devices.
Simple Lazy Load Example
<img src="" alt="" loading="lazy" />
This single attribute (loading="lazy") is enough for modern browsers. You can also implement JavaScript fallback for older browsers if needed.
Improving Cumulative Layout Shift (CLS)
To avoid content jumping while images load, always specify width and height attributes, or use aspect-ratio containers:
.random-item img {
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
border-radius: 10px;
}
This ensures that your layout remains stable as images appear, which improves user experience and your Core Web Vitals score — an important SEO factor.
Step 4: Make It Fully Responsive
Combine CSS Grid with flexible breakpoints so your random post section looks balanced on every screen.
.random-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
padding: 1rem;
}
.random-item {
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
transition: transform 0.2s ease;
}
.random-item:hover {
transform: translateY(-4px);
}
These small touches — spacing, shadows, and hover effects — make your blog feel professional and cohesive without additional frameworks.
Step 5: SEO and Crawlability Best Practices
Because Jekyll generates static HTML, your random posts are already crawlable. Still, there are a few tricks to make sure Google understands them correctly.
- Use
altattributes and descriptive filenames for images. - Use semantic tags such as
<section>and<article>. - Add internal linking relevance by grouping related tags or categories.
- Include JSON-LD schema markup for improved understanding.
Example: Random Post Schema
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [
{% for post in posts_data %}
{
"@type": "ListItem",
"position": {{ forloop.index }},
"url": "{{ post.url | absolute_url }}"
}{% if forloop.last == false %},{% endif %}
{% endfor %}
]
}
</script>
This structured data helps search engines treat your random post grid as an organized set of related articles rather than unrelated links.
Step 6: Optional – Random Posts via JSON Fetch
If you want more dynamic randomization (e.g., different posts on each page load), you can use lightweight client-side JavaScript to fetch the same JSON file and shuffle it in the browser. However, you should always output fallback HTML in the Liquid template to maintain SEO value.
<script>
fetch('/posts.json')
.then(response => response.json())
.then(data => {
const shuffled = data.sort(() => 0.5 - Math.random()).slice(0, 5);
const container = document.querySelector('.random-grid');
shuffled.forEach(post => {
const item = document.createElement('a');
item.href = post.url;
item.className = 'random-item';
item.innerHTML = `
<img src="${post.image}" alt="${post.title}" loading="lazy">
<h4>${post.title}</h4>
`;
container.appendChild(item);
});
});
</script>
This hybrid approach ensures that your static pages remain SEO-friendly while adding dynamic user experience on reload.
Performance Metrics You Should Watch
| Metric | Goal | Improvement Method |
|---|---|---|
| Largest Contentful Paint (LCP) | < 2.5s | Use lazy loading, optimize images |
| First Input Delay (FID) | < 100ms | Minimize JS execution |
| Cumulative Layout Shift (CLS) | < 0.1 | Use fixed image aspect ratios |
Final Thoughts
By combining JSON data, lazy loading, and responsive design, your Jekyll random post section becomes both elegant and efficient. You reduce redundant code, enhance mobile usability, and maintain a high SEO value through pre-rendered, crawlable HTML. This blend of data-driven structure and minimalistic design is exactly what modern static blogs need to stay fast, smart, and discoverable.
In short, random posts don’t have to be chaotic — with the right setup, they can become a strategic part of your content ecosystem.