Rewriting an old project! Part 1: HTML & CSS
Tags: javascript, css, html, showdev
Published: 2019-04-08 20:52:32

---
title: Rewriting an old project! Part 1: HTML & CSS
published: true
description: I revisited an old weekend hack of mine from college, and man, how I (and the platform) have grown! I decided to rewrite it here in 2019, and to share that experience for some reflection and some laughs.
tags: javascript, css, html, showdev
series: Rewriting jSphere
cover_image: https://thepracticaldev.s3.amazonaws.com/i/11a9ehfhmd7byqordyqj.png
---

# Backstory

I'm a guy who's been around the web for a while. I learned JavaScript at age 12 (talking 2003 here, IIRC) when I found [Steven W. Disbrow's *JavaScript Weekend Crash Course*](https://www.amazon.com/JavaScript-Weekend-Course-Steven-Disbrow/dp/0764548042) on my dad's bookshelf, sat down with it at the Windows 95 machine my dad had rescued for me from the trash heap at his corporate IT job, opened Notepad and IE6, and started hacking away. As I recall, this is roughly the code that got me hooked:

```javascript
for (var i=0; i<10000000000000; i++) {
    document.write(i + ' ');
}
```

And of course, the reason it got me hooked was that, when I added enough zeroes to the number in the conditional, it crashed my browser. And that meant I was a

```
..................................................................................
..................888.....................888.....................................
..................888.....................888.....................................
..................888.....................888.....................................
..................88888b...8888b....d8888b888..888..d88b..888d888.................
..................888."88b...."88bd88P"...888..88Pd8P..Y8b888P"...................
..................888..888.d888888888.....888888K.88888888888.....................
..................888..888888..888Y88b....888."88bY8b.....888.....................
..................888..888"Y888888."Y8888P888..888."Y8888.888.....................
..................................................................................
.............._____________________________________________________...............
....._,aad888P""""""""""Y888888888888888888888888888888P"""""""""""Y888baa,_......
....aP'$$$$$$$$$$$$$$$$$$$$$`""Ybaa,.........,aadP""'$$$$$$$$$$$$$$$$$$$$$`Ya.....
...dP$$$$$$$$$$$$$$$$$$$$$$$$$$$$$`"b,.....,d"'$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Yb....
...8l$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8l_____8l$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8l...
..[8l$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8l"""""8l$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8l]..
...8l$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$d8.......8b$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8l...
...8l$$$$$$$$$$$$$$$$$$$$$$$$$$$$$dP/.......\Yb$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$8l...
...8l$$$$$$$$$$$$$$$$$$$$$$$$$$$,dP/.........\Yb,$$$$$$$$$$$$$$$$$$$$$$$$$$$$8l...
...8l$$$$$$$$$$$$$$$$$$$$$$$$,adP'/...........\`Yba,$$$$$$$$$$$$$$$$$$$$$$$$$8l...
...Yb$$$$$$$$$$$$$$$$$$$$$,adP'...................`Yba,$$$$$$$$$$$$$$$$$$$$$dP....
....Yb$$$$$$$$$$$$$$$$,aadP'.........................`Ybaa,$$$$$$$$$$$$$$$$dP.....
.....`Yb$$$$$$$$$$,aadP'.................................`Ybaa,$$$$$$$$$$dP'/.....
.......`Ybaaaaad8P"'.........................................`"Y8baaaaadP'........
..................................................................................
```
<figcaption>hacker 😎<br>(btw, ascii art lifted from <a href="http://ascii.co.uk/art/hacker" target="_blank">here</a> and <a href="https://www.asciiart.eu/clothing-and-accessories/glasses" target="_blank">here</a>, with some modifications)</figcaption>

Anyhow. Fast forward like 8 or 9 years. I'm at college, senior year, 2012 I think, avoiding work. I've never lost my love for the web, though I'm a little closeted about it, given that it was the height of the "JS Sucks" movement. But I often spent a portion of my procrastination hours hacking on small JS projects to get my hit. I ran across a tutorial (probably [this one](http://rectangleworld.com/blog/archives/298), though I'm not sure) talking about the relatively new HTML5 `<canvas>` and how to make a little faux-3D sphere using dots with varying shades of gray to simulate depth. And I thought the result was cool, so I decided to try and figure it out on my own without reading the tutorial.

I did, and I was pretty happy with the result. I even added some interactivity that the original didn't have, which was fun to figure out. Here it is, copy-pasted into a CodePen:

{% codepen https://codepen.io/kenbellows/pen/MxZrjy default-tab=result %}

Looking back at the code now, it's still not terrible for the time. But man, it needs some updating. 2012 was a long time ago, and both I and the web have significantly improved since then.

So I thought I'd update the code, and it seemed like a fun idea to write it up as I go, to see what's changed in our wonderful web world (www) since 2012.

If you want to follow along, the repo is here: https://github.com/kenbellows/jsphere/
And the demo is here: https://kenbellows.github.io/jsphere/

The repo now has the new code pushed to the `master` and `gh-pages` branches, but I'll keep around the prior state of things in a branch named [`gh-pages__old`](https://github.com/kenbellows/jsphere/tree/gh-pages__old), so check there for the complete previous code that went basically untouched for around 7 years.

**Important:** I'm not going to be discussing the *content* of the code here, what the code does or anything, just how I've updated the structure and syntax and such. However, I do plan to write a final post that discusses what the code actually does, and walks through it in proper tutorial style.


# HTML

So first. That HTML. Not great. Here's the structure, very slightly abbreviated:

```html
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script type="text/javascript" src="./js/jquery-1.7.1.min.js"></script>
        <script type="text/javascript" src="./js/jquery.event.drag-2.0.min.js"></script>
        <script type="text/javascript" src="./js/sphere.js"></script>
        <link rel="stylesheet"...>
    </head>
    <body>
        <!-- github link banner omitted -->

        <div id="header">
            <h1 id="header-title">jSphere</h1>
            <h2 id="header-subtitle">Just to see what I could do.</h2>
        </div>
        <div id="controls">
            <h3 id="controls-title">Controls</h3>
            <div id="controls-body">
                <p id="c-1">Rotate:  Click and drag</p>
                <p id="c-2">Pan:     Hold shift, click and drag</p>
                <p id="c-3">Zoom:    Hold ctrl, click and drag</p>
            </div>
        </div>
        <div id="content">
            <canvas id="canvas" width="800" height="700"></canvas>
            <p id="psst">Psst. There are a couple (that's 2) hidden key combos that do some things that I found by accident, so play around.</p>
        </div>
    </body>
</html>
```

Okay. Reflections:

1. ~~No need to put the script tags in the header. Just drop them at the end of the body. This removes the need for the jQuery `$(function(){ ... })` wrapper.~~ **Update:** As pointed out in [a comment by @crazytim](https://dev.to/crazytim/comment/a255), this approach is *also* pretty outdated! `<script>`s at the end of the `<body>` can't start downloading until the rest of the HTML is parsed and dealt with, which slows things down, and there's a standard solution to this: [the `defer` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer), which tells the browser to download the file so it's ready, but wait until the DOM is fully parsed before running it. Exactly what I need! So I should really keep my script in the `<head>`, but use `<script defer ...>`, which sill gets rid of the `$(function(){ ... })` wrapper. Thanks Tim!
2. Also, we don't need jQuery anymore. It made the world a ton easier back in the day, but these days it's just not necessary, especially for a project as small as this one. I'm pretty sure I only imported it to use the `$()` element selector function and the `jquery.event.drag` plugin, both of which can be eliminated now.
3. [Semantic HTML](https://dev.to/kenbellows/stop-using-so-many-divs-an-intro-to-semantic-html-3i9i)! I will never write another `<div id="header">` again. Just use `<header>`! Same for `<div id="content">`: that's basically just `<main>`.
4. *Man* I loved `id`s! *Every single element in the body* has an `id`! That's so unnecessary. We have a rich CSS selector syntax (and did back then, too) to take care of finding the right things on the page.

So, here's how I'm restructuring the page. I've collapsed `id="controls"` and `id="content"` within the `<main>` block and significantly rearranged its insides, and that will be reflected in the CSS as well, but we'll get there next:

```html
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link rel="stylesheet" type="text/css" href="./css/sphere.css">
        <link rel="stylesheet" type="text/css" href="./css/fonts.css">
        <script defer type="text/javascript" src="./js/sphere.js"></script>
    </head>
    <body>
        <!-- github link banner omitted -->

        <header>
            <h1>jSphere</h1>
            <h2>Just to see what I could do.</h2>
        </header>
        <main>
            <section id="controls">
                <h3>Controls</h3>
                <ul id="controls-listing">
                    <li>Rotate:  Click and drag</li>
                    <li>Pan:     Hold shift, click and drag</li>
                    <li>Zoom:    Hold ctrl, click and drag</li>
                </ul>
            </section>
            <canvas id="canvas" width="800" height="700"></canvas>
            <p class="psst">Psst. There are a couple (that's 2) hidden key combos that do some things that I found by accident, so play around.</p>
        </main>
    </body>
</html>
```

The big changes:
1. ~~Moved the script to the end of the body~~ (see note above) Added the `defer` attribute to the `<script>` tag to eliminate the need for any `onready` type event handlers.
2. Removed jQuery. I'll have to redo the mouse interaction code that relied on the `jquery.event.drag` plugin, but that's okay; it's much easier these days anyhow.
3. Refactored the markup to use the semantic elements `<header>`, `<main>`, and `<section>`. Restructured the code to be more semantic. The previous structure was heavily influenced by the CSS layout modes available at the time (or lack thereof), so it's going to be a lot simpler to do what I want now.
4. On that note, got rid of almost every `id`. The only one I left is the one for the `<section>` tag, and I do think that sections need labels; there's often more than one, and they often need to be specifically selected in CSS, so they have value IMO.

Okay, now for the CSS to match.

# CSS

Here's the old stuff. Remember that it goes with the first HTML sample above. I'm skipping the font and color stuff, as it's all pretty standard and stayed the same. The interesting bits are the layout and selectors related to the refactored HTML from above.

```css
#header {
    position: relative;
    width: 100%;
}
#header-title, #header-subtitle {
    width: 500px;
}
#header-subtitle {
    font-style: italic;
}

