Most marketing sites bury blog content in a 3×3 grid at the bottom of the homepage — small card previews, static layout, zero incentive to scroll. Velocity X went sideways: a horizontal scroll strip with 6 blog teasers that you flick through with your mouse wheel (desktop) or swipe (mobile), native CSS scroll-snap snapping each post to the center, no library dependencies, no JavaScript animations. The strip reads like "here's what we're writing about right now" instead of "here's our archive." On mobile, it's a native gesture users understand instantly. On desktop, it's a novelty that catches eyes. This is how it works.
Why Horizontal Scroll Converts Better Than Grids
A 3×3 grid is passive. You land on the page, your eye sweeps across 9 card titles, you either click one or you bounce. Grids are information retrieval tools — great for archives, terrible for discovery. A horizontal scroll strip is a gesture interface. Your fingers (mobile) or mouse wheel (desktop) control the flow; the browser snaps each post to the center as you move; the motion itself becomes part of the experience. The strip also forces post ordering — "these 6 are the new ones" — whereas a grid can feel like an endless scroll of archive clutter. Plus, horizontal layouts use screen width more efficiently on mobile; you get a full card preview instead of a cramped one-third of a card squeezed between padding.
The Markup: Flex Container with Scroll-Snap
The container is a flex row with `overflow-x: auto` and `scroll-behavior: smooth` so scrolling feels buttery. Each child card is `flex-shrink-0` and a fixed width (let's say `w-80`, or 320px) so cards don't compress. The container gets `scroll-snap-type: x mandatory` — mandatory means the browser snaps aggressively to each card, no coasting past. Each card gets `scroll-snap-align: center` so it snaps to the horizontal center of the viewport instead of the left edge. Hide the scrollbar with `scrollbar-width: none` (Firefox) and `::-webkit-scrollbar { display: none; }` (Chrome/Safari) because a visible scrollbar on a snap container looks janky.
{`.blog-slider {
display: flex;
overflow-x: auto;
scroll-behavior: smooth;
scroll-snap-type: x mandatory;
gap: 1.5rem;
padding: 1rem;
scrollbar-width: none;
}
.blog-slider::-webkit-scrollbar {
display: none;
}
.blog-card {
flex-shrink: 0;
width: 20rem;
scroll-snap-align: center;
scroll-snap-stop: always;
}`}
Keyboard Navigation: Arrow Keys to Scroll
Desktop users don't expect to scroll with a mouse wheel on a snap container — the gesture feels fragile. Instead, capture left/right arrow key presses and programmatically scroll the container. When the user hits the right arrow, calculate `nextPos = container.scrollLeft + cardWidth + gap`, then call `container.scrollTo({ left: nextPos, behavior: 'smooth' })`. Ditto for the left arrow with `nextPos = container.scrollLeft - cardWidth - gap`. If you hit the start, don't scroll left; if you hit the end, don't scroll right. This gives keyboard users (and accessibility auditors) a native feel without JavaScript animations.
{`const slider = document.querySelector('.blog-slider');
const cardWidth = 320;
const gap = 24;
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight') {
slider.scrollBy({ left: cardWidth + gap, behavior: 'smooth' });
}
if (e.key === 'ArrowLeft') {
slider.scrollBy({ left: -(cardWidth + gap), behavior: 'smooth' });
}
});`}
Mobile: Swipe Gesture and Touch-Friendly Spacing
On mobile, the scroll-snap behavior kicks in automatically — users swipe left/right with their thumb and the browser snaps to the next card. No JavaScript needed. But you do need to be careful with card width. On a 375px screen, a 320px card looks massive and blocks the next card entirely; users won't realize they can scroll. Instead, on mobile, set card width to `w-72` (288px) and add a sliver of the next card peeking behind — about 40–60px. This gives a visual hint: "there's more to the right." Desktop can stay at full width since keyboard nav and mouse wheel are already discoverable cues.
Frequently Asked Questions
Can I add previous/next arrow buttons?
Yes, but resist the urge. The strip itself is the UI — arrows add visual clutter and duplicate keyboard nav. If your mobile users can't discover the swipe gesture, that's a design signal that your card design or peeking width isn't working yet. Fix the visual hint instead of adding chrome.
How many cards should I show?
Six is the sweet spot. Five feels incomplete; seven starts to overwhelm. Each card should be a complete story — title, category tag, excerpt, read-time, cover image — so dense that you can't fit more than 6 without the container feeling cramped.
Should the slider autoplay (loop every 8 seconds)?
No. Autoplay is a dark pattern on homepage sliders — it yanks focus away from the user's reading and triggers seizure warnings for photosensitive visitors. Let users control the pace. If your blog teasers are compelling, they'll scroll. If they're not, autoplay won't save them.
What if a blog post title wraps to two lines?
That's fine — it's a card preview, not a heading. Use `line-clamp-2` to cap the title at two lines, then `line-clamp-3` for the excerpt. The card height will grow slightly, but the scroll-snap behavior will still snap correctly because we're snapping to the card center, not to a fixed pixel height.
Can I link the whole card to the post, or just the title?
How do I prevent the slider from scrolling horizontally when I scroll vertically on mobile?
You don't. The browser handles it — `overflow-x: auto` means horizontal scroll only if the user explicitly swipes horizontally. Vertical scroll works independently. This is native behavior and requires zero code.
The Bottom Line
A blog grid is storage. A horizontal scroll strip is a storytelling device. Velocity X treats recent posts as a curated stream instead of an archive, making the homepage feel alive and giving readers a reason to stick around. Wrap a flex container in `scroll-snap-type: x mandatory`, add arrow-key navigation with 4 lines of JavaScript, and ship. Your homepage blog section just went from an obligation to a conversion point. See the full pattern in the Velocity home layout at the TechStack deep-dive, then deploy your own fork at /pricing.