blog-bootstrap Meta-Blog

Where I write down what I did, how I did it, what I want to do, how I want to do it, and any other information involved in and about the process of creation of the content of this blog.


How I fixed the giant blank gap under image-heavy articles

The "Went to IKEA to do some product comparisons." article had a massive empty space at the bottom whenever it was expanded.

Fri Aug 7 09:11:28 PM PDT 2026 by Daniel

Both of blog.js's height functions, getFullHeight() and getHeightForFirstN(n), computed an article's height by looping over its direct children and adding up each one's own offsetHeight:

let height = contentChildren.reduce((acc, el) => {
    const style = getComputedStyle(el);
    return acc + el.offsetHeight + parseFloat(style.marginTop) + parseFloat(style.marginBottom);
}, 0);

That assumes every child sits on its own row, stacked one under the next — true for block-level elements like <h3>, <p>, and <table>. But <img> defaults to display: inline, and blog.css has no rule that changes that. Consecutive <img> tags flow like words in a sentence — they sit side by side and only wrap to a new line when they run out of horizontal room, exactly like text.

The IKEA article has two runs of images (5 photos, then 7 more) that actually render as just 2 visual rows. I confirmed this in the browser console: all 5 images in the first run shared the same rendered top offset, and all 7 in the second run shared a different single top. But the summing loop added up all 12 images' heights as if each occupied its own row — 3318px of summed heights versus 767px of real visual content. Since the article has overflow: hidden, the box just got set to that inflated 3318px-ish height and the real content sat at the top, leaving a huge blank area below it.

The fix was to stop reimplementing layout math and just read the browser's own measurements instead:

  • getFullHeight() now simply returns article.offsetHeight once the article's height is set to 'auto' — the browser has already laid out any wrapped inline content correctly, so there's nothing left to compute. This also made the old getBrHeight() special-case for <br> unnecessary, since native layout handles that too.
  • getHeightForFirstN(n) now takes the actual rendered getBoundingClientRect() of the Nth included child and measures down from the article's own top edge, rather than summing individual child heights.

The first version of this fix introduced a smaller follow-up bug: it added the article's own bottom padding as trailing space after the cut-off point, but since the next (hidden) child sits immediately after with no gap, that padding just revealed a sliver of its text. I caught this by actually looking at a screenshot of the collapsed articles, not just checking that the previously-broken one now worked. The real fix measures the actual rendered gap to whatever child follows the cutoff (which already accounts for CSS margins correctly, no matter what the next element is), and only falls back to the article's own padding when there's no next child at all — i.e. when the "preview" is actually the whole article.

Verified in Chromium via the claude-in-chrome extension: the IKEA article now expands to hug its content with no extra gap, the earlier Expand/Collapse fix (see the entry below) still works on the "Harry Sends..." articles, and an article with a <br> and several tables still renders with normal padding, not an inflated one.

How I diagnosed two articles that wouldn't Expand/Collapse

Two articles in the main blog had working-looking Expand/Collapse controls that didn't actually resize anything when clicked.

Fri Aug 7 08:35:00 PM PDT 2026 by Daniel

The main blog's blog.js gives every <article> an Expand/Collapse toggle. Collapsed, it shows a short preview; expanded, it shows everything. It does this by measuring two heights and animating between them:

  • getFullHeight() — the height of every child element inside the <article>.
  • getHeightForFirstN(3) — the height of just the first 3 child elements.

The "Harry Sends..." email articles each consist of exactly 3 top-level children: an <h3>, a <p class="meta"> timestamp, and an <iframe> with the email content. Since "first 3 children" and "all children" were the same 3 elements, the collapsed and expanded heights came out identical — the toggle still flipped its label between "Expand" and "Collapse", but the article never visibly changed size.

The fix was to stop hardcoding 3 and instead compute the preview size from each article's own structure: the heading, plus however many class="meta" siblings immediately follow it.

const getCollapsedChildCount = () => {
    let count = 0;
    if (contentChildren.length > 0 && /^H[1-6]$/.test(contentChildren[0].tagName)) {
        count = 1;
    }
    while (count < contentChildren.length && contentChildren[count].classList.contains('meta')) {
        count++;
    }
    return count;
};

applyState() now calls getHeightForFirstN(getCollapsedChildCount()) instead of getHeightForFirstN(3). Every article's preview now scales to its own heading + meta block, so an article only fails to visibly toggle if its heading and meta lines really are its entire content.

To verify, I served the blog with python3 -m http.server, loaded it in Chromium via the claude-in-chrome extension, cleared localStorage to reset all articles to their default state, and clicked Expand/Collapse on both previously-broken articles and on a normal article to confirm nothing regressed.

Meta-Post about What I wish Chromium DevTools (and what Chromium) would do

Chromium is pretty great. Chromium DevTools is pretty great too. DevTools is almost a full featured IDE. To make it so, what would I want it to do?

25-05-15 10:17 (UTC-7) by Daniel

I really like that I can edit source using the "Workspace" feature of DevTools. I also like that I can manually reload the page by typing location.reload().

I wish I could make DevTools do that whenever I did ^s (control-s). i.e. whenever I save the file.

Hello $s^3$ katex