#content {
    padding: 0px;
    width: 810px;
    height: 900px;
    margin: 0px auto;
    position: relative;
    top: -50px;
}

#canvas {
    border: 2px solid black;
    z-index: 2;
}

#controls {
    width: 810;
    height: 200px;
    margin-left: auto;
    margin-right: auto;
    margin-top: 60px;
    margin-bottom: -50px;
    z-index:1;
    position: relative;
}
#controls-title {
    width: 75px;
    margin-bottom: 15px;
}
#controls-body {
    width: 100%;
    position: relative;
    margin: 0px;
}

#c-1 { /* Rotate */
    position: absolute;
    left: 0px;
    top: 0px;
    margin: 0px;
}
#c-2 { /* Pan */
    position: relative;
    width: 200px;
    text-align: center;
    margin: 0px auto;
    right: 10px;
}
#c-3 { /* Zoom */
    position: absolute;
    right: 10px;
    top: 0px;
    margin: 0px;
}

#psst {
    font-style: italic;
}
```

Hoo that's a lot of absolute positioning and fixed lengths. Now, I do want to emphasize that this was a little weekend hack that I didn't want to spend a lot of time on, and I didn't have all the layout methods available to me that we have now, but still... seems unnecessary. I was rushing, I think.

Of particular interest are the three `<p>` tags describing the Rotate, Pan, and Zoom controls. I gave them each an `id`, `#c-1`, `#c-2`, and `#c-3`, and positioned them absolutely to get the alignment I wanted. I think this was caused by the difficulty of centering one item and side-aligning the other two at the time. You could do it with tables, but... tables for layout were taboo even in 2012. I wouldn't dare except as an absolute last resort. Absolute positioning was definitely better in my mind.

