4 JUL, 2021

How this website works

This whole post is likely to be outdated reasonably quickly, because I'm always tweaking and updating things as I see/learn about them. I even just switched over to php in preparation for writing this!

How did you get here?

I've always messed around with HTML and webpages, as soon as I knew I could. My first website development was me seeing what I could do on my Chromebook (yes, there is a fully functional web server as a Chrome app!) at school. From there, I moved on to other programming things, but I always kept web development in the back of my mind.

Server?

For other reasons, I came into possession of a Raspberry Pi model 3B. For a while, it was actually being used as something useful, running DAKboard on a part of my triple monitor setup. Turns out, I didn't have any use for it, other than a nice big clock. I didn't have a complicated calendar, and if I wanted weather info, I can just look outside.

As such, it didn't do a whole lot, although I learnt about the wonders of cron, and what it can do for me. I initially used it to disable the HDMI port at certain times, so that my monitor would go to sleep, and wake as I would. Thus began my foray into 'smart' devices and home automation, which I might put in another post.

Shortly afterwards, I acquired a USB-powered LED strip. After initially plugging it into my multiplug (a.k.a. 'power strip'), I quickly realised that the LEDs are bright, and distracting whilst I'm trying to sleep. Thus, I plugged it into my Pi instead! A quick addition to my cron jobs later, and they were also sync'd to my sleep schedule.

After the disbanding of my triple monitors, my Pi kept on running cron jobs for my lights, and eventually that migrated to a simple webpage to execute some simple shell scripts (via php). Subsequently, that got built out to receive HTTP POST requests, an a corresponding Android widget (thanks to KWGT and 'HTTP Shortcuts') to send them.

Nowadays, the lights are handled by a dedicated device, that is suitable for it. Hang on, website? This is starting to sound like a home automation post!

Server

So now the Raspberry Pi, henceforth 'pixie', runs this website, and a separate desktop is running my ownCloud instance, known as 'hewie'. My network isn't anything fancy, but it is quite configured, if you will.

pixie connects over Wi-Fi, and uses apache2 to host any and everything I need from it. Everything goes through it, and is forwarded to hewie as needed, via some neato redirects (which took altogether too much trouble to set up).

It's also configured to do nice things with apache2's mod_dir and mod_mime, such as to automatically send over an index when a directory is requested. mod_mime helps figure out content type. There's also MultiViews to just completely ignore file extensions, so that a request for index will actually grab index.php or index.html (Use Options MultiViews under the Directory directive). A client can't guarantee what the file type is, hence why the server sends it over, and the server can infer the correct mime type from the requested resource. As such, all file extensions are arbitrary (as long as there aren't any duplicate names).

How did this website start?

Way back when (remember me playing with HTML in school?), I had an ICT project, to make a website for some arbitrary thing. An animal breed or some such like nonsense. I just used my friend's Chihuahua, and made it a very nice website, including all sorts of fancy things.

Anyway, fast forward a lot, and I need another website for ... reasons. Oh look, a nice-ish website from a couple years ago! I subsequently tidied it up, and set out to do things properly this time around.

Didn't quite work out, but we'll get to that. I swapped out my (now defunct) website for this one, and I was off to the races. Everything kinda just 'worked' due to my efforts in configuring it properly earlier, so that was nice. But then, I needed a new website as well.

It was suggested that I should start a blog for long-form tech stuff. So I did (well duh, you're reading it). However, whilst 'modernising' my old school project, I found a lot of kludges and hacky stuff that I didn't like. This was my opportunity to build it actually right.

So I did my research, I learned me some stuff, and I finally fell in love with CSS instead of hating it. I built the whole thing, and while it looks similar, under the hood it's quite a different beast. Or, it was. I've since redone the other site, to be more in line with all the other ones.

Oh right, other ones. Yeah so a big part of why and how I designed the new one was to be able to just make new pages as fast and easily as possible, while keeping with native HTML and CSS (and minimal JS). The other part, was to be able to update the whole site, with minimal changes to one central file, e.g. for styling changes.

So how does it actually work, now?

I think I achieved that, mostly. I have achieved that even more now, because of a really cool thing I found: I realised that I kept copy-pasting the same old HTML header meta information and scripts, etc., for each new site. And I didn't need to actually change anything, but if I did, it would be a pain to go back and redo all of them. So, I did some more research, and I found the php include function/command:

<?php include $_SERVER["DOCUMENT_ROOT"] . "/header.html" ?>

Because it's php, you can't see it, but that is at the top of almost every page. What it means, is that before the HTML gets sent back to the client, the webserver runs the PHP, which combines everything together into the final document. Thus, the client only sees the proper, native HTML page, but behind-the-scenes it's a composition of several .html pages.

Styling

Everything is written by hand, in pure CSS. There is a single, centralised style.css to handle all the big stuff, and more a specialised article.css stylesheets for the specific sites' pages. The goal is to be able to write (and style) quickly, and efficiently, exactly as I think about it. Thus, I want all the styling to be already set up, with no classes or ID's or nonsense to worry about. Style, layout, etc., should already be defined, and I just insert the right tag where I want it. Anyway, let's take... a closer look.

style.css

This lives in /styles

Explaining this whole thing is far too much for a post, so I'll pick just a few items... soon™.

theme.js

This lives in /scripts

This one is pretty simple, although in practice there's quite a bit going on. It can all be boiled down to three things.

First up, this little gem:

const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");

This will get the user's preference from their browser directly. This can often be configured to follow the system theme, or always set to light/dark as desired, via the browser settings. It's amazing how simple it is to just grab it, considering how abstracted the actual browser client often feels.
And on that trend, we have another one-line-wonder!

currentTheme = localStorage.getItem("theme");

Here, we get the user's preference, but this time from the local storage, i.e. cookies, for just this site. We can then apply a little bit of logic to prefer the user's settings for this site first, and then go by the browser's preference if that's not set. Lastly, we have a button in the top-right, which you've hopefully seen.

setTheme(theme);
applyTheme();

It has some checks to make it toggle, and then it just sets as appropriate (using other functions that are boring and simple.)

anchors.js

This also is in /scripts
This one is small and simple enough to just drop the whole thing in. Here you go:

const elements = document.querySelectorAll('h2');

elements.forEach(element => {
	var a = document.createElement('a');
	var heading = element.innerText;
	heading = heading.toLowerCase();
	var cleanedID = heading.replace(/\W/g, '-'); //cleanedId is "whatever_your_id_is"
	a.href = "#" + cleanedID;
	a.innerText = " 🔗";
	a.id = "section-anchor-link";

	element.appendChild(a);

	var anchor = document.createElement('a');
	anchor.id = cleanedID;
	anchor.className = "section-anchor-view"
	element.appendChild(anchor);
});

This grabs all the h2 sized headings, and then does some operations on and around them. We first make an a "anchor" element, i.e. a link. Then we do some processing on the heading text:

  1. Make it all lowercase
  2. Replace all the non-text characters with a hyphen
  3. Stick a hash in front of it
We set that to the href destination of the link, give it a suitable Unicode icon, and an ID to be able to have it styled via CSS.
Next up, we put it next to the heading, and do something a bit wierd.

We make another link element! Sure, this one doesn't have to be a link, it's just easy and simple. We give this one the ID that goes with the previous link, so that clicking it will look for this element. This time, we use an appropriate class for CSS styling, which will put it way above the actual heading. You can check this out for yourself via the "Inspect element" view. That way, the browser will scroll to it, and leave enough space at the top for the header!

If there's any niggling little things left, please see the home page for contact information.