My New Blog: A Study in Lightweight Web Frontends
Written by: Kimberlee Model, posted: 2019-09-26. Tags: I Made a Thing, Web Development, Computing Thoughts, Home Server.This past summer, I've put a good deal of effort into updating my blog. Previously I had used Apache Roller, and I decided that I would replace it with a web-application of my own creation. The goals I had when I set out to create this were to build a good looking online space for me to share my thoughts and opinions, and to completely avoid the use of JavaScript while doing so.
So, I started out only seeking to make a theme of my own in Roller, but I soon decided that roller felt too "thick". It uses a programming language it calls "Velocity" to insert blog elements: posts, tags, author's biographies, etc. I'm not quite sure how it is interpreted, but it felt a little too much for me, so I set out on my own to make the lightest blog I possibly could.
At the moment of writing this, the public facing front end uses almost no javascript. In mobile orientations, the hamburger button uses javascript to toggle the menu's visibility, and even that I have thoughts on eliminating. Anyways, I wanted to share the tools and tricks that I picked up in light weight web-design. The code for this site can be found here.
CSS Selectors
When I look at the source of a lot of websites, the biggest thing that stands out to me is the excessive use of class="class1 class2 etc"
.
And it my mind that makes the code of a website very obscure and difficult to read.
At first brush, perhaps that isn't too much of an issue -- we have browsers to display it and syntax hilighters and validators to help us develop -- but as a developer myself, I think about the dependency nightmare it must be to try to edit any of those.
Changing the name of one class means traversing a potentially huge codebase looking to replace classes in both class
attributes, and in JavaScript which may edit the classList
attribute of a element.
Instead, while designing my own front end, I took advantage of advanced CSS Selectors, which allow me to use a single class on a container element, and select children of the container by their type and placement. A good example is the header bar on this website.
It uses classes and IDs on a few top level attributes, and from there it selects children and grandchildren of the top level attributes. A few elements do have class attributes, but these are special directives to treat them differently.
<nav class="topbar" role="navigation">
<a class="nostyle" href="...">
<img src="..." alt="avatar image" />
</a>
<a class="collapse2" href="...">About</a>
<span>RedBow Kimee</span>
<span id="replacefill"> </span>
<a href="..." class="collapse1">
Things I Made
</a>
<a href="..." class="collapse1">
Computing Thoughts
</a>
<a href="..." title="menu" id="toggleMenu">
<div>
<div> </div>
<div> </div>
<div> </div>
</div>
</a>
</nav>
Note that I shortened all the href attributes to minimize distraction.
Note the top level nav class="topbar"
container element.
Since I do not currently use any other nav
elements, I could omit the class="topbar"
but I am currently undecided if I will add any additional nav
elements in the future.
While many of the children of the nav class="topbar"
do indeed have classes, each class has semantic meaning.
collapse1
and collapse2
indicate to media queries which elements should be hidden in the first downsize from "desktop" to "tablet", and which should be hidden in the second downsize from "tablet" to "smartphone".
replacefill
indicates that when the "hamburger" menu is opened and items fall onto the drop down menu, which elements should be made visible to simply fill the horizontal space on the topbar.
The nostyle
class on the <a><img>
is an unfortunate product of CSS not being quite ready for what I want to do.
CSS has an experimental and unsupported pseudo selector function selector:has(selector)
.
This will find an element which has a child matching the second selector.
I wanted to use the selector nav.topbar a:has(>img)
which would have matched an anchor containing an image, so that I could remove the padding.
When :has(selector)
is sufficiently widely supported I could change this and remove this tag.
Lets look at some of my CSS now, still looking at the top bar.
I want to point out a few selector patterns that I found myself using a lot.
first is parent>child
.
This matches any child with the direct parent.
The second I find myself using a lot is ancestor element
.
This one matches any element who has the given ancestor.
Last one is selector, selector
which matches either the first selector or the second selector.
I'm not going to excerpt any of my CSS, because there is a lot of it, but it is available for viewing here,
Media Queries and Responsive Web Design
I started out making a skin for my Apache Roller blog, on desktop, and I didn't originally put a lot of thought into mobile usability. It was supposed to simply be a simple three column view: main content in the center, and support content to each side. But one day I was reading about Responsive Web Design, and decided to give it a try. Most of the reading I did said to make the mobile view first, and allow it to expand from there. Obviously I went about the opposite direction: started at desktop and shrunk down to mobile. The primary mechanism I used for shrinking was to have the support content at the sides "fall down" below the main content. Responsive Web Design was honestly easier than it sounds, and I quickly added support for items on the top bar to fall into a "hamburger menu" as the space decreased.
This isn't primarily about RWD, so I won't go indepth about it.
I found that media queries were far easier than expected.
I also found that although display: flex
elements are not explicitly made for RWD the same way media queries are, that flex elements play very nicely with RWD, especially because the order of containers can be set using CSS and media queries.
I still need to mess with some of the media query thresholds for switching, but RWD is really much less of a "big deal" than it is made out to be.
No JS
So a few weeks ago, I was planning to make a humorous post about building a website with "no js", as a pun on "node.js". I decided to search for the term first, and I actually found this. It is a small JavaScript library designed enable small amounts of interactivity by performing very simple DOM manipulations without writing any JavaScript.
Originally I had held myself to a rigid "no javascript" rule. Once I did find no.js, I quickly found myself extending it and making this pull request on no.js's github repo.
The idea behind no.js is not to write JavaScript, but instead add extension attributes to DOM nodes, which are then processed by a framework that translates them into event listeners. Of course, no.js is itself written in JavaScript, but it enables you to write no JavaScript. Here is a small example.
<style type="text/css"">.hidden { display: none; }</style>
<button no-js on-click-toggle-class="#message hidden">
toggle hidden message
</button>
<span id="message" class="hidden">Hidden Message</span>
Hidden Message
In the example, the button will toggle the hidden message's visibility, by changing its CSS classes.
Closing Thoughts
So, this project has been fun and interesting, if not frustrating in moments. For me, one of the reasons I went about this project was to see just how necessary are heavy weight frameworks like Angular.js and React.js. I found that for the minimal amount of web-based project that I do, not even that much JavaScript is necessary. One thing I didn't try to do was a WYSIWYG for comments. Currently, I am still implementing comments, and I'm deciding whether I should go with a markdown-like-processor or a WYSIWYG. I would expect a more advanced WYSIWYG to require more advanced JavaScript than no.js, but it isn't something I've looked into yet.