(In retrospect, this was very silly of me, and a quick CSS table (I think those were supported at the time?) or even an HTML table would have been a much cleaner solution.)

Nowadays, we have two more options for layout: Flexbox and Grid. My first instinct when rewriting was just to lay down a quick flex container with a `justify-items: space-between`, since it's fewer lines. But I remembered after implementing that this is a classic corner-case where Flexbox acts slightly differently than you might expect, unless you really understand how it works. 

Don't get me wrong, it behaves in a totally fine and predictable and useful way, just not how I thought it did. I initially wrote up an explanation of that distinction here, comparing it to CSS Grid, but it turned out super long, so I published it in its own post here: [Flex items are not grid columns](https://dev.to/kenbellows/flex-items-are-not-grid-columns-4p2i)

The outcome of that post is that I used the following CSS on the parent `<ul>` element from the new HTML above:

```css
ul#controls-listing {
    grid-auto-flow: columns;  /* automatically place new items in new columns */
    grid-auto-columns: 1fr;   /* auto-columns should be 1fr wide */
}
```
I used the auto-flow method rather than, say, `grid-template-columns: 1fr 1fr 1fr`, 
because I like to future-proof my code as long as it doesn't add much work, and this method neatly handles any number of items, so I can add more controls later if I want to.

I also used a couple `text-align` rules on the grid items to center-align them by default, then left-align the first item and right-align the last one:

```css
ul#controls-listing > li {
    text-align: center;
}
ul#controls-listing > li:first-child {
    text-align: left;
}
ul#controls-listing > li:last-child {
    text-align: right;
}
```

The rest of the CSS changes are mostly updated selectors to (1) take into account the HTML restructuring and (2) use element selectors where possible instead of all those `#id` references. Her's the full final result:

```css
header > h2 {
    font-style: italic;
}

main {
    max-width: 810px;
    margin: 0px auto;

    display: flex;
    flex-direction: column;
    align-items: stretch;
}

#controls > h3 {
    text-align: center;
    margin-bottom: 15px;
}

ul#controls-listing {
    /** removing the default ul padding*/
    padding: 0;

    /* flexbox fallback if grid is not supported */
    display: flex;
    justify-content: space-between;

    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
}
ul#controls-listing > li {
    list-style: none;
    text-align: center;
}
ul#controls-listing > li:first-child {
    text-align: left;
}
ul#controls-listing > li:last-child {
    text-align: right;
}

canvas {
    border: 2px solid black;
}

.psst {
    font-style: italic;
}
```

That's a *whole* lot less CSS, and I hope you'll agree it's a whole lot cleaner and more readable. Flexbox and Grid have really made a difference in that area, and I'm very happy about the future of the web.

# Cliffhanger

So that's it for the HTML and CSS. The JavaScript is a *whole* other ball of wax, and requires its own post for sure. So I'll leave it here. I hope you've enjoyed this; it's definitely a bit cathartic to tear apart old code and congratulate myself on having improved as a developer in the last 7ish years, but it's also very exciting to see how much easier even very simple layouts like this one are in the new era of CSS layout methods.


See you next time!