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 profile with proportional constraints

    A UIKit-style profile screen built from Auto Layout constraints written as data-⚓️-* attributes, with proportional widths from sync-width and --⚓️-mult-x.

    Full page
    <div class="page" data-device="portrait" data-sc="compact">
      <header class="toolbar">
        <div class="brand">
          <strong>Proportional profile</strong>
          <span>UIKit Auto Layout, written as <code>data-⚓️-*</code></span>
        </div>
        <fieldset class="seg" aria-label="Device and size class">
          <legend>Device</legend>
          <label><input type="radio" name="device" value="portrait" checked> <span>Portrait</span></label>
          <label><input type="radio" name="device" value="landscape"> <span>Landscape</span></label>
          <label><input type="radio" name="device" value="ipad"> <span>iPad</span></label>
        </fieldset>
        <output class="trait" aria-live="polite">compact</output>
        <label class="switch"><input type="checkbox" name="inspect" role="switch"> Constraints</label>
      </header>
    
      <main class="stage">
        <div class="stage-main">
          <div class="device">
            <div class="screen app" data-⚓️-root data-⚓️-scope="all" data-size-class="compact">
    
              <div class="scroll" data-⚓️-root tabindex="0" aria-label="Mara Okafor profile">
                <!-- Layout guides (UILayoutGuide): invisible, only ever anchors -->
                <div class="g g-superview" data-⚓️-name="--superview" data-⚓️-pin-x data-⚓️-pin-top data-label="superview"></div>
                <div class="g g-margins" data-⚓️-name="--margins" data-⚓️-pin-x data-⚓️-pin-top data-label="layoutMarginsGuide"></div>
    
                <div class="cover" data-⚓️-name="--cover" data-⚓️-pin-x data-⚓️-pin-top data-label="cover" role="img" aria-label="Foggy ridgeline cover photo"></div>
                <div class="g g-edge" data-⚓️-name="--edge" data-⚓️-to="--cover" data-⚓️-stretch-x data-⚓️-align-bottom data-label="cover.bottom"></div>
                <div class="g g-col" data-⚓️-name="--col" data-⚓️-to="--margins" data-⚓️-align-leading data-⚓️-sync-width="--margins" data-label="column"></div>
    
                <div class="avatar" data-⚓️-name="--avatar" data-⚓️-to="--edge" data-⚓️-sync-width="--superview"
                  data-⚓️-center-all
                  data-compact="center-all" data-regular="align-y=center align-leading=--margins"
                  data-label="avatar" role="img" aria-label="Mara Okafor avatar"><span>MO</span></div>
    
                <h1 class="name" data-⚓️-name="--name" data-⚓️-to="--avatar"
                  data-⚓️-below data-⚓️-align-x="center"
                  data-compact="below align-x=center" data-regular="after below=--edge"
                  data-label="nameLabel">Mara Okafor</h1>
                <div class="badge" data-⚓️-name="--badge" data-⚓️-to="--name" data-⚓️-after data-⚓️-align-top data-⚓️-sync-height data-label="verifiedBadge"><svg viewBox="0 0 24 24" aria-label="Verified" role="img"><path fill="currentColor" d="M12 1.5l2.6 1.9 3.2-.2 1 3.1 2.6 1.9-1 3.1 1 3.1-2.6 1.9-1 3.1-3.2-.2L12 22.5l-2.6-1.9-3.2.2-1-3.1-2.6-1.9 1-3.1-1-3.1 2.6-1.9 1-3.1 3.2.2z"/><path fill="none" stroke="var(--bg)" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" d="M7.6 12.2l3 3 5.8-6.2"/></svg></div>
                <p class="handle" data-⚓️-name="--handle" data-⚓️-to="--name" data-⚓️-below
                  data-⚓️-align-x="center"
                  data-compact="align-x=center" data-regular="align-leading"
                  data-label="handleLabel">@mara.fog</p>
                <p class="bio" data-⚓️-name="--bio" data-⚓️-to="--handle" data-⚓️-below data-⚓️-stretch-x="--col"
                  data-label="bioLabel">Landscape photographer chasing fog along the Pacific Northwest coast. Film when it's slow, digital when it isn't.</p>
    
                <div class="stats" data-⚓️-name="--stats" data-⚓️-to="--bio" data-⚓️-below data-⚓️-stretch-x="--col" data-label="statsStack"></div>
                <div class="stat" data-⚓️-name="--stat1" data-⚓️-to="--stats" data-⚓️-align-leading data-⚓️-stretch-y data-⚓️-sync-width data-label="stat[0]"><b>248</b><span>Posts</span></div>
                <div class="stat" data-⚓️-name="--stat2" data-⚓️-to="--stat1" data-⚓️-after data-⚓️-stretch-y data-⚓️-sync-width="--stats" data-label="stat[1]"><b class="followers">12.4K</b><span>Followers</span></div>
                <div class="stat" data-⚓️-name="--stat3" data-⚓️-to="--stat2" data-⚓️-after data-⚓️-stretch-y data-⚓️-sync-width="--stats" data-label="stat[2]"><b>311</b><span>Following</span></div>
                <div class="divider" data-⚓️-name="--div1" data-⚓️-to="--stat2" data-⚓️-align-leading data-⚓️-stretch-y data-label="divider"></div>
                <div class="divider" data-⚓️-name="--div2" data-⚓️-to="--stat3" data-⚓️-align-leading data-⚓️-stretch-y data-label="divider"></div>
    
                <button class="btn btn-follow" type="button" aria-pressed="false" data-⚓️-name="--follow" data-⚓️-to="--stats" data-⚓️-below data-⚓️-align-leading data-⚓️-sync-width data-label="followButton">Follow</button>
                <button class="btn btn-message" type="button" data-⚓️-name="--message" data-⚓️-to="--follow" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width data-⚓️-sync-height data-label="messageButton">Message</button>
    
                <div class="g g-grid" data-⚓️-name="--grid" data-⚓️-to="--follow" data-⚓️-below data-⚓️-pin-x
                  data-compact="to=--follow below pin-x" data-regular="to=--col after below=--edge align-trailing=--margins"
                  data-label="photoGrid"></div>
                <div class="cell" style="--h:210" data-⚓️-name="--p1" data-⚓️-to="--grid" data-⚓️-align-top data-⚓️-align-leading data-⚓️-sync-width="--grid" data-label="cell[0]"></div>
                <div class="cell" style="--h:30" data-⚓️-name="--p2" data-⚓️-to="--p1" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[1]"></div>
                <div class="cell" style="--h:160" data-⚓️-name="--p3" data-⚓️-to="--p2" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[2]"></div>
                <div class="cell" style="--h:260" data-⚓️-name="--p4" data-⚓️-to="--p1" data-⚓️-below data-⚓️-align-leading data-⚓️-sync-width="--grid" data-label="cell[3]"></div>
                <div class="cell" style="--h:80" data-⚓️-name="--p5" data-⚓️-to="--p4" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[4]"></div>
                <div class="cell" style="--h:190" data-⚓️-name="--p6" data-⚓️-to="--p5" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[5]"></div>
                <div class="cell" style="--h:320" data-⚓️-name="--p7" data-⚓️-to="--p4" data-⚓️-below data-⚓️-align-leading data-⚓️-sync-width="--grid" data-label="cell[6]"></div>
                <div class="cell" style="--h:140" data-⚓️-name="--p8" data-⚓️-to="--p7" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[7]"></div>
                <div class="cell" style="--h:50" data-⚓️-name="--p9" data-⚓️-to="--p8" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[8]"></div>
                <div class="cell" style="--h:230" data-⚓️-name="--p10" data-⚓️-to="--p7" data-⚓️-below data-⚓️-align-leading data-⚓️-sync-width="--grid" data-label="cell[9]"></div>
                <div class="cell" style="--h:110" data-⚓️-name="--p11" data-⚓️-to="--p10" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[10]"></div>
                <div class="cell" style="--h:0" data-⚓️-name="--p12" data-⚓️-to="--p11" data-⚓️-after data-⚓️-align-top data-⚓️-sync-width="--grid" data-label="cell[11]"></div>
    
                <!-- bottom content inset: keeps the last row clear of the tab bar + home indicator -->
                <div class="g g-spacer" data-⚓️-to="--p10" data-⚓️-below></div>
    
                <!-- inspector highlight: fills whichever view is hovered, glides between them -->
                <div class="hl" data-⚓️-fill="--avatar" data-⚓️-transition="glide" aria-hidden="true"></div>
              </div>
    
              <div class="statusbar" data-⚓️-pin-top data-⚓️-pin-x aria-hidden="true">
                <span class="time">9:41</span>
                <span class="glyphs">
                  <svg viewBox="0 0 18 12"><rect x="0" y="8" width="3" height="4" rx="1"/><rect x="5" y="5.5" width="3" height="6.5" rx="1"/><rect x="10" y="3" width="3" height="9" rx="1"/><rect x="15" y="0" width="3" height="12" rx="1"/></svg>
                  <svg viewBox="0 0 26 12"><rect x=".5" y=".5" width="22" height="11" rx="3.5" fill="none" stroke="currentColor" opacity=".4"/><rect x="2" y="2" width="16" height="8" rx="2"/><rect x="23.5" y="4" width="1.8" height="4" rx=".9" opacity=".4"/></svg>
                </span>
              </div>
    
              <nav class="navbar" data-⚓️-pin-top data-⚓️-pin-x aria-label="Navigation bar">
                <button class="glass" type="button" aria-label="Back"><svg viewBox="0 0 24 24"><path d="M15 5l-7 7 7 7" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
                <span class="nav-title">Mara Okafor</span>
                <button class="glass" type="button" aria-label="More"><svg viewBox="0 0 24 24"><circle cx="5.5" cy="12" r="1.9"/><circle cx="12" cy="12" r="1.9"/><circle cx="18.5" cy="12" r="1.9"/></svg></button>
              </nav>
    
              <nav class="tabbar" data-⚓️-pin-bottom data-⚓️-pin-x aria-label="Tab bar">
                <a href="#" aria-label="Home"><svg viewBox="0 0 24 24"><path d="M4 10.5L12 4l8 6.5V20h-5v-6H9v6H4z"/></svg><span>Home</span></a>
                <a href="#" aria-label="Search"><svg viewBox="0 0 24 24"><circle cx="10.5" cy="10.5" r="6" fill="none" stroke="currentColor" stroke-width="2.2"/><path d="M15 15l5 5" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg><span>Search</span></a>
                <a href="#" aria-label="Activity"><svg viewBox="0 0 24 24"><path d="M12 20s-7.5-4.6-7.5-10A4.3 4.3 0 0112 7.3 4.3 4.3 0 0119.5 10c0 5.4-7.5 10-7.5 10z"/></svg><span>Activity</span></a>
                <a href="#" aria-current="page" aria-label="Profile"><svg viewBox="0 0 24 24"><circle cx="12" cy="8.5" r="4"/><path d="M4.5 20a7.5 7.5 0 0115 0z"/></svg><span>Profile</span></a>
              </nav>
    
              <div class="island" data-⚓️-pin-top data-⚓️-pin-x aria-hidden="true"></div>
              <div class="home-indicator" data-⚓️-pin-bottom data-⚓️-pin-x aria-hidden="true"></div>
            </div>
          </div>
        </div>
    
        <aside class="inspector" aria-label="Constraints inspector">
          <header>
            <h2>Constraints</h2>
            <p>Active set: <b class="sc-label">compact</b> width. Hover or focus a view to highlight it. Dimmed rows belong to the other size class.</p>
          </header>
          <div class="c-list">
            <section data-target="--margins" tabindex="0"><h3>layoutMarginsGuide</h3><ul>
              <li>margins.leading = safeArea.leading + <var class="lm">16</var></li>
              <li>margins.trailing = safeArea.trailing − <var class="lm">16</var></li>
            </ul></section>
            <section data-target="--cover" tabindex="0"><h3>cover <small>UIImageView</small></h3><ul>
              <li>cover.top = superview.top</li>
              <li>cover.leading = superview.leading</li>
              <li>cover.trailing = superview.trailing</li>
              <li data-when="compact">cover.height = 0.333 × cover.width + safeArea.top</li>
              <li data-when="regular">cover.height = 0.2 × cover.width + safeArea.top</li>
            </ul></section>
            <section data-target="--avatar" tabindex="0"><h3>avatar <small>UIImageView</small></h3><ul>
              <li data-when="compact">avatar.centerX = superview.centerX</li>
              <li data-when="regular">avatar.leading = margins.leading</li>
              <li>avatar.centerY = cover.bottom</li>
              <li data-when="compact">avatar.width = 0.3 × superview.width <em>@750</em></li>
              <li data-when="regular">avatar.width = 0.12 × superview.width <em>@750</em></li>
              <li>avatar.width ≤ 132 <em>@1000</em></li>
              <li>avatar.height = 1.0 × avatar.width <em>1:1</em></li>
            </ul></section>
            <section data-target="--name" tabindex="0"><h3>nameLabel <small>UILabel</small></h3><ul>
              <li data-when="compact">name.centerX = avatar.centerX</li>
              <li data-when="compact">name.top = avatar.bottom + 8 <em>standard</em></li>
              <li data-when="regular">name.leading = avatar.trailing + 16</li>
              <li data-when="regular">name.top = cover.bottom + 12</li>
            </ul></section>
            <section data-target="--badge" tabindex="0"><h3>verifiedBadge <small>UIImageView</small></h3><ul>
              <li>badge.leading = name.trailing + 4</li>
              <li>badge.firstBaseline = name.firstBaseline</li>
            </ul></section>
            <section data-target="--handle" tabindex="0"><h3>handleLabel <small>UILabel</small></h3><ul>
              <li>handle.top = name.bottom + 8 <em>standard</em></li>
              <li data-when="compact">handle.centerX = name.centerX</li>
              <li data-when="regular">handle.leading = name.leading</li>
            </ul></section>
            <section data-target="--col" tabindex="0"><h3>column <small>UILayoutGuide</small></h3><ul>
              <li>column.leading = margins.leading</li>
              <li data-when="compact">column.width = 1.0 × margins.width</li>
              <li data-when="regular">column.width = 0.36 × margins.width</li>
            </ul></section>
            <section data-target="--bio" tabindex="0"><h3>bioLabel <small>UILabel, lines = 0</small></h3><ul>
              <li data-when="compact">bio.top = handle.bottom + 12</li>
              <li data-when="regular">bio.top = handle.bottom + 16</li>
              <li>bio.leading = column.leading</li>
              <li>bio.trailing = column.trailing</li>
            </ul></section>
            <section data-target="--stats" tabindex="0"><h3>statsStack <small>UIStackView .fillEqually</small></h3><ul>
              <li>stats.top = bio.bottom + 16</li>
              <li>stats.leading = column.leading</li>
              <li>stats.trailing = column.trailing</li>
              <li>stats.height = 60</li>
            </ul></section>
            <section data-target="--stat2" tabindex="0"><h3>stat[0…2] <small>arranged subviews</small></h3><ul>
              <li>stat[i].width = 0.333 × stats.width</li>
              <li>stat[i].top = stats.top, .bottom = stats.bottom</li>
              <li>stat[0].leading = stats.leading</li>
              <li>stat[i].leading = stat[i−1].trailing</li>
            </ul></section>
            <section data-target="--div1" tabindex="0"><h3>divider <small>hairline</small></h3><ul>
              <li>divider.leading = stat[i].leading</li>
              <li>divider.width = 1 ÷ displayScale</li>
              <li>divider.top = stat.top + 14, .bottom = stat.bottom − 14</li>
            </ul></section>
            <section data-target="--follow" tabindex="0"><h3>followButton <small>UIButton</small></h3><ul>
              <li>follow.top = stats.bottom + 16</li>
              <li>follow.leading = column.leading</li>
              <li>follow.width = 0.5 × stats.width − 4</li>
            </ul></section>
            <section data-target="--message" tabindex="0"><h3>messageButton <small>UIButton</small></h3><ul>
              <li>message.leading = follow.trailing + 8 <em>standard</em></li>
              <li>message.width = 1.0 × follow.width <em>equal</em></li>
              <li>message.height = 1.0 × follow.height</li>
              <li>message.top = follow.top</li>
            </ul></section>
            <section data-target="--grid" tabindex="0"><h3>photoGrid <small>UILayoutGuide</small></h3><ul>
              <li data-when="compact">grid.top = follow.bottom + 24</li>
              <li data-when="compact">grid.leading = superview.leading</li>
              <li data-when="compact">grid.trailing = superview.trailing</li>
              <li data-when="regular">grid.top = cover.bottom + 20</li>
              <li data-when="regular">grid.leading = column.trailing + 24</li>
              <li data-when="regular">grid.trailing = margins.trailing</li>
            </ul></section>
            <section data-target="--p5" tabindex="0"><h3>cell[0…11] <small>3 across</small></h3><ul>
              <li>cell.width = 0.333 × grid.width − 1.33</li>
              <li>cell.height = 1.0 × cell.width <em>1:1</em></li>
              <li>cell[n].leading = cell[n−1].trailing + 2</li>
              <li>cell[n+3].top = cell[n].bottom + 2</li>
            </ul></section>
          </div>
        </aside>
      </main>
    </div>

    data-⚓️-afterdata-⚓️-align-bottomdata-⚓️-align-leadingdata-⚓️-align-topdata-⚓️-align-xdata-⚓️-belowdata-⚓️-center-alldata-⚓️-filldata-⚓️-namedata-⚓️-pin-bottomdata-⚓️-pin-topdata-⚓️-pin-xdata-⚓️-rootdata-⚓️-scopedata-⚓️-stretch-xdata-⚓️-stretch-ydata-⚓️-sync-heightdata-⚓️-sync-widthdata-⚓️-todata-⚓️-transition

    Copied