K2.08.4mixed-DPI layout roundingdesign

Font size and spacing conversions accumulate error under mixed resolutions

Aliases: fractional scaling · 125% layout error · nested rounding

What it is

A 13-point face, 8 pixels of padding, and a 1-pixel stroke each get multiplied by 125% or 150% and then snapped to integers. One layer is off by half a pixel; three nested layers later, row heights disagree, icon and label baselines split, and a toolbar that fitted one line wraps. Mixed-DPI layout rounding is that drift in type size and spacing after layer-by-layer conversion at non-integer scales. It is not the whole window stretching into blur, and not whether an icon should swap to @2x. Integer scales (200%) almost never trigger it; 125%, 150%, and 175% are the wreck.

Why it happens

Layout is a chain of integer constraints: row height, gap, border, icon slot—all must land on whole pixels to paint. A non-integer ratio inserts “multiply, then round” at every layer. Padding 8×1.25 = 10; a 13-point face ×1.25 = 16.25 becomes 16 or 17; a 1-pixel stroke ×1.25 = 1.25 becomes 1 or 2. If each layer picks its own rounding direction, bias stacks: three layers at +0.5 shed 1.5 pixels, twenty rows in a column become 30 pixels of height drift, and a scrolling body parts from a sticky header. Rounding the other way opens gaps or clips. Icons snap to even slots, text snaps to glyph metrics; the two grids cease to share a measure under fractional scale. A toolkit that multiplies once at the parent and again at the child squares the ratio—the error is no longer rounding, it is the wrong dimension.

Where it stops holding

Two screens both at 100% or both at 200% have no fractional factor; accumulated snap almost never appears. A vector engine that keeps fractions until a single final raster snaps will drift much less. When people stack system scale with a separate “make text larger” setting, that is another multiply; desktop apps that honored system DPI but not text zoom enlarge the error again. Tables and code editors that keep time with row height feel a 1-pixel drift far more than a card stream.

Applying it

  • Convert the current screen’s scale once at the root; children only add and subtract. Do not let every control multiply scale again.
  • Give row height, icon slots, and toolbar height the same rounding rule (all down, or all to the nearest even) so the icon grid and the text row do not each pick their own.
  • Use integer scales as design and test anchors, but accept 125% and 150% in QA: look for wrapped rows, ragged columns, sticky headers parting from the scrolling body.
  • Verify: open the deepest nested panel (toolbar + tabs + padded card) at 150% and measure adjacent row heights with a pixel ruler; the icon center should sit on the label row’s vertical midline. Drag the window to 100% and back to 150%; the same measures must not creep—if every round trip adds a gap, the conversion ran twice.

Related

  • Within the group: K2.08.1 Apps must read each display's scale, not a system-wide value · K2.08.2 Bitmaps must reload at the destination display's resolution when moved · K2.08.3 Apps that ignore per-display scale go blurry or misaligned on high-DPI screens
  • Adjacent: J2.02 Text zoom · A1.16 Visual angle and size conversion
  • Search terms: fractional scaling · layout rounding · mixed DPI

Cards in the same group

Quick Actions

Share

Share this page

ios_share

https://hci.top/en/handbook/K2.08.4