Every once in a while, I love browsing the Wayback Machine1 to catch a glimpse of the early internet. I enjoy the waves of nostalgic indie hacker vibes that wash over me as I type a URL into the search box and click to see an old snapshot of the site frozen in time. Being a kid of the early ’00s, I missed the spectacular cosmic genesis of the ’90s internet in its entire nascent glory. However, I did briefly get a coup d’œil of the raw, untainted web 1.0 right before SEO firms, ads, pop-ups, modals, autoplays, and heavy frontend frameworks started prowling and gentrifying the whole space into an anxiety-inducing corporate circus.

Before social media and other corporate silos became mainstream, the web had, for the lack of a better word, more character to it. From IRC rooms to personal blogs with weird pixelated designs and sound effects, the realm was fragmented, chaotic, heterogeneous, and mostly, a lot of fun. There were no best practices around doing anything, and the notion of creativity wasn’t tied to the craft of how many keywords or interactive animations you could shove into a page to get the most eyeballs. You were the cool kid if you could just wire together a few pages with Perl, PHP, Python, or even Bash, and put something useful out there.

Now, I don’t want to come across as one of those anachronistic hipster millennials, reeking of RMS energy, who will reject anything that’s even remotely modern. Neither am I under the illusion that web 1.0 was a blissful nirvana, and we should’ve halted the progress wheel there. I wouldn’t want to relive the past of loading jQuery-heavy pages on my crappy 2G mobile network or the security horrors of PHP CMSes. Also, I’d prefer not all the websites to adopt the user-hostile-pitch-black-text-on-blinding-white design. It wouldn’t be functional, and the UX would probably drive away most folks.

But there’s absolutely no denying that the raw, unfiltered chaos of the old web had a magical spark to it that the sterile, framework-stuffed UIs of today often lack. While the mighty legion of the framework overlords and their thousand minions seem unstoppable in their quest to homogenize the web, it doesn’t have to be this way everywhere. There are still pockets where the web’s wild spirit can run free, untouched by the unrelenting march of frameworks stomping out all traces of creativity.

Whenever I see technology mughals like Peter Norvig or Rob Pike showcase their thoughts through ancient relics like this2 or this3, it does put a smile on my face. No gaudy animations, no fancy fonts, no dark mode—just strings of thoughts laid bare against a backdrop of naked HTML. If you don’t like the design, just load the content with Safari or Firefox reader and you’re golden. Of course, not all websites have to be like this but not every website has to look like Stripe’s4 either.

People often conflate this brutalist5 approach to designing websites with user-hostile, overly minimalist, and lazy design. The opposite of UI maximalism doesn’t need to be UX belligerence. Your site can look like absolute poop but still be responsive on any device and provide a great UX, like this absolutely hilarious rant page6. It wraps perfectly on your laptop, phone, or tablet, and doesn’t need to load 2 MB static assets. Plus, who cares about the layout when the content is this interesting?

The neo-grotesque web keeps the minimalist design of the brutalist philosophy while maintaining a neat UX and emphasizing content rather than fluff. Bring back those single-column personal blogs where writers would just list out a few heartfelt contents and call it a day. Bring back those gigachad dynamic websites like Craigslist7 with their unadorned buttons and blue URLs that, UI-wise, give those million-dollar react-y pages a run for their money. As long as the pages wrap on your phone, what’s there to complain about? Ugly can still be beautiful. Excrement contains nutrients. All hail the neo-grotesque web!

Recent posts

  • TypeIs does what I thought TypeGuard would do in Python
  • ETag and HTTP caching
  • Crossing the CORS crossroad
  • Dysfunctional options pattern in Go
  • Einstellung effect
  • Strategy pattern in Go
  • Anemic stack traces in Go
  • Retry function in Go
  • Type assertion vs type switches in Go
  • Patching pydantic settings in pytest