justin․searls․co

Takes, re-designed

Today, I updated the design of the short-form takes on this web site to look a little more distinctive and to better conform to the design of other "non-prose" posts. Like each podcast player, the take is rendered "beneath the page" as if the page has been cut out. Each component of the take is then rendered as a roundrect: my avatar, the text of the take, and the action links.

This design is roughly what I'd wanted to make for a while, but figuring out a responsive way to render a two-piece roundrect for takes that extend beyond the height of my avatar took a while to get right.

The approach to achieve this effect requires a lot of absolute positioning, with every component but the prose itself having a fixed height, and the two white-background roundrects that contain the prose being absolutely positioned and pinned relative to all four sides of the widget.

If you're curious how this was implemented, here's the markup and tailwind classes (most of which are stock, but this site uses a custom sizing scale):

<div class="mx-auto max-w-68">
  <div class="relative p-1 md:mt-6 md:mr-2 bg-secondary beneath-the-page list-inside-all">
    <!-- The top portion of the background of each take, pinned to the top and with width adjusted to make room for the avatar -->
    <div class="z-10 bottom-12 absolute w-[calc(100%-124px)] mr-1 top-1 ml-13.5 shadow-lg bg-primary rounded-xl">
    </div>
    <!-- The bottom portion of the background of the take, pinned to the bottom and with fuller width -->
    <div class="z-20 bottom-11.5 absolute w-[calc(100%-16px)] mr-1 top-14.5 shadow-lg bg-primary rounded-tl-xl rounded-bl-xl rounded-br-xl"
      data-min-height="20">
    </div>

    <a href="/about">
      <!-- my face, fixed width/height, floated to the left -->
      <img class="float-left w-12 h-12 mt-px mb-0 mr-2.5 shadow-2xl rounded-xl" src="/img/face.jpg">
    </a>
    <div class="relative z-30 px-1 text-lg pt-sm min-h-11.5 [&amp;>*:first-child]:mt-0 [&amp;>*:last-child]:mb-0">
      <!-- The take's inner HTML, rendered from markdown -->
    </div>
    <div class="flex flex-row justify-between h-5 px-2 mx-auto mt-3 rounded-lg shadow-lg max-w-48 py-sm bg-primary min-w-30">
      <!-- Action links & icons -->
    </div>
    <div class="h-3 pt-1 text-sm text-center mt-sm text-secondary/60">
      <!-- the like count & time -->
    </div>
  </div>
</div>

This was almost enough on its own, but the two take backgrounds needed to overlap to cover the rounded corners on the bottom of the top piece. As a result, sometimes there'd be an extra trailing white doo-dad without any text associated. For this, I needed a bit of JavaScript. So I put a data-min-height="20" on the background and wrote this script:

function enforceRenderingConstraintsFor (el) {
  if (el.dataset.minHeight != null) {
    el.classList.remove('hidden') // have to remove hidden first b/c otherwise el.clientHeight will be 0
    el.classList.toggle('hidden', el.clientHeight < parseInt(el.dataset.minHeight, 10))
  }
}

function enforceRenderingConstraints () {
  const elements = document.querySelectorAll('[data-min-height]')
  elements.forEach(enforceRenderingConstraintsFor)
}

window.addEventListener('DOMContentLoaded', enforceRenderingConstraints);
window.addEventListener('resize', enforceRenderingConstraints);

The design is pretty busy and a little cramped, but I dig it anyway.


Got a taste for fresh, hot takes?

Then you're in luck, because you can subscribe to this site via RSS or Mastodon! And if that ain't enough, then sign up for my newsletter and I'll send you a usually-pretty-good essay once a month. I also have a solo podcast, because of course I do.