Skip to content

Instantly share code, notes, and snippets.

@christippett
Last active July 18, 2024 15:34
Show Gist options
  • Save christippett/5097af0ea59c867c4578996350933776 to your computer and use it in GitHub Desktop.
Save christippett/5097af0ea59c867c4578996350933776 to your computer and use it in GitHub Desktop.
Hacker News Stylesheet

Hacker News userstyle

A modern re-styling of the Hacker News front page, including automatic light/dark mode.

Install directly with Stylus

Screenshots

HN 1

HN 2

/* ==UserStyle==
@name Hacker's New CSS
@author Chris Tippett <git@christippett.dev> (https://christippett.dev)
@description A modern retake on the classic Hacker News design.
@version 2024.05.24
@namespace @christippett
@homepageURL https://github.com/christippett
@supportURL https://gist.github.com/christippett/5097af0ea59c867c4578996350933776/
@updateURL https://gist.github.com/christippett/5097af0ea59c867c4578996350933776/raw/hn.user.css
@license MIT
@preprocessor uso
==/UserStyle== */
@-moz-document domain("news.ycombinator.com") {
:root {
color-scheme: light dark;
}
html {
--font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
--primary: #ff6600;
--primary-alt: #c8c5c5;
--text-color: #4b4b4b;
--text-color-alt: #828282;
--table-bg: #fcfffa;
--body-bg: #f6f6ef;
--border-color: #f6f6ef;
--border-radius: 3px;
--smaller: 0.8em;
--content: 0.96rem;
font-size: 14px;
color: var(--text-color);
}
@media (prefers-color-scheme: dark) {
html {
--text-color: white;
--text-color-alt: #c3c3c3;
--primary-alt: #828282;
--border-color: #1b1b1c;
--table-bg: #232323;
--body-bg: #1b1b1c;
}
}
* {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-border-horizontal-spacing: 0;
-webkit-border-vertical-spacing: 0;
font-family: var(--font-family) !important;
}
body {
padding: 20px 40px 50px;
background-color: var(--body-bg);
}
@media (max-width: 750px) {
body {
padding: 0;
}
}
body > center {
position: relative;
}
table {
width: 100%;
}
td {
font-size: 1rem;
color: var(--text-color);
}
br {
padding: 0;
}
/* hide consecutive <br> tags */
br + br {
display: none;
}
i {
font-size: calc(var(--content) / 1.1);
margin: 0 0.25em;
}
font[size] {
font-size: var(--smaller);
}
/* help text on profile & post submission pages */
font[size="2"],
html[op="submit"] form > table tr:last-child td {
font-size: var(--smaller);
color: var(--text-color-alt);
font-style: italic;
}
a,
a:link {
color: var(--text-color);
text-underline-offset: 2px;
text-decoration-color: var(--text-color-alt);
}
a:visited {
color: var(--text-color-alt);
}
form {
padding: 0;
max-width: 700px;
}
textarea,
input,
select,
a.morelink {
max-width: 90%;
border: none;
font-size: var(--smaller);
border-radius: var(--border-radius);
color: var(--text-color-alt) !important;
padding: calc(var(--smaller) / 2) var(--smaller);
box-shadow: inset 0 0 1px var(--primary-alt);
outline: 1px solid var(--border-color);
background-color: var(--body-bg);
}
textarea + a {
padding: 0.25rem;
}
textarea:focus,
input:not([type="submit"]):focus {
background-color: var(--table-bg);
}
/* button style */
input[type="submit"],
a.morelink {
cursor: pointer;
margin: 0.75rem 0;
display: inline-flex;
align-items: center;
letter-spacing: 0.2px;
text-transform: capitalize;
text-decoration: none !important;
}
form input[type="submit"]:hover,
a.morelink:hover {
text-decoration: underline !important;
}
input[name="q"] {
background: var(--table-bg);
}
/* --- LOGIN / CREATE ACCOUNT --*/
html:not([op]) body {
background-color: var(--table-bg);
}
html:not([op]) b {
display: inline-block;
margin-top: 1rem;
}
a[href="forgot"] {
display: inline-block;
margin-top: -1rem;
padding: 0.75rem;
color: var(--text-color-alt) !important;
font-style: italic;
text-decoration: none;
font-size: var(--smaller);
}
/* --- USER PROFILE --- */
#pagespace + tr > td:empty {
display: none;
}
form > table td {
padding: 0.25rem;
width: 100%;
}
/* field labels */
form > table td:first-child {
width: auto;
min-width: 120px;
padding-right: 1rem;
font-size: 0.75rem;
font-weight: 500;
text-transform: uppercase;
}
/* --- TABLE / LAYOUT --- */
#hnmain {
max-width: 900px;
overflow: hidden;
background: var(--table-bg);
border-radius: var(--border-radius);
box-shadow: 0 0 1px var(--primary-alt);
}
/* only add padding for parent table cells */
#hnmain > tbody > tr:not(:first-child) > td {
padding: 1rem;
width: 100%;
}
#hnmain tr:not(.spacer):empty {
display: none;
}
.morespace {
display: none;
}
.morespace + tr td {
padding: 0.5rem 0;
}
.spacer {
height: 1rem !important;
}
/* error message shown if not logged in when making comment */
html[op="x"] #hnmain > tbody > tr:last-child td {
color: transparent;
}
/* --- HEADER --- */
td[bgcolor="#ff6600"] {
background: linear-gradient(#ff6600, #eb5f00);
}
td[bgcolor="#000000"] {
background: linear-gradient(#111111, #2c2b2a);
}
#hnmain > tbody > tr:first-child > td:first-child {
padding: 0.4rem 0.6rem;
}
#hnmain > tbody > tr:first-child > td:first-child > table td {
height: auto !important;
line-height: 1 !important;
vertical-align: middle;
}
.pagetop {
color: #fff;
line-height: 1;
font-weight: 500;
font-size: var(--smaller);
padding: 0 0.5rem;
}
.pagetop font {
font-weight: bold;
}
.pagetop a,
.pagetop a:visited {
color: #fff;
line-height: 1rem;
}
.pagetop a:hover,
.sitebit a:hover {
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
}
/* 'hacker news' title */
.hnname {
margin-right: 0.5rem;
text-transform: uppercase;
font-size: 1.1rem;
font-weight: 800;
}
.hnname a:hover {
text-decoration: none !important;
}
#me {
font-weight: 600;
font-style: italic;
}
#karma {
font-size: var(--smaller);
line-height: 1rem;
display: inline-flex;
align-items: center;
cursor: grabbing;
}
/* can't remember what this was supposed to hide */
span:not([class])[id]:not(#karma) {
display: none;
}
/* ---- FRONT PAGE ---- */
.sitebit a:hover {
text-decoration-color: var(--primary);
}
/* stories from [Month] [Day], [Year] */
#pagespace + tr > td > div {
padding: 0 0 1rem;
margin: 0 0 1rem !important;
border-bottom: 1px solid var(--primary-alt);
font-size: var(--content);
font-weight: 500;
}
#pagespace + tr > td > div > div {
font-style: italic;
font-size: var(--smaller);
margin-top: 0.25rem !important;
}
.hnmore a,
.hnmore a:link,
.hnmore a:visited {
color: var(--text-color-alt);
}
/* --- ARTICLE --- */
.rank {
color: var(--text-color-alt);
font-weight: 500;
}
.title {
font-size: 1rem;
overflow: unset;
}
.title .titleline {
width: 100%;
font-weight: 500;
display: flex;
gap: 1rem;
justify-content: space-between;
align-items: baseline;
}
/* transparent parantheses around url */
.titleline .sitebit {
color: transparent;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}
.subtext span.subline,
.subtext span.subline a {
display: inline-block;
color: var(--text-color-alt);
font-size: 0.9rem;
padding: 2px 0;
}
.subtext .score {
color: var(--text-color-alt);
font-weight: 600;
border-radius: var(--border-radius);
}
/* ---- COMMENTS ---- */
/* text color */
.c00,
.c00 a:link {
color: var(--text-color);
text-decoration-color: var(--primary-alt);
}
table.itemlist,
table.fatitem,
table.comment-tree {
position: relative;
}
html:not([op="reply"]) table.fatitem {
padding-bottom: 0.75rem;
margin-bottom: 0.75rem;
border-bottom: 1px solid var(--primary-alt);
}
td.default {
width: 100%;
position: relative;
padding: 0;
font-size: var(--content);
}
.default p {
margin-top: var(--smaller);
}
.toptext,
form[action="comment"] {
padding: 1rem 0;
margin: 1em 0 0;
}
.toptext {
font-size: var(--content);
margin-bottom: -1rem;
}
/* comment: header/author/etc */
.comhead {
font-size: var(--smaller);
color: var(--text-color-alt);
}
a.hnuser {
font-weight: 500;
}
.comment {
font-size: var(--content);
line-height: 1.4;
color: var(--text-color);
margin: 0 0 0.5rem;
padding: 0.4rem 0.8rem;
}
.reply {
margin-top: 0.8rem;
text-transform: capitalize;
}
.reply a,
.reply a:link,
.reply a:visited {
color: var(--text-color-alt);
text-decoration-color: var(--primary-alt);
}
.reply u {
text-decoration: none;
}
.navs {
margin-left: 0.25ch;
display: inline-flex;
align-items: center;
gap: 0.75ch;
}
a.togg {
padding: 0.1em 0.2em;
font-weight: bold;
border-radius: var(--border-radius);
/*background-color: red;*/
}
/* --- UPVOTE/DOWNVOTE LINKS --- */
.votelinks {
position: relative;
text-align: center;
padding: 0;
--icon-size: 1rem;
}
.votelinks center {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: var(--table-bg);
padding: 0 0.25rem;
}
/* self-post indicator */
.votelinks center img,
.votelinks center br {
display: none;
}
.votelinks center font {
height: 1rem;
width: 1rem;
color: transparent;
}
.votelinks center font:before {
content: "★";
color: var(--primary);
display: inline-block;
font-size: 0.8em;
}
.votearrow {
background: none;
margin: 0;
width: auto;
height: auto;
transform: unset !important;
}
.votearrow:before {
width: 1rem;
height: 1rem;
padding: 1px;
display: block;
line-height: 1;
font-size: 0.9em;
text-align: center;
border-radius: 50%;
color: var(--text-color-alt);
transition: transform 100ms ease-in-out;
}
.votearrow[title="upvote"]:before {
content: "↑";
}
.votearrow[title="downvote"]:before {
content: "↓";
}
a.clicky:hover > .votearrow:before,
a.clicky.nosee > .votearrow:before {
color: var(--primary);
}
a.clicky:hover > .votearrow:before {
transform: scale(1.2);
}
.votelinks a.nosee {
visibility: visible;
font-weight: bold;
}
/* ---- FOOTER ---- */
#hnmain > tbody > tr:has(.yclinks) {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
transform: translateY(100%);
z-index: 99;
padding: 1rem 0;
}
/* footer: hide orange horizontal bar above footer */
img[src="s.gif"] + table {
display: none;
}
.yclinks {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
color: var(--text-color-alt);
margin: 0.5rem 0;
padding: 0.5rem 1rem;
width: max-content;
border-radius: calc(var(--border-radius) * 2);
}
.yclinks a:link {
color: var(--text-color-alt);
font-size: 0.9rem;
}
.yclinks a:hover {
text-decoration: underline;
text-underline-offset: 2px;
text-decoration-thickness: 1px;
text-decoration-color: var(--primary);
}
form[action="//hn.algolia.com/"]
{
color: var(--text-color-alt);
font-size: var(--smaller);
display: flex;
align-items: center;
justify-content: center;
gap: 1ch;
}
/* yc application notice */
center > a[href$="ycombinator.com/apply/"] {
color: var(--text-color-alt);
text-decoration: underline;
text-underline-offset: 2px;
font-weight: 500;
}
}
@gingerbeardman
Copy link

