Skip to content

Instantly share code, notes, and snippets.

@c6p
Last active June 15, 2025 22:19
Show Gist options
  • Select an option

  • Save c6p/463892bb243f611f2a3cfa4268c6435e to your computer and use it in GitHub Desktop.

Select an option

Save c6p/463892bb243f611f2a3cfa4268c6435e to your computer and use it in GitHub Desktop.
Reddit Multi Column
// ==UserScript==
// @name Reddit Multi Column
// @namespace https://gist.github.com/c6p/463892bb243f611f2a3cfa4268c6435e
// @version 0.2.6
// @description Multi column layout for reddit redesign
// @author Can Altıparmak
// @homepageURL https://gist.github.com/c6p/463892bb243f611f2a3cfa4268c6435e
// @match https://www.reddit.com/*
// @match https://new.reddit.com/*
// @grant none
// @downloadURL https://update.greasyfork.org/scripts/371490/Reddit%20Multi%20Column.user.js
// @updateURL https://update.greasyfork.org/scripts/371490/Reddit%20Multi%20Column.meta.js
// ==/UserScript==
/* jshint esversion: 6 */
(function() {
'use strict';
const MIN_WIDTH = 400;
const COLUMNS = 4;
let columns = COLUMNS;
let cleanup = null;
let parent = null;
const cardIcon = () => document?.querySelector('shreddit-sort-dropdown[header-text="View"]')?.shadowRoot?.querySelector('svg');
const shouldClean =(icon) => icon === undefined ? false : icon.getAttribute('icon-name') !== "view-card-outline";
cleanup = shouldClean()
let postMap = new Map()
const indexOfSmallest = function (a) {
let lowest = 0;
for (let i = 1; i<a.length; i++) {
if (a[i] < (a[lowest]-1)) lowest = i;
}
return lowest;
};
const makeLayout = function(changes=[]) {
if (cleanup) return;
if (!parent) return;
if (parent.style.position !== "relative") {
document.querySelector("main").style.maxWidth = "100%";
const mainContainer = document.querySelector("div.main-container");
mainContainer.className = [...mainContainer.classList].filter(c => !c.includes(":grid-cols-")).join(" ") // make wide
document.querySelector("div.subgrid-container").classList.remove("m:w-[1120px]") // make wide
document.getElementById("right-sidebar-container").style.display = "none" // hide sidebar
parent.style.position = "relative"
}
const cols = Math.floor(parent.offsetWidth / MIN_WIDTH);
columns = cols;
const WIDTH = Math.floor((100-columns)/columns);
const nodes = [...parent.querySelectorAll("article, shreddit-ad-post, faceplate-partial").values()]
for (const article of nodes) {
const key = article.ariaLabel
if (key === null) /* faceplate-partial */ {
} else if (key in postMap) {
const post = postMap[key]
if (post.height !== article.offsetHeight) {
post.height = article.offsetHeight
}
} else {
postMap.set(key, {height:article.offsetHeight, col:0, top:0})
}
}
let tops = Array(columns).fill(0);
for (const post of postMap.values()) {
post.col = indexOfSmallest(tops)
post.top = tops[post.col]
tops[post.col] += post.height
}
const height = Math.max(...tops)
if (height) {
parent.style.height = height + 500 + "px"
}
for (const article of nodes) {
const key = article.ariaLabel
const {col, top} = postMap.get(key) ?? {col:0, top:tops[0]}
article.setAttribute("style", cleanup ? "" : `position:absolute; width:${WIDTH}%; top:${top}px; left:${col*(WIDTH+1)}%`)
}
for (const batch of parent.querySelectorAll("faceplate-batch").values()) {
if (!batch.style.height) {
batch.style.height = [...batch.childNodes].reduce((height,c) => height + c.clientHeight, 0) + "px"
}
}
};
const setLayout = function(changes, observer) {
const c = shouldClean(cardIcon());
if (c !== cleanup) {
cleanup = c;
window.requestAnimationFrame(makeLayout)
}
};
const requestLayout = () => window.requestAnimationFrame(makeLayout)
const pageChange = new MutationObserver(requestLayout);
window.addEventListener('resize', requestLayout);
window.addEventListener('scrollend', requestLayout);
const layoutSwitch = new MutationObserver(setLayout);
const watch = function(changes, observer) {
postMap = new Map()
parent = document.querySelector("article + hr + faceplate-partial").parentNode
if (parent === null) return;
pageChange.observe(parent, {childList: true});
const timeout = setTimeout(() => {
const icon = cardIcon();
if (icon !== undefined) {
clearTimeout(timeout);
layoutSwitch.observe(icon, {attributes: true});
}
})
window.requestAnimationFrame(makeLayout);
};
const apply = new MutationObserver(watch);
const app = document.querySelector("shreddit-app")
apply.observe(app, {attributes: true});
watch();
})();
@Krokette
Copy link

Krokette commented Jun 12, 2024

@c6p Awesome ! Thank you, the design is pretty neat ! And the performance seems to be better than before ♥

@lolDayus
Copy link

lolDayus commented Jul 2, 2024

Hey this might just be a "me" thing but this is so close to doing what I want BUT I'm having this issue where, as I scroll down my feed, each post will swap places around on the screen so that one second a post is in the right column and then the next it's in center (I have 3 columns). This gets confusing very quickly with how often they switch places, in that I'll see a post I want to click but by the time the page "settles" it'll be shifted to a different part of the page. any ideas?

@drhouse
Copy link

drhouse commented Jul 2, 2024

as I scroll down my feed, each post will swap places around on the screen so that one second a post is in the right column and then the next it's in center (I have 3 columns).

+1 having same issue

@c6p
Copy link
Author

c6p commented Jul 3, 2024

@lolDayus @drhouse noted. While threads are coming, it re-layouts. But since some thread images are not yet loaded, their height changes. So does their position.

When I have the time, I'm going to try to wait until a thread's content is loaded, to make the layout more stable. Or just keep their assigned rows and columns, even if it makes some columns longer than others.

@c6p
Copy link
Author

c6p commented Sep 11, 2024

v0.2.1released

  • Add new.reddit.com
  • Fix left sidebar scrolling
  • Fix article jumpiness

@c6p
Copy link
Author

c6p commented Sep 12, 2024

v0.2.2 released

  • Fix subreddits that use faceplate-batch elements to virtualize loaded articles

@c6p
Copy link
Author

c6p commented Sep 13, 2024

v0.2.3

  • Fix empty page due to reddit hiding too far away articles
    • Fixed: unbalanced columns

@Archer2011
Copy link

Doesn't work anymore

@thepick
Copy link

thepick commented Jan 12, 2025

Doesn't work anymore

Yeah, I think there was an update on Reddit's end. It doesn't work across all browsers now.

@c6p
Copy link
Author

c6p commented Jan 12, 2025

v0.2.4

  • Fix: update main element type

@DannL444
Copy link

DannL444 commented Feb 5, 2025

It stopped working

@thepick
Copy link

thepick commented Feb 6, 2025

It seems to be working well in Chrome-based browsers now, but not on Firefox-based browsers. Switching from Violentmonkey to Tampermonkey didn't help.

@c6p
Copy link
Author

c6p commented Apr 8, 2025

v0.2.5

  • Fix: filter-out :grid-col- classes from main-container to make it wide

@c6p
Copy link
Author

c6p commented Apr 8, 2025

v0.2.6

  • Fix: ads breaking column layout

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment