Anchored Auto Layout
npm

Hover or focus a box to measure it. Click its tag, or press ] and [, to pin one. Esc unpins.

    Legend
    • Anchor: a box with data-⚓️-name
    • Placed by anchors: out of flow
    • Gap from the anchor's edge, in px
    • Edges of the box you're inspecting

    Every tag, line and number here is itself placed by data-⚓️-* attributes. JS only measures.

    Card ↔ list view toggle

    Switch a music library between cards and a list: only the invisible grid changes, and three anchored layers per item (background, cover, text) morph to their new slots with data-⚓️-fill + data-⚓️-transition="morph".

    Full page
    <header class="intro">
      <h1>Card ↔ list view</h1>
      <p>
        The only thing the toggle changes is the invisible grid behind the tracks: the
        <code>.cell</code>s and their empty <code>.slot</code>s snap to the new layout instantly.
        The card background, cover art and text are three separate layers, each anchored to its own
        slot with <code>data-⚓️-fill</code> and <code>data-⚓️-transition="morph"</code>, so they morph
        to their new place and size on their own. <code>data-⚓️-scope="all"</code> lets every row reuse
        the same three anchor names. Zero JavaScript.
      </p>
      <form class="controls" aria-label="View controls">
        <fieldset class="segmented">
          <legend>View</legend>
          <label><input type="radio" name="view" value="grid" checked> <span aria-hidden="true">▦</span> Cards</label>
          <label><input type="radio" name="view" value="list"> <span aria-hidden="true">☰</span> List</label>
        </fieldset>
        <label class="xray-toggle"><input type="checkbox" name="xray"> X-ray <small>(green: <code>--item</code> cells, pink: <code>--cover</code>/<code>--text</code> slots)</small></label>
      </form>
    </header>
    
    <main data-⚓️-root>
    <ul class="library" aria-label="Tracks">
      <li class="cell" style="--hue: 250" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Blue Monday</strong>
          <span>New Order · 1983</span>
        </div>
      </li>
      <li class="cell" style="--hue: 200" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Teardrop</strong>
          <span>Massive Attack · 1998</span>
        </div>
      </li>
      <li class="cell" style="--hue: 330" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Windowlicker</strong>
          <span>Aphex Twin · 1999</span>
        </div>
      </li>
      <li class="cell" style="--hue: 170" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Hyperballad</strong>
          <span>Björk · 1995</span>
        </div>
      </li>
      <li class="cell" style="--hue: 290" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Midnight City</strong>
          <span>M83 · 2011</span>
        </div>
      </li>
      <li class="cell" style="--hue: 60" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Roygbiv</strong>
          <span>Boards of Canada · 1998</span>
        </div>
      </li>
      <li class="cell" style="--hue: 20" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Everything In Its Right Place</strong>
          <span>Radiohead · 2000</span>
        </div>
      </li>
      <li class="cell" style="--hue: 0" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Da Funk</strong>
          <span>Daft Punk · 1995</span>
        </div>
      </li>
      <li class="cell" style="--hue: 100" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Glory Box</strong>
          <span>Portishead · 1994</span>
        </div>
      </li>
      <li class="cell" style="--hue: 220" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Strobe</strong>
          <span>deadmau5 · 2009</span>
        </div>
      </li>
      <li class="cell" style="--hue: 140" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Gosh</strong>
          <span>Jamie xx · 2015</span>
        </div>
      </li>
      <li class="cell" style="--hue: 310" data-⚓️-name="--item" data-⚓️-scope="all">
        <span class="slot slot-cover" data-⚓️-name="--cover" aria-hidden="true"></span>
        <span class="slot slot-text" data-⚓️-name="--text" aria-hidden="true"></span>
        <div class="bg" data-⚓️-to="--item" data-⚓️-fill data-⚓️-transition="morph"></div>
        <div class="cover" data-⚓️-to="--cover" data-⚓️-fill data-⚓️-transition="morph" aria-hidden="true"></div>
        <div class="text" data-⚓️-to="--text" data-⚓️-fill data-⚓️-transition="morph">
          <strong>Porcelain</strong>
          <span>Moby · 1999</span>
        </div>
      </li>
    </ul>
    </main>

    data-⚓️-filldata-⚓️-namedata-⚓️-rootdata-⚓️-scopedata-⚓️-todata-⚓️-transition

    Copied