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.

    iOS app shell: nav bar, tab bar, push, sheet and split view

    A UITabBarController + UINavigationController shell built from constraints.

    Full page
    <!--
      A UITabBarController + UINavigationController shell. Every bar, guide, scroll view,
      pushed screen and sheet is placed by data-⚓️-* attributes. Positioned siblings instead
      of nested subviews: an anchor has to be a descendant of the target's containing block,
      so a bar's buttons sit next to the bar and constrain to it by name.
      The attributes below are the compact (iPhone) constraint set; script.js activates the
      regular (iPad split view) set on a size-class change, like NSLayoutConstraint.activate().
    -->
    <div class="window" data-⚓️-name="--window" data-size="compact" data-sim>
    <div class="app" data-⚓️-root>
    
      <!-- ===== layout guides (UILayoutGuide) — invisible boxes other views constrain to ===== -->
      <div class="guide g-screen"    data-key="screen"    data-⚓️-name="--screen"    data-⚓️-pin-all></div>
      <div class="guide g-safe"      data-key="safe"      data-⚓️-name="--safe"      data-⚓️-pin-all></div>
      <div class="guide g-primary"   data-key="primary"   data-⚓️-name="--primary"   data-⚓️-pin-all></div>
      <div class="guide g-secondary" data-key="secondary" data-⚓️-name="--secondary" data-⚓️-pin-all></div>
    
      <!-- ===== navigation bar (anchor) + tab bar (anchor) ===== -->
      <div class="nav" data-key="nav" data-⚓️-name="--nav"
           data-⚓️-to="--safe" data-⚓️-align-top data-⚓️-stretch-x="--primary"></div>
    
      <nav class="tabbar" data-key="tabbar" data-⚓️-name="--tabbar" aria-label="Tabs"
           data-⚓️-to="--safe" data-⚓️-align-bottom data-⚓️-stretch-x="--screen">
        <button class="tab" data-tab="listen" aria-pressed="false">
          <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path class="solid" d="M10 8.2v7.6l6-3.8z"/></svg>
          <span>Listen Now</span>
        </button>
        <button class="tab" data-tab="library" aria-pressed="true">
          <svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="7" width="18" height="14" rx="3"/><path d="M6 4h12M8.5 1.5h7"/></svg>
          <span>Library</span>
        </button>
        <button class="tab" data-tab="search" aria-pressed="false">
          <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m15.5 15.5 5 5"/></svg>
          <span>Search</span>
        </button>
      </nav>
    
      <!-- ===== the scroll view: top = navBar.bottom, bottom = tabBar.top ===== -->
      <main class="content" data-key="content" data-⚓️-name="--content"
            data-⚓️-below="--nav" data-⚓️-above="--tabbar" data-⚓️-stretch-x="--primary">
    
        <section class="panel" data-panel="library">
          <h1 class="large-title">Library</h1>
    
          <h2 class="group-head">Auto Layout</h2>
          <ul class="group">
            <li><label class="cell switch-cell"><span>Simulate safe area</span><input type="checkbox" role="switch" id="opt-sim" checked></label></li>
            <li><label class="cell switch-cell"><span>Extend under bars</span><input type="checkbox" role="switch" id="opt-extend"></label></li>
            <li class="wide-only"><label class="cell switch-cell"><span>Compact width (iPhone)</span><input type="checkbox" role="switch" id="opt-compact"></label></li>
          </ul>
          <p class="group-foot">Extend under bars swaps the scroll view's top/bottom constraints from the bars to the superview, so content scrolls behind the blur.</p>
    
          <h2 class="group-head">Recently Added</h2>
          <ul class="group albums">
            <li><button class="cell album-row" data-hue="18" style="--hue: 18"  data-title="Currents" data-artist="Tame Impala" data-year="2015" data-tracks="Let It Happen|Nangs|The Moment|Yes I'm Changing|Eventually|Gossip">
              <span class="art" aria-hidden="true"></span><span class="lines"><b>Currents</b><small>Tame Impala</small></span><i class="chev" aria-hidden="true"></i></button></li>
            <li><button class="cell album-row" data-hue="200" style="--hue: 200" data-title="In Rainbows" data-artist="Radiohead" data-year="2007" data-tracks="15 Step|Bodysnatchers|Nude|Weird Fishes/Arpeggi|All I Need|Reckoner">
              <span class="art" aria-hidden="true"></span><span class="lines"><b>In Rainbows</b><small>Radiohead</small></span><i class="chev" aria-hidden="true"></i></button></li>
            <li><button class="cell album-row" data-hue="300" style="--hue: 300" data-title="Random Access Memories" data-artist="Daft Punk" data-year="2013" data-tracks="Give Life Back to Music|The Game of Love|Giorgio by Moroder|Within|Instant Crush|Get Lucky">
              <span class="art" aria-hidden="true"></span><span class="lines"><b>Random Access Memories</b><small>Daft Punk</small></span><i class="chev" aria-hidden="true"></i></button></li>
            <li><button class="cell album-row" data-hue="140" style="--hue: 140" data-title="Blonde" data-artist="Frank Ocean" data-year="2016" data-tracks="Nikes|Ivy|Pink + White|Solo|Self Control|Nights">
              <span class="art" aria-hidden="true"></span><span class="lines"><b>Blonde</b><small>Frank Ocean</small></span><i class="chev" aria-hidden="true"></i></button></li>
            <li><button class="cell album-row" data-hue="260" style="--hue: 260" data-title="Vespertine" data-artist="Björk" data-year="2001" data-tracks="Hidden Place|Cocoon|It's Not Up to You|Undo|Pagan Poetry|Aurora">
              <span class="art" aria-hidden="true"></span><span class="lines"><b>Vespertine</b><small>Björk</small></span><i class="chev" aria-hidden="true"></i></button></li>
            <li><button class="cell album-row" data-hue="60" style="--hue: 60" data-title="Moon Safari" data-artist="Air" data-year="1998" data-tracks="La Femme d'Argent|Sexy Boy|All I Need|Kelly Watch the Stars|Talisman|Remember">
              <span class="art" aria-hidden="true"></span><span class="lines"><b>Moon Safari</b><small>Air</small></span><i class="chev" aria-hidden="true"></i></button></li>
          </ul>
          <p class="group-foot">Tap an album to push it. On a regular-width window it opens in the split view's secondary column instead.</p>
        </section>
    
        <section class="panel" data-panel="listen" hidden>
          <h1 class="large-title">Listen Now</h1>
          <h2 class="group-head">Top Picks</h2>
          <ul class="group picks">
            <li class="cell pick" style="--hue: 330"><b>Late Night Anchors</b><small>Made for you</small></li>
            <li class="cell pick" style="--hue: 190"><b>Constraint Chill</b><small>Updated Friday</small></li>
            <li class="cell pick" style="--hue: 40"><b>Safe Area Classics</b><small>Hits from the notch era</small></li>
          </ul>
        </section>
    
        <section class="panel" data-panel="search" hidden>
          <h1 class="large-title">Search</h1>
          <label class="search"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m15.5 15.5 5 5"/></svg><input type="search" placeholder="Artists, Songs, Lyrics and More" aria-label="Search"></label>
          <h2 class="group-head">Recently Searched</h2>
          <ul class="group">
            <li class="cell">position-anchor</li>
            <li class="cell">anchor-size()</li>
            <li class="cell">@position-try</li>
          </ul>
        </section>
      </main>
    
      <!-- ===== bar backgrounds: extend past the safe area to the superview edges ===== -->
      <div class="bar-bg bar-top" data-key="barTop" data-⚓️-pin-top data-⚓️-stretch-x="--primary" data-⚓️-align-bottom="--nav" aria-hidden="true"></div>
      <div class="bar-bg bar-bottom" data-key="barBottom" data-⚓️-align-top="--tabbar" data-⚓️-pin-bottom data-⚓️-stretch-x="--screen" aria-hidden="true"></div>
    
      <!-- ===== navigation bar items ===== -->
      <p class="nav-title" data-key="navTitle" data-⚓️-to="--nav" data-⚓️-center-all>Library</p>
      <button class="bar-btn nav-action" data-key="navAction" aria-label="New playlist"
              data-⚓️-to="--nav" data-⚓️-align-trailing data-⚓️-align-y="center">
        <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
      </button>
    
      <!-- ===== pushed view controller ===== -->
      <section class="detail" data-key="detail" data-⚓️-name="--detail" aria-label="Album" inert
               data-⚓️-to="--screen" data-⚓️-side="after" data-⚓️-sync-width data-⚓️-pin-top data-⚓️-above="--tabbar"
               data-⚓️-transition="morph">
        <div class="guide d-safe" data-key="dSafe" data-⚓️-name="--d-safe" data-⚓️-pin-all></div>
        <div class="d-nav" data-key="dNav" data-⚓️-name="--d-nav" data-⚓️-to="--d-safe" data-⚓️-align-top data-⚓️-pin-x></div>
        <div class="d-content" data-key="dContent" data-⚓️-below="--d-nav" data-⚓️-pin-x data-⚓️-pin-bottom>
          <div class="album-head">
            <span class="hero-art" aria-hidden="true"></span>
            <h2 class="album-title">Currents</h2>
            <p class="album-artist">Tame Impala</p>
            <p class="album-meta">Psychedelic · 2015 · Lossless</p>
            <div class="actions">
              <button class="pill"><svg viewBox="0 0 24 24" aria-hidden="true"><path class="solid" d="M7 4.5v15l12-7.5z"/></svg>Play</button>
              <button class="pill"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 7h4l10 10h4M3 17h4l3-3m4-4 3-3h4m-3-3 3 3-3 3m0 4 3 3-3 3"/></svg>Shuffle</button>
            </div>
          </div>
          <ol class="tracks"></ol>
          <p class="group-foot tracks-foot"></p>
        </div>
        <div class="bar-bg d-bar" data-key="dBar" data-⚓️-pin-top data-⚓️-pin-x data-⚓️-align-bottom="--d-nav" aria-hidden="true"></div>
        <button class="bar-btn d-back" data-key="dBack" data-⚓️-to="--d-nav" data-⚓️-align-leading data-⚓️-align-y="center">
          <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15 4 7 12l8 8"/></svg><span>Library</span>
        </button>
        <p class="nav-title d-title" data-key="dTitle" data-⚓️-to="--d-nav" data-⚓️-center-all>Currents</p>
        <button class="bar-btn d-more" data-key="dMore" aria-label="Add to playlist"
                data-⚓️-to="--d-nav" data-⚓️-align-trailing data-⚓️-align-y="center">
          <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M7.5 12h.01M12 12h.01M16.5 12h.01" stroke-width="2.6"/></svg>
        </button>
      </section>
    
      <!-- ===== inspector button (a floating accessory view) ===== -->
      <button class="fab" data-key="fab" data-⚓️-name="--fab" aria-expanded="false" aria-controls="inspector"
              data-⚓️-to="--tabbar" data-⚓️-above data-⚓️-align-trailing="--safe">
        <svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="3"/><path d="M3 9h18M9 9v12"/></svg>
        <span>Constraints</span>
      </button>
    
      <!-- ===== simulated hardware (only when "Simulate safe area" is on) ===== -->
      <div class="sim status-bar" data-key="statusBar" data-⚓️-pin-top data-⚓️-pin-x data-⚓️-above="--safe" aria-hidden="true">
        <span class="time">9:41</span><span class="glyphs"><i></i><i></i><i></i></span>
      </div>
      <div class="sim island" data-key="island" data-⚓️-to="--screen" data-⚓️-align-top data-⚓️-align-x="center" aria-hidden="true"></div>
      <div class="sim home-indicator" data-key="home" data-⚓️-to="--screen" data-⚓️-align-bottom data-⚓️-align-x="center" aria-hidden="true"></div>
    </div>
    
    <!-- ===== modal sheet (UISheetPresentationController) ===== -->
    <div class="sheet" id="sheet" popover data-key="sheet" data-⚓️-name="--sheet" data-detent="medium" role="dialog" aria-labelledby="sheet-title"
         data-⚓️-to="--window" data-⚓️-align-bottom data-⚓️-stretch-x data-⚓️-sync-height>
      <div class="guide s-safe" data-key="sSafe" data-⚓️-name="--s-safe" data-⚓️-pin-all></div>
      <button class="grabber" data-key="grabber" aria-label="Resize sheet" data-⚓️-pin-top data-⚓️-pin-x data-⚓️-align-self="center"></button>
      <header class="s-head">
        <div><h2 id="sheet-title">Add to a Playlist</h2><p class="s-hint">Drag or tap the grabber for the large detent</p></div>
        <button class="s-close" popovertarget="sheet" popovertargetaction="hide" aria-label="Close">
          <svg viewBox="0 0 24 24" aria-hidden="true"><path d="m7 7 10 10M17 7 7 17"/></svg>
        </button>
      </header>
      <ul class="group s-list">
        <li><label class="cell check-cell"><span class="art" style="--hue: 330" aria-hidden="true"></span><span>Late Night Anchors</span><input type="checkbox"></label></li>
        <li><label class="cell check-cell"><span class="art" style="--hue: 190" aria-hidden="true"></span><span>Constraint Chill</span><input type="checkbox" checked></label></li>
        <li><label class="cell check-cell"><span class="art" style="--hue: 40"  aria-hidden="true"></span><span>Safe Area Classics</span><input type="checkbox"></label></li>
        <li><label class="cell check-cell"><span class="art" style="--hue: 100" aria-hidden="true"></span><span>Road Trip</span><input type="checkbox"></label></li>
      </ul>
      <button class="s-done" data-key="sDone" popovertarget="sheet" popovertargetaction="hide"
              data-⚓️-to="--s-safe" data-⚓️-align-bottom data-⚓️-stretch-x>Done</button>
    </div>
    
    <!-- ===== constraints inspector (doubles as X-ray) ===== -->
    <aside class="inspector" id="inspector" popover="manual" aria-label="Constraints inspector"
           data-⚓️-to="--fab" data-⚓️-above data-⚓️-align-trailing>
      <header><b>Constraints</b><span class="trait"></span></header>
      <div class="i-list"></div>
    </aside>
    <div class="hl-box" popover="manual" data-⚓️-to="--screen" data-⚓️-fill="--screen" data-⚓️-transition="glide" aria-hidden="true"></div>
    <div class="hl-label" popover="manual" data-⚓️-to="--screen" data-⚓️-side="below" data-⚓️-align-leading data-⚓️-try="flip-y" aria-hidden="true"></div>
    </div>

    data-⚓️-abovedata-⚓️-align-bottomdata-⚓️-align-leadingdata-⚓️-align-selfdata-⚓️-align-topdata-⚓️-align-trailingdata-⚓️-align-xdata-⚓️-align-ydata-⚓️-belowdata-⚓️-center-alldata-⚓️-filldata-⚓️-namedata-⚓️-pin-alldata-⚓️-pin-bottomdata-⚓️-pin-topdata-⚓️-pin-xdata-⚓️-rootdata-⚓️-sidedata-⚓️-stretch-xdata-⚓️-sync-heightdata-⚓️-sync-widthdata-⚓️-todata-⚓️-transitiondata-⚓️-try

    Copied