Website Breakdown
A simple article that'll break down how I ended up doing various parts of my website, from the layout to err ... maybe other things in the future; the layout was the thing that I hated the most in trying to figure out and optimize, so it'll be the first and primary one.
(PrismJS was used to colour code the coding for this page.)
Jump to: layout / helper classes / ::before and ::after decos / reader mode only
Layout
My original layout was based off the skyline theme that sadgrl had remade, and you can see the remnants of it lingering about. My old system used to be grid based, but after gutting my entire site all over again, I've changed it up again in how I have it organized. It's a simple flexbox system this time around, with the left sidebar and right sidebar having defined widths, and the middle being set to auto-fill.
CSS File
:root {
/* SIZES + SPACING */
--blog-size: 1100px;
--grid-gap: 13px;
--body-gap: 13px;
--left-sidebar-size: 250px;
--right-sidebar-size: 220px;
}
/* -------------------------------------------------------- */
/* GRID LAYOUT */
/* -------------------------------------------------------- */
#container-grid {
margin-left: 50px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: var(--grid-gap);
width: var(--blog-size);
}
#left-sidebar {
display: flex;
flex-direction: column;
gap: var(--body-gap);
/* force sidebar to one size only */
max-width: var(--left-sidebar-size);
min-width: var(--left-sidebar-size);
margin-top: 20px;
height: fit-content;
position: sticky;
top: 75px;
text-align: center;
}
main,
main > article {
display: flex;
flex-direction: column;
gap: var(--body-gap);
min-width: 0; /* ...? why the fuck does this fix the flexbox being too big ... */
max-width: calc(
var(--blog-size) - (var(--left-sidebar-size) + (calc(var(--grid-gap) * 2)))
); /* literally the px number is just grip-gap x2 */
}
aside {
display: flex;
flex-direction: column;
gap: var(--body-gap);
/* force sidebar to one size only */
max-width: var(--right-sidebar-size);
min-width: var(--right-sidebar-size);
width: 100%;
margin-top: 20px;
}
#left-sidebar > section,
main > section,
aside > .section {
background-color: var(--body-bg);
border-radius: var(--border-radius);
box-shadow: 6px 6px 0 var(--body-outline);
position: relative;
padding: 1em;
width: auto;
}
HTML File
<body>
<!-- =============================================== -->
<!-- Accessibility links. -->
<!-- =============================================== -->
<div id="skip"><a href="#content">Skip to content</a></div>
<nav-header></nav-header>
<!-- =============================================== -->
<!-- BODY BEGINS. -->
<!-- =============================================== -->
<div id="container-grid">
<left-sidebar></left-sidebar>
<!-- =============================================== -->
<!-- MAIN CONTENT BEGINS. -->
<!-- =============================================== -->
<main id="content">
<section>
<h1>Title</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In accumsan quis urna et sodales. Donec
ac leo eu mauris vehicula varius. Vivamus justo odio, efficitur et finibus et, ultrices in leo.
Nam sed vestibulum felis. Quisque cursus blandit semper. Interdum et malesuada fames ac ante
ipsum primis in faucibus. Fusce luctus justo vel purus scelerisque, eget scelerisque libero
tempor. Quisque eget luctus dolor. Nam sit amet tellus mauris. Integer at ullamcorper nulla.
Curabitur a faucibus tortor. In vehicula congue turpis a viverra. Sed felis felis, finibus vel
diam a, tincidunt egestas nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
efficitur cursus scelerisque. Vestibulum condimentum odio dui, a feugiat dolor faucibus non.
</p>
</section>
</main>
<aside>
<section>
<div class="title">Wow a cool aside chunk goes here</div>
</section>
</aside>
</div>
<a href="#skip" id="backscroll" class="backscroll" title="Go to top">Top</a>
<general-footer></general-footer>
<!-- Tippy.js -->
<script src="https://unpkg.com/popper.js@1"></script>
<script src="https://unpkg.com/tippy.js@5"></script>
<script src="/js/tippy-deco.js"></script>
<!-- PAGE ONLY SCRIPTS -->
</body>
... and if I remove the aside, then the main body (like here) stretches to fit out the rest of the 'blog size'. I did have to do some bullshit calculation for the main body size; I wish I could give a more thorough explanation for the math behind it, but basically it just takes away the left sidebar width from the full size, and adds the two "grid gaps" that would've existed.
As you can also tell, I reuse my header, left sidebar, and footer using javascript so I don't need to rewrite it for each page. This isn't the full code (I trimmed out my nav headers + some left sidebar chunks), but it is the bones of my layout + my image randomizer.
Layout.js
document.addEventListener("DOMContentLoaded", function () {
// Page has finished loading. Now, do things.
new NavHeader();
new LeftSidebar();
new GeneralFooter();
// Add any custom JavaScript code here...
var bodyElem = document.querySelector("body");
var fontForm = document.getElementById("fontFamily");
if (!localStorage.getItem("fontFamily")) {
populateStorage();
} else {
setStyles();
}
function populateStorage() {
localStorage.setItem("fontFamily", document.getElementById("fontFamily").value);
setStyles();
}
function setStyles() {
var currentFont = localStorage.getItem("fontFamily");
document.getElementById("fontFamily").value = currentFont;
bodyElem.style.fontFamily = currentFont;
}
fontForm.onchange = populateStorage;
});
/* TAB TITLE INTEGRATION */
const tabTitle = document.title;
if (tabTitle !== "aid's little corner") {
document.title = tabTitle + " • aid's little corner";
}
/* BEGIN HEADER */
const content = `
<!-- HEADER -->
<header>
<div class="title">aid's small corner</div>
<div class="subtext">a little personal site</div>
</header>
<!-- FONT TOGGLE -->
<div class="font-wrapper">
<label for="fontFamily" class="title">Font</label>
<select name="fontFamily" id="fontFamily">
<option value="Nunito">Nunito</option>
<option value="Open Dyslexic">Open Dyslexic</option>
<option value="Intel One">Intel One</option>
<option value="Atkinson">Atkinson Hyperlegible</option>
</select>
</div>
<!-- NAVIGATION -->
<nav>
<button id="toggle-0" aria-label="Toggle main menu">☰</button>
<ul id="menu-0">
<li id="item-1-0-0"><a id="link-1-0-0" href="/index.html">Home</a></li>
<li id="item-2-0-0"><a id="link-2-0-0" href="/about.html">About</a></li>
<li id="item-3-0-0"><a id="link-3-0-0" href="/gallery.html">Art</a></li>
<li id="item-4-0-0" class="dropdown">
<a id="link-4-0-0" href="#">Personal</a>
<ul id="menu-4">
<li id="item-4-1-0"><a id="link-4-1-0" href="https://zhongvie.bearblog.dev/">Blog</a></li>
<li id="item-4-2-0"><a id="link-4-2-0" href="/diary/index.html">Diary</a></li>
<li id="item-4-3-0"><a id="link-4-3-0" href="/manifesto.html">Manifesto</a></li>
<li id="item-4-4-0"><a id="link-4-4-0" href="/blog.html">Microblog</a></li>
<li id="item-4-5-0"><a id="link-4-5-0" href="/now.html">Now</a></li>
</ul>
</li>
</ul>
</nav>
`;
class NavHeader extends HTMLElement {
constructor() {
super();
this.innerHTML = content;
}
}
customElements.define("nav-header", NavHeader);
/* BEGIN LEFT SIDEBAR */
class LeftSidebar extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = `
<div id="left-sidebar">
<section id="intro">
<div class="img-floatinganim">
<img class="dendro" src="/img/decos/dendro_symbol.png" aria-hidden="true" alt="" />
</div>
<div id="sidedeco"></div>
</section>
<section>
<div class="description">
<div class="title">Welcome!</div>
<p style="text-align: center">
<b>aid</b>
<img
style="padding-left: 5px; padding-right: 5px"
src="/img/decos/flower_bullet.png"
aria-hidden="true"
alt="" />
<b>25+</b>
<img
style="padding-left: 5px; padding-right: 5px"
src="/img/decos/flower_bullet.png"
aria-hidden="true"
alt="" />
<b>she/her</b>
</p>
<hr />
<p>Welcome to my silly lil corner, hope you enjoy your stay!!</p>
</div>
</section>
<section>
<div class="title">
Site Button
</div>
<div class="site-button">
<div class="flexbox-lazy">
<div>
<a href="https://zhongvie.neocities.org/" target="_blank" class="block"
><img src="/img/zhongvie_button_1.gif" alt="zhongvie button" style="min-width: 88px;"
/></a>
</div>
<div>
<textarea id="site-button" name="site-button" style="width: 100px">
<a href="https://zhongvie.neocities.org/"><img src="https://file.garden/Zq0xOX6Iv3i3b1te/Neocities/sylvieButton.gif" alt="zhongvie button" loading="lazy"></a></textarea
>
</div>
</div>
<label for="site-button" class="subtle" style="text-align: center; line-height: 0.5em;"
>Please do not hotlink. <a href="./links.html">Alt buttons</a>.</label
>
</div>
</section>
<section>
<div class="flexbox-lazy" style="padding: 0">
<a
href="https://www.tumblr.com/lavendergalactic" style="text-decoration: none"
title="gifs by lavendergalactic as a commission for me. please don't use.">
<img src="/img/shiny/bites%20you%20shiny%20button.gif" alt="shiny button that says bites you" />
<img src="/img/shiny/silly%20shiny%20button.gif" alt="shiny button that says silly" />
<img src="/img/shiny/zhongvie%20shiny%20button.gif" alt="shiny button that says zhongvie" /></a>
</div>
</section>
</div>
`;
}
}
customElements.define("left-sidebar", LeftSidebar);
// DO IMAGE REROLL THINGS
const images = [
{
imagesrc: "/img/sidebar/yippe.gif",
alt: "A small dancing yippee creature of Sylvie.",
url: "https://vgen.co/cakepawzz"
},
{
imagesrc: "/img/sidebar/sylvie_chibi_1.jpg",
alt: "A small chibi of Sylvie sitting and looking at a flower in their hand.",
url: "https://twitter.com/magaridilatte"
},
{
imagesrc: "/img/sidebar/sylvie_chibi_4.jpg",
alt: "A small chibi of Sylvie waving at the viewer.",
url: "https://twitter.com/magaridilatte"
}
];
var randomIndex = Math.floor(Math.random() * images.length);
const finalImage =
"<a href='" +
images[randomIndex].url +
"' class='block'><img src='" +
images[randomIndex].imagesrc +
"' alt='" +
images[randomIndex].alt +
"' loading='lazy'/></a>";
document.getElementById("sidedeco").innerHTML = finalImage;
/* BEGIN FOOTER */
const footer = `
<footer>
<p>
2025 © lovingly coded by <a href="https://justinjackson.ca/webmaster/">aid</a> • <a href="/changelog.html">changelog</a> • <a href="/credits.html">credits</a> • <a href="/feed.xml">rss</a> • <a href="https://asuraid.atabook.org/">guestbook</a> • <a href="https://revospring.net/@asuraid">askbox</a> • <a href="mailto:sylviegirly@pm.me">contact me</a>
</p>
</footer>
`;
class GeneralFooter extends HTMLElement {
constructor() {
super();
this.innerHTML = footer;
}
}
customElements.define("general-footer", GeneralFooter);
HTML Portion
<!-- Preloading -->
<link rel="preload" href="/css/style.css" as="style" />
<link rel="preload" href="/js/layout.js" as="script" />
<!-- CSS: -->
<link rel="stylesheet" href="/css/style.css" />
<link rel="stylesheet" href="/css/normalize.css" />
<!-- JavaScript: -->
<script src="/js/layout.js" defer></script>
<script src="/js/navigation.js" type="module"></script>
(Thanks to reyn for bringing this up in their website breakdown for the preloading...)
This also handles the logic of my font changer to maintain/remember what font you chose (thanks to punkwasp for the code), this is the only thing stored from my site. This also includes a snippet from petrapixel to have my tab title included (like you see 'aid's little corner' above).
My navigation header is using the WCAG navbar by Nick DJM, I wish I had a better breakdown for it, but I genuinely don't remember how I got it to work. You're free to dig through my style sheet and check out my nav section, and the navigation.js item.
Mobile responsiveness is mostly just changing the layout to be columns, nuking the left sidebar and aside, and profit (hiding anything using a helper code that just hides it on mobile only). You can check out some of my templates to see it in action in the code, since it's the same logic I use here.
Helper Classes
I tend to like using helper classes a lot now that I've gotten more used to it ... aka very lazy and quick coding snippets I can slap on top of something. Lazy flexbox? Got you:
/* lazy flexbox for items */
.flexbox-lazy {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: center;
align-content: center;
align-items: center;
padding: 5px;
gap: 5px;
}
.flexbox-lazy a {
text-decoration: none;
line-height: 0;
}
Quick class you can add to images to make them float, plus go to a block display on mobile? Yep, got that too:
.float-img-right {
max-width: 40%;
float: right;
margin: 5px 0 5px 10px;
}
.float-img-left {
max-width: 40%;
float: left;
margin: 5px 10px 5px 0;
}
@media screen and (max-width: 800px) {
/* float image fixes */
.float-img-right {
float: none;
display: block;
margin-left: auto;
margin-right: auto;
max-width: 50%;
}
.float-img-left {
float: none;
display: block;
margin-left: auto;
margin-right: auto;
max-width: 50%;
}
}
I even have a simple CSS class I can plop on a link, button, or image to just 'disable' it temporarily and pop a warning cursor when hovering over it. Really good for the pages I've not finished LMAO.
.disabled {
opacity: 0.6;
cursor: not-allowed;
}
I'm not going to list all of my helper codes, but they're really nice to have, especially since I use the same CSS styling across my whole page ... but you could always made a CSS file you call on every page that has easily accessible helper codes, especially if you make more unique layouts.
Decorative ::before and ::after
I'll write this up eventually ... case in point is my H1 and my sidebar titles.
Reader Mode Only
I'll expand on this sooner, but I used this tutorial for visually hiding stuff andtabindex="-1" for avoiding things being focused on
when using tab.