So I'm abandoning Lobsters, for all the reasons above. Just far too unfriendly and nobody needs that in 2023.

My new favourite place is Tildes.net which is another "Hacker News clone" but with much friendlier interface, onboarding, users and range of topics. Invites are quick, free and easy by posting at https://www.reddit.com/r/tildes/ at the time of writing this thread. Once invited you login and post new links through the sidebar.

@christippett
Copy link
Author

Interesting, I wonder if the name has any correlation with the Linux tilde communities that are out there (tilde.club, tilde.town are the two I'm familiar with).

@nervous-inhuman
Copy link

Hey, it seems like the Userstyle has stopped working - starting today, at least for me.
Using the Userstyle directly from this gist, fwiw.

@pmarreck
Copy link

pmarreck commented Sep 2, 2023

Since I got banned by Reddit across everything thanks to "intelligence-free and thus sometimes accidentally too punitive fingerprinting", I can't even join "tildes" apparently. Is there another way to join?

@pmarreck
Copy link

pmarreck commented Sep 2, 2023

(actually, I applied to tilde.town via SSH. Which is an amazing user filter. LOL)

@christippett
Copy link
Author

Hey, it seems like the Userstyle has stopped working - starting today, at least for me.
Using the Userstyle directly from this gist, fwiw.

What extension are you using to apply the CSS? The gist hasn't been updated for awhile and it's still working fine for me on both Safari and Firefox.

@nervous-inhuman
Copy link

Hey, it seems like the Userstyle has stopped working - starting today, at least for me.
Using the Userstyle directly from this gist, fwiw.

What extension are you using to apply the CSS? The gist hasn't been updated for awhile and it's still working fine for me on both Safari and Firefox.

Stylus with Firefox, oddly enough, it seems to have fixed itself, but prior to that, it just wasn't getting applied at all.

@nervous-inhuman
Copy link

And it's back to not being applied. I'm clueless as to what's happening.

@christippett
Copy link
Author

And it's back to not being applied. I'm clueless as to what's happening.

When you next notice it not working, can you dump the HTML source here so I can take a look? Maybe there's an overly specific CSS selector that's not applying.

@nervous-inhuman
Copy link

And it's back to not being applied. I'm clueless as to what's happening.

When you next notice it not working, can you dump the HTML source here so I can take a look? Maybe there's an overly specific CSS selector that's not applying.

Yeah, I probably should've started with that, sorry.

Here it is: https://gist.github.com/nervous-inhuman/1e1f470ab7a108a8e4f759bcb77391ca

@christippett
Copy link
Author

christippett commented Sep 29, 2023

FYI I've been playing around with the style, mostly around the layout of items and the upvote/downvote links. I'll dogfeed it for a week to ensure I haven't completely broken things before I publish it. Maybe it'll fix things for a few of you – who knows!

@nervous-inhuman I loaded your HTML gist and the page rendered just fine with the current CSS. It perhaps suggests there's something else interfering with the style on your end?

@gingerbeardman
Copy link

gingerbeardman commented May 23, 2024

Seems broken for me as of today, all paragraphs are very narrow and stack horizontally.

Before

image

Quick Fix

  td.default div:first-child {
    display: inline-block !important;
    height: inherit !important;
  }

After

Screen shot 2024-05-23 at 21 45 21

@christippett
Copy link
Author

Oh yikes, yes that's awful. I've removed the td.default div:first-child rule altogether, the HTML has obviously been updated and it no longer targets whatever it was it was originally supposed to! Hopefully the update propagates quickly to a stylesheet extension near you...

@pmarreck
Copy link

Thanks @christippett ! I noticed the same the other day; turned it off assuming (correctly) that it'll get fixed. Appreciate this HN restyle!

@christippett
Copy link
Author

Chuffed you guys are still enjoying it. Apparently this is the most downloaded userstyle for Hacker News too!

image

@pmarreck
Copy link

Just noticed that if I try to style a code block by indenting it 4 spaces, it won't monospace it as it's supposed to...

@christippett
Copy link
Author

@pmarreck leave it with me, I'll look into it.

While we're posting bugs: there's an issue with the column widths becoming unwieldy if the first item on a page happens to be a sponsored post (ie. a YC company job ad). These items don't allow for up/down votes which throws out the alignment for the rest of the table. I've noticed this mostly when viewing page 2+ onwards.

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