A brutalist website.

It's been a while I wanted to jump on the brutalist bandwagon but I never got the chance to think about anything worth it.

That's why I decided to go for something not worth it.
Inutile.co is an unnecessary pet project, which lists unnecessary pet projects, stuff I might not even write about because they are either lame, not interesting or for the LOLs — or all these together.

Brutalist web design expresses in a lot of different canons, as you might notice at a glance navigating through the amazing collection at brutalistwebsites.com. But what defines a brutalist web design? The best description I found is

harsh, stripped-down designs that have no frills, as a reaction to the cleanliness and polish of design systems.
UX brutalism:

First iterations

The first iteration of it was a plain HTML page containing

<html>
    <head>
        <title>Inutile dot co</title>
    </head>
    <body>
        <h1>Inutile</h1>
        <dl><dt>Inutile</dt><dd>useless, unnecessary, pointless</dd></dl>
        <ul>
            <!-- a list of: -->
            <li><a href="https://mypetproject.dsgn.it">Pet Project title</a></li>
        </ul>
        <small>by <a href="https://cedmax.com">cedmax</a></small>
    </body>
</html>

and some basic styles to increase the font size, make the definition list monospaced and that was about it.

It didn't feel right, though: brutalist doesn't mean sloppy, nor lazy. I wanted more technical nuances, that would keep the look and feel brutal, but with an underlying depth.

The first effort was to make a good use of before and after pseudo-elements for the links: I removed the list style from the lis and added them as ::before to be able to colour them depending on the state.

That was fairly easy: using borders I could achieve triangles and roll with it.

A little trickier was to animate in a blink-like manner the ::after.

Blink is a now deprecated HTML tag that would animate its content, making it, as the name suggests, blink.

Achieving the same result with a CSS animation is not a big deal in itself. Applying that very animation to the pseudo-element is not a problem either. The problem is applying it only on certain states of the link (for example only when the links are not visited, in my use case).

To prevent Web pages from accessing a user's history [...], browsers must limit the ability of Web pages to style pages based on whether links are visited.
David Baron

The list of supported style properties is fairly short and it's almost exclusive to colour changes (including fill and stroke) excluding the alpha channel.

The most sensible workaround to apply the blink effect is explained very well by Una Kravets (except she didn't animate her version, probably because she has some discernment): the blink is always on, since it can't be modified depending on state, but when the links are visited it blinks white text on a white background.

At this point, I started sharing the page with a few friends, and a very expert UX designer, and I'm not even kidding, suggested me to change the timing of the blink.

And that's how I ended up writing the most random piece of CSS I've ever conceived, I hope:

li:nth-child(2n) a::after {
  animation-delay: .2s;
  animation-duration: 1.3s;
}

li:nth-child(3n) a::after {
  animation-delay: .3s;
  animation-duration: .8s;
}

li:nth-child(4n) a::after {
  animation-delay: .7s;
  animation-duration: .1.1s;
}

li:nth-child(5n) a::after {
  animation-delay: .9s
}

It did the trick.

Going wild

This was enough, wasn't it?
Not really.

Interlude

Sgurz is a made up world, introduced for the first time in the collective immagination by Riondino, an Italian comedian and modern minstrel, to define something undefinable.

Sgurz is something that hits you like a wave and makes you do something crazy and perfect at the same time. Nobody knows what it is, but it's there: it happens all of a sudden and you are forced to perform a Sgurz act. Either you have the Sgurz or you don't.

I can't claim I have the Sgurz, but right now I can't think for any other reason why I thought about...

The offline experience

A while ago I came across Offline, and what I believe is its evolution: The Disconnect.

Chris Bolin's work inspired me to think about introducing a different offline experience to my brutalist site.

It could have worked in two ways: polishing the design incredibly (skeumorphism?) or continue on the brutalist route, with a different angle.

Not being any good at Photoshop, I didn't really have many options. I wanted a game, but I rewrote the whole thing in react static first.

There are a few reasons for this choice:

  • Bolin's work is based on a component he open sourced (react-offline-detect) and I didn't want to rewrite the functionality from scratch
  • A static HTML is great for a document listing links, less so for a game
  • React static provides an opportunity to produce a progressive enhanced website, where my HTML would still look exactly the same, and then react would take over, adding the offline detection functionality.

The rework didn't take long, the main pain point surfaced later on, introducing react-detect-offline: react static failed silently to convert the react body into the HTML. After some debugging, I figured that the reason was that components relying on window or document are not really supported by React Static. The solution seems straightforward now but I wouldn't have noticed the problem without running Lighthouse.

In itself react-detect-offline offer a simple API: an Offline and an Online component. It takes care of switch between rendering the children of one or the other without any effort on your side.

This is how I ended up wrapping the whole thing to get the static rendering working:

export default () => (
  (typeof window !== 'undefined') 
    ? <Body />
    : (
        <Fragment>
          <Online><Body /></Online>
          <Offline><Body offline /></Offline>
        </Fragment>
      )
)

The initial game is stupid and trivial (hence perfect): users will have to catch a ball bouncing on the screen with a speed increase at each level (three of them so far).

The animation is all CSS with a 0 to 100vh/vw, to their respective axis; the speed increase is calculated in js and there's also a random animation delay to make sure every time the component is rendered, every time the user catches the ball, it appears in a different portion of the screen.

After 3 levels there's a surprise but I won't spoiler that, let me just say that I'm very proud of how it fits in a brutalist experience. 😁

One last problem.

After the game went live, a game that probably no one will ever see (except maybe people reading this), I decided to add a service worker, to make sure offline was completely accounted for.

I took advantage of the code shared by Jeremy Keith and whilst everything went fine on the service worker side of things, I figured I had a problem.

I used styled components themes to switch between online and offline colour scheme and disable pointer events to get the links not to interfere with the game. Alas, I couldn't get styled-components to hydrate properly the theme after a page reload: once the CSS was staticised, and loaded from the HTML, the components wouldn't render with the new theme, even if the events were firing correctly. This meant that refreshing while offline, you would see the colour scheme (and the have the pointer events) as if you were online, but the game would still be playable.

This was very annoying and confusing, but the only way I figured I could work around that was giving up switching the theme and moving to a more usual "offline" class name on the body. To avoid a flash of the wrong theme, before javascript kicked in, I added a couple of commands to npm script to copy the index.html to offline.html and inject the class name in the body.

The end

All in all it was a lot of fun and it's the classic little stupid thing you can laugh at with friends.

The code

Inutile: https://github.com/cedmax/inutile

--

Cover Image via Irene Ros