How the Sausage Garden Is Made
A field guide to the lively parts of this blog
A field guide to the lively parts of this blog
Why this exists
I rebuilt parts of this blog to explore non-linearity in thinking. I'm a visual thinker, and I subscribe to the philosophy that any work can be a channel for artistic expression. My blog is especially that to me: a place where I explore, tinker, reflect, learn, and build my taste.
While I love beautiful, non-linear digital spaces, like the blogs of Maggie Appleton and Amelia Wattenberger, I don't quite have their skill for creating digital works of art.
So I decided to use AI as my coach. I rebuilt my digital garden, and then had it teach me how it was done.
The result was a redesigned landing page and an experiment in adding non-linearity and life to my writing manifesto, Writing the Thing.
This post dissects the techniques used to make them.
The map
The vertical ruler on the landing page is not an image and not a series of borders. It is one line drawn behind the entire list.
First, make a coordinate system. An absolutely positioned element needs an ancestor to measure itself against. Giving the parent position: relative establishes that boundary.
Then, generate the line. ::before creates a decorative box without adding meaningless HTML. Stretch it from top: 0 to bottom: 0, and put its left edge at half the parent's width.
.timeline {
position: relative; /* establish the coordinate system */
}
.timeline::before {
content: ""; /* make the pseudo-element exist */
position: absolute;
top: 0;
bottom: 0; /* stretch it vertically */
left: 50%; /* place it in the middle */
border-left: 1px solid currentColor;
}
The posts appear to wander, but every row lives on the same strict three-column grid.
.item {
display: grid;
grid-template-columns:
minmax(0, 1fr)
3rem
minmax(0, 1fr);
}
.item.left .summary { grid-column: 1; text-align: right; }
.item.right .summary { grid-column: 3; text-align: left; }
.item .marker { grid-column: 2; }
fr means a fraction of the free space. The two 1fr columns therefore remain equal. The fixed middle column reserves breathing room around the ruler.
minmax(0, 1fr) is a defensive version of 1fr. The zero allows a long title to shrink or wrap instead of forcing the grid wider than the screen.
The page is not unaligned. It alternates between two alignments.
Left-hand entries are right-aligned as they approach the axis. Right-hand entries are left-aligned as they leave it. The eye travels across the page.
The manifesto looks loosely arranged. It is not random. Several small, repeating rules overlap until the pattern becomes difficult to notice.
li:nth-child(3n + 2) {
margin-left: clamp(0rem, 6vw, 5rem);
}
li:nth-child(4n + 1) { transform: rotate(-.45deg); }
li:nth-child(4n + 3) { transform: rotate( .55deg); }
li:hover { transform: translateX(.35rem) rotate(0); }
:nth-child() selects elements by their position. 3n + 2 means the second item in every group of three: 2, 5, 8, and so on.
clamp(min, preferred, max) is deterministic, not random. The browser calculates the preferred value at the current screen size, then prevents it from falling below the minimum or exceeding the maximum. In clamp(0rem, 6vw, 5rem), the indent is 6% of the viewport width until that value reaches the 5rem ceiling.
The restraint matters. Half a degree disturbs a baseline. Five degrees turns every sentence into a sticker. The intention is not to advertise the effect, only to make the page feel less mechanical.
The manifesto separates its repeated conclusion from its changing premises. Scroll through this section and watch the large phrase stay present.
.field {
display: grid;
grid-template-columns: 4fr 6fr;
}
.refrain {
position: sticky;
top: 3rem;
align-self: start;
}
No JavaScript is watching the scroll position. The browser works from two pieces of information: the element's normal position in the document and the boundary established by its containing section.
The element participates in normal document flow. It takes up space in the grid and scrolls toward the top like everything else.
top: 3rem establishes a constraint. When scrolling would move the element above that line, the browser offsets it just enough to hold it there.
The element is not allowed to escape its containing section. When the section's bottom reaches it, the browser stops applying that offset, and both leave the viewport together.
align-self: start also matters inside this grid. Grid items stretch by default. A stretched element can occupy the full height of its row, leaving it nowhere to travel. Aligning it to the start keeps it only as tall as its contents.
This is more than a visual trick. It lets two parts of an argument exist at once: a fixed proposition and changing examples. The same primitive could hold a question beside several answers, a hypothesis beside evidence, or an AI agent's interpretation beside its sources.
A pseudo-element can borrow the dimensions of a word, which makes it useful for marks that feel drawn onto the page.
This page was built with ordinary CSS.
.handmark {
position: relative;
display: inline-block;
}
.handmark::after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: .08em;
width: 100%;
height: .16em;
background: var(--accent);
transform: rotate(-1deg);
}
inline-block makes the wrapper exactly as wide as its contents. The generated mark can then use width: 100%.
The negative z-index places the mark behind the letters. A one-degree rotation removes its machine-perfect edge.
Hover or focus each line
The interaction should complete the thought. The negative statement receives a strike. The positive statement receives a check. The movement is small, but its meaning belongs to the sentence.
CSS knows how a filtered timeline should look. JavaScript only needs to decide what is visible and which side each remaining item belongs on.
::beforefunction filterBy(tag) {
const items = document.querySelectorAll("[data-garden-tags]");
items.forEach(function (item) {
const tags = item.dataset.gardenTags.split(" ");
item.hidden = tag !== "all" && !tags.includes(tag);
});
reflowVisibleItems();
}
data-garden-tags="css writing" stores information on the element without inventing a visual class. JavaScript reads it through element.dataset.gardenTags.
After filtering, the visible items are counted again. Even-numbered items receive the left class; odd-numbered items receive the right class. JavaScript changes semantic state. CSS remains responsible for pixels.
Responsive design does not require squeezing the desktop composition into a phone. It requires deciding which idea must survive.
@media (max-width: 640px) {
.item {
grid-template-columns: 1.4rem minmax(0, 1fr);
}
.summary {
grid-column: 2;
text-align: left;
}
.refrain {
position: relative; /* stop sticking */
}
}
On this blog, the centered ruler becomes a left-hand rail. The sticky two-column manifesto becomes a normal vertical flow. Rotations and long connector lines disappear.
The choreography is sacrificed before readability is. The timeline remains a timeline. The refrain remains larger than its examples. The idea survives even when the arrangement changes.
Create a clear order.
Then let a few things
gently create some disorder.
Get notified when new posts are published.