How to make a completely unusable homepage in CSS3 and jQuery

One of my favorite bits of code I’ve ever done is on the front page of my jiggy, ancient, perpetually-under-construction, virtually-never-viewed old personal website, Life In A Mikeycosm. Eager to make my front page “pop” a little more back in days gone by, I came up with a clever CSS3/javascript hack that caused the page text and logo to slip and slide in three dimensions in response to your mouse movements, rendering the page somewhere between difficult and totally unusable for actually navigating the content of the site. I’ve always been inordinately fond of this.

I’ve embedded it below so you can experience the source of my amusement. Actually, if you click through the above link to the real site, at the bottom left there’s a “Stop this crazy thing” link that stops the animation and moves the links into rows so they’re readable and clickable. I don’t know if the below embed is big enough to show this, though. When animated, the moving links are indeed clickable, if you can catch one with your mouse to click on it. I added a glow-on-hover text effect to indicate when the mouse is over a link and it’s clickable.

Really, I find the whole thing pretty entertaining.

An explanation of how it’s done is below. There’s a “stop this crazy” thing link in the lower left, but depending on your screen dimensions it might be cut off, you might need to stretch the embedded view by dragging the little resize nubbin at the bottom right corner to see the whole kit & kaboodle (Note to web developers: yes, it’s a resizable iframe. Eat that!)

How It’s Done:

The html layout of the page is extremely simple. It’s a couple of section headings, followed by links, laid out in a pretty simply, like this:

{!{code}!}czozNTI6XCImbHQ7bnhiciZndDsmbHQ7YiZndDtTZWN0aW9uIDE6Jmx0Oy9iJmd0OyZhbXA7bmJzcDsgJmFtcDtuYnNwOw0KJmx0O2F7WyYqJl19IGhyZWY9XCJpbm5lcnBhZ2UxLmh0bWxcIiZndDtQYWdlIDEgdGl0bGUmbHQ7L2EmZ3Q7DQombHQ7L254YnImZ3Q7DQomYW1wO25ic3A7e1smKiZdfSAmYW1wO25ic3A7Jmx0O3diciZndDsNCiZsdDtueGJyJmd0OyZsdDthIGhyZWY9XCJpbm5lcnBhZ2UyLmh0bWxcIiZndDtQYWdlIDImbHtbJiomXX10Oy9hJmd0OyZsdDsvbnhiciZndDsNCiZhbXA7bmJzcDsgJmFtcDtuYnNwOyZsdDt3YnImZ3Q7DQombHQ7bnhiciZndDsmbHQ7YSBoe1smKiZdfXJlZj1cImlubmVycGFnZTMuaHRtbFwiJmd0O1BhZ2UgMyZsdDsvYSZndDsmbHQ7L254YnImZ3Q7IFwiO3tbJiomXX0={!{/code}!}

The only thing that bears some explanation is those custom <nxbr> tags. The reason for those is, this site actually dates back to the very earliest days of my web development, back in the mid ’90s. For a while, before I made the page dynamic and jiggery, I just wanted to control the wrapping so titles didn’t break across lines, and those started life as &lt;nobr&gt; tags. Over time &lt;nobr&gt; tags came to be deprecated, and I’m sure as I was trying to animate things there were some conflicts, or something—this was all decades ago now—and I wound up using CSS to format things how I wanted, but left the tags in, converted to absolutely meaningless &lt;nxbr&gt; tags, because in my neophyte days I guess I wasn’t yet aware you could do &lt;div class="..."&gt; or &lt;span class="..."&gt; or something. Anyway, at this point, all <nxbr>…</nxbr> is doing is marking the individual links, because I want to animate them separately.

Then, the magic starts with this CSS:

{!{code}!}czoxMDU1OlwiDQoNCm54YnIgew0KCWRpc3BsYXk6IGlubGluZS1ibG9jazsNCn07DQoNCmJvZHkgew0KCXBvc2l0aW9uOiBhYnNvbHV7WyYqJl19dGU7DQoJcGVyc3BlY3RpdmU6IDMwMHB4Ow0KCXdpZHRoOiAxMDAlOw0KCWhlaWdodDogMTAwJTsNCglvdmVyZmxvdzogaGlkZGVuO3tbJiomXX0NCn0NCg0KbnhiciB7DQoJZGlzcGxheTogaW5saW5lLWJsb2NrOw0KCS13ZWJraXQtdHJhbnNpdGlvbjogYWxsIDEwMDBtczsNCgkte1smKiZdfW1vei10cmFuc2l0aW9uOiBhbGwgMTAwMG1zOw0KCS1vLXRyYW5zaXRpb246IGFsbCAxMDAwbXM7DQoJdHJhbnNpdGlvbjogYWxsIDF7WyYqJl19MDAwbXM7DQoJbWFyZ2luLXRvcDogLjVlbTsNCgltYXJnaW4tYm90dG9tOiAuNWVtOw0KfQ0KDQpueGJyOm50aC1vZi10eXBlKDNuKXtbJiomXX0geyAvL2V2ZXJ5IHRoaXJkIG54YnINCgl0cmFuc2Zvcm06IHJvdGF0ZVgoLTVkZWcpIHJvdGF0ZXkoLTEwZGVnKSB0cmFuc2xhdGV6e1smKiZdfSg0NXB4KTsNCn0NCg0KbnhicjpudGgtb2YtdHlwZSgzbisxKSB7IC8vb25lIGFmdGVyIGV2ZXJ5IHRoaXJkIG54YnINCgl0cmFuc2Z7WyYqJl19b3JtOiByb3RhdGVYKDBkZWcpIHRyYW5zbGF0ZXooNTBweCk7DQp9DQoNCm54YnI6bnRoLW9mLXR5cGUoM24rMikgeyAvL3NlY29uZHtbJiomXX0gYWZ0ZXIgZXZlcnkgdGhpcmQgbnhicg0KCXRyYW5zZm9ybTogcm90YXRlWCg1ZGVnKSByb3RhdGV5KDEwZGVnKSB0cmFuc2xhdGV6e1smKiZdfSg1NXB4KTsNCn0NCg0KI21rVGl0bGUgew0KCS8vIHRoaXMgaXMgdGhlIGJhY2tncm91bmQgaW1hZ2UgZGlzcGxheTogYmxvY2s7DQp7WyYqJl19CXBvc2l0aW9uOiBhYnNvbHV0ZTsNCglvcGFjaXR5OiAuMjsNCgltYXJnaW46IDEwMHB4IDE1cHg7DQoJcG9pbnRlci1ldmVudHM6IHtbJiomXX1ub25lOw0KCXdpZHRoOiA5MCU7DQoJaGVpZ2h0OiA5MCU7DQoJLy9zZXQgdGhlIGltYWdlIHRvIG1vdmUgbmljZSAmYW1wOyBzbG93e1smKiZdfWx5IA0KCS13ZWJraXQtdHJhbnNpdGlvbjogYWxsIDExNTAwbXM7DQoJLW1vei10cmFuc2l0aW9uOiBhbGwgMTE1MDBtczsNCgktby17WyYqJl19dHJhbnNpdGlvbjogYWxsIDExNTAwbXM7DQoJdHJhbnNpdGlvbjogYWxsIDExNTAwbXM7DQoJei1pbmRleDogLTEwMDAwOw0KfQ0KXCJ7WyYqJl19O3tbJiomXX0={!{/code}!}

Those nxbr:nth-of-type(3n) rules create three different alternating sets of tags, defined individually by those <nxbr> tags.

Then, having already loaded jQuery, this script tells the four CSS rules how to animate the <nxbr> tags to which they apply:

{!{code}!}czoyNzQ2OlwiDQoNCi8vJmx0OyFbQ0RBVEFbDQokKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHsNCiAgICBtb3VzZVBlcnNwZWN7WyYqJl19dGl2ZSgkKHdpbmRvdykud2lkdGgoKSwgJCh3aW5kb3cpLmhlaWdodCgpKTsNCg0KICAgIGZ1bmN0aW9uIG1vdXNlUGVyc3BlY3RpdntbJiomXX1lKHcsIGgpIHsgLy9iZWdpbiBtb3VzZSBtb3ZlbWVudCBldmVudCBoYW5kbGVyLg0KICAgICAgICAkKGRvY3VtZW50KS5tb3VzZW1ve1smKiZdfXZlKGZ1bmN0aW9uKGUpIHsNCiAgICAgICAgICAgIC8vdGhpcyBmdW5jdGlvbiBpbmhlcml0cyBcImVcIiwgYW4gb2JqZWN0IGNvbnRhaXtbJiomXX1uaW5nIHBhZ2VYIGFuZCBwYWdlWSwgY29vcmRpbmF0ZXMgb2YgdGhlIG1vdXNlLg0KDQogICAgICAgICAgICB2YXIgWG1vdXNlID0ge1smKiZdfWUucGFnZVg7DQogICAgICAgICAgICB2YXIgWW1vdXNlID0gZS5wYWdlWTsNCiAgICAgICAgICAgIHZhciBYcGVyYyA9IFhtb3VzZSB7WyYqJl19LyB3Ow0KICAgICAgICAgICAgdmFyIFlwZXJjID0gWW1vdXNlIC8gaDsNCiAgICAgICAgICAgIFhwb3MgPSBNYXRoLmZsb29yKFhwZXtbJiomXX1yYyAqIDEwMCk7DQogICAgICAgICAgICBZcG9zID0gTWF0aC5mbG9vcihZcGVyYyAqIDEwMCk7DQogICAgICAgICAgICBYcmV2ID0ge1smKiZdfTEwMCAtIFhwb3M7DQogICAgICAgICAgICBZcmV2ID0gMTAwIC0gWXBvczsNCg0KICAgICAgICAgICAgJChcImJvZHksdGFibGUsbnhie1smKiZdfXIsc3BhbixhXCIpLmNzcyh7DQogICAgICAgICAgICAgICAgcGVyc3BlY3RpdmVPcmlnaW46IDEyLjUgKiBYcG9zICsgXCclIFwnICsgMTJ7WyYqJl19LjUgKiBZcG9zICsgXCclXCcsDQogICAgICAgICAgICAgICAgXCd0cmFuc2Zvcm0tc3R5bGVcJzogXCdwcmVzZXJ2ZS0zZFwnLA0KICAgICAgIHtbJiomXX0gICAgICAgICBcJy1tb3otdHJhbnNmb3JtLXN0eWxlXCc6IFwncHJlc2VydmUtM2RcJywNCiAgICAgICAgICAgICAgICBcJy13ZWJraXQtdHJ7WyYqJl19YW5zZm9ybS1zdHlsZVwnOiBcJ3ByZXNlcnZlLTNkXCcNCiAgICAgICAgICAgIH0pOw0KDQovLyBOb3cgd2UgZG8gZmFuY3kgbWF0aCB0b3tbJiomXX0gdHJhbnNmb3JtIFNPTUUgKGJ1dCBub3QgYWxsKSBvZiB0aGUgM0QgQ29vcmRpbmF0ZXMgb2YgbnRoLW9mLXR5cGUoNG4pIG54YnIge1smKiZdfXRhZ3MuICBZZXMsIHRoZSBDU1MgaGFzIGEgcmVwZWF0aW5nIGN5Y2xlIG9mIHRocmVlIGdyb3VwcyBvZiB0YWdzLCBidXQgdGhlIGp7WyYqJl19UXVlcnkgY2hhbmdlcyBwYXJhbWV0ZXJzIGluIGEgcmVwZWF0aW5nIGdyb3VwIG9mIDQuIExvb2sgYXQgbWUsIElcJ20gdGhlIEtpbmd7WyYqJl19IENyaW1zb24gb2Ygd2ViIGRlc2lnbiENCg0KICAgICAgICAgICAgJChcIm54YnI6bnRoLW9mLXR5cGUoNG4pOm5vdChcJy5ub3JtYWxcJ3tbJiomXX0pXCIpLmNzcyh7IA0KICAgICAgICAgICAgICAgIFwndHJhbnNmb3JtXCc6IFwncGVyc3BlY3RpdmUoMzAwcHgpIHJvdGF0ZVgoXCcgKyAoLTV7WyYqJl19ICogWHBvcyAvIDEwMCkgKyBcJ2RlZykgcm90YXRlWihcJyArICgtNTAgKiBYcG9zIC8gWXBvcykgKyBcJ2RlZykgdHJhbnNsYXRleihcJyB7WyYqJl19KyAzNDUgKiBNYXRoLnNpbihZcG9zKSAqIFhwb3MgLyA3MCArIFwncHgpXCcNCiAgICAgICAgICAgIH0pOw0KDQogICAgICAgICAgICAke1smKiZdfShcIm54YnI6bnRoLW9mLXR5cGUoNG4rMSk6bm90KFwnLm5vcm1hbFwnKVwiKS5jc3MoeyAvL2NvbG9yOlwnYmx1ZVwnLA0KICAgICAgICAgICB7WyYqJl19ICAgICBcJ3RyYW5zZm9ybVwnOiBcJ3BlcnNwZWN0aXZlKDMwMHB4KSByb3RhdGVYKFwnICsgKDI1ICogKFhwb3MgKyA1MCkgLyAxMDApICt7WyYqJl19IFwnZGVnKSByb3RhdGV5KFwnICsgKDI1MCAqIChZcG9zIC0gNTApIC8gMTAwKSArIFwnZGVnKSB0cmFuc2xhdGV6KFwnICsgKDU1ICsgTWF7WyYqJl19dGgudGFuKFhwb3MpKSArIFwncHgpXCcNCiAgICAgICAgICAgIH0pOw0KDQogICAgICAgICAgICAkKFwibnhicjpudGgtb2YtdHlwZSg0bntbJiomXX0rMik6bm90KFwnLm5vcm1hbFwnKVwiKS5jc3MoeyAvL2NvbG9yOlwncmVkXCcsDQogICAgICAgICAgICAgICAgXCd0cmFuc2Zvcm1cJzogXCdwZXJ7WyYqJl19c3BlY3RpdmUoMzAwcHgpIHJvdGF0ZVgoXCcgKyAoLTE1ICogKFlwb3MgKiBYcG9zICsgNTApIC8gMTAwKSArIFwnZGVnKSByb3RhdGV5e1smKiZdfShcJyArICgtMTAgKiAoWXBvcyArIDUwKSAvIDEwMCkgKyBcJ2RlZykgdHJhbnNsYXRleig0NXB4KVwnIC8veW91IGNhbiB0dXJuIC0xMCB7WyYqJl19dG8gLTM2MCBvciBtb3JlIGZvciBkcmFzdGljIHJvdGF0aW9uIGVmZmVjdHMuIE9yIHlvdSBjYW4gYWRkIDM2MCBpbnRlYWQgb2YgbXtbJiomXX11bHRpcGx5aW5nIGl0LCB0byBtYWtlIGl0IHNwaW4gb25jZSBiZWZvcmUgc2V0dGxpbmcgb24gbGVzcyBvZiBhIGRyYXN0aWMgcm90e1smKiZdfWF0aW9uDQogICAgICAgICAgICAgICAgICAgIC8vbmVlZCB0byBpbmNsdWRlIHBlcnNwZWN0aXZlIGluIGVhY2ggZGVjbGFyYXRpb257WyYqJl19IGJlY2F1c2UgaW4gRmlyZWZveCBpdCBkb2VzblwndCBpbmhlcml0IGRvd24gcGFzdCBpbW1lZGlhdGUgY2hpbGRyZW4gb2YgZWxlbWV7WyYqJl19bnQgaXRcJ3MgYXBwbGllZCB0bw0KICAgICAgICAgICAgfSk7DQoNCiAgICAgICAgICAgICQoXCJueGJyOm50aC1vZi10eXBlKDRuKzMpe1smKiZdfTpub3QoXCcubm9ybWFsXCcpXCIpLmNzcyh7IC8vY29sb3I6XCdwdXJwbGVcJywNCiAgICAgICAgICAgICAgICBcJ3RyYW5zZm9ybVwnOiBcJ3BlcntbJiomXX1zcGVjdGl2ZSgzMDBweCkgcm90YXRlWChcJyArICg3ICogKFhwb3MgLyA1MCkgLyAxMDApICsgXCdkZWcpIHJvdGF0ZXkoXCcgKyAoMzYwe1smKiZdfSArIC0xNSAqIChNYXRoLnRhbihZcG9zKSAqIDEwMCAtIDUwKSAvIDEwMCkgKyBcJ2RlZykgdHJhbnNsYXRleihcJyArICgyNSAqIChYcHtbJiomXX1vcyAvIChZcG9zICsgMjAwKSArIC41KSkgKyBcJ3B4KVwnDQogICAgICAgICAgICB9KTsNCg0KICAgICAgICB9KTsNCg0KICAgIH0NCn17WyYqJl19KTsNCg0KLy9dXSZndDsNCg0KXCI7e1smKiZdfQ=={!{/code}!}

That’s about it. There’s plenty of cruft in there, and if you look at the page code it’s even messier… it includes javascript libraries it doesn’t need, etc. It’s pretty obvious I was still figuring all this out back then. But, hey, it works! Just ask anyone who’s tried to click one of the links to access one of the internal pages, if anyone ever had.

There was just a little bit more CSS and jQuery, to get the “stop” button working, which I’ll add here at a later date.