Skip to content

History / Mobile Friendly Techniques

Revisions

  • Techniques: three notes from the settings tidy-ups (#1006) - When you "normalise" a layout, state BOTH insets in one place. Leaving the modal header to LAYER 3's plain rule aligned three pages of four: inbox.css:2549 carries .modal-content:has(> .modal-body) > .modal-header at (0,3,0), which beats it, and only one modal has a .modal-body. Reads as a one-page quirk until you find the selector. - Measure where the TEXT starts, not where the box starts. Comparing a full-width header <div> to an inset <label> by rect.left measures the padding, not the misalignment — it reported a 14px error on four pages that were mostly fine. - A shared class means a one-page fix is a five-page fix. .tab-content is styled once in inbox.css at padding:30px — a sixth of a 360px screen — so trimming it for one module improved all five.

    @edmozley edmozley committed Aug 9, 2026
  • Mobile: tickets settings (#1005) + five more techniques Mobile: Tickets gains a settings section; overview status/table/layer count updated. Five things promoted into Techniques: - Read a page's own CSS comments before opting it in. tickets/settings states outright that <body> must not be flex (extension-injected nodes became flex items and wrecked the layout) and builds its own shell. LAYER 2 would have re-created that bug. No harness catches it -- a headless run has no extensions. - A page that renders one tab at a time is 1/N verified. Measuring it as loaded reported clean; walking all 18 tabs found the real problems. - Exclude what must not change, don't enumerate what must. The anti-zoom rule listed six input types and missed a datetime-local. - Stacking a grid to one column does nothing if its children span two -- the browser creates an implicit second column and the rule looks like it failed. The tell is unequal tracks. - Ask the question measurement can answer. "Contained but crushed" kept slipping past overflow checks, so assert the actual property: nothing may still be laid out in more than one column at phone width.

    @edmozley edmozley committed Aug 9, 2026
  • Mobile: Service Status round 2 (#1004) + two more techniques Module page gains a Round 2 section (two screens, tap-anywhere cards, pill alignment, the sticky action bar, the confirm) and a note that the settings card feed from #1000 is gone. Calendar page's card-feed bullet marked superseded, with the reasoning kept — it lost to consistency across the set, not to being wrong. Two things promoted into Techniques: - position:sticky does NOT pin anything to the bottom of a short container; it only stops an element scrolling away. Pair it with margin-top:auto in a flex column. And the two fight a negative margin-bottom — auto absorbs the free space the negative margin creates, so they cancel and the bar lands its own margin short. - Never mix getBoundingClientRect() with clientHeight on anything inside a transformed container. Rects are scaled, layout properties are not; mixing them produced a "bottom" beyond the viewport and sent a diagnosis completely wrong. Fourth false alarm from animating modals.

    @edmozley edmozley committed Aug 9, 2026
  • Mobile: Service Status (#1003) + four more techniques New page Mobile-Friendly-Service-Status, linked from the overview (status blockquote, module table, honest assessment, layer count), the sidebar, all four sibling module pages, Techniques and Service-Status.md. Four things promoted into Techniques: - An inline style.display set by the page's own JS beats your rule. Service Status re-sets display:table on every render, so the card feed needed !important or it reverts on the first refresh. Grep a module for style.display before converting one of its tables. - "It reflows" is not the same as "it works". The board was already an auto-fill grid -- and a single column at 360px, i.e. a list. Ask what the component is FOR; a status board is for scanning, so density beats card size. - Not every module needs a mobile.js branch. Four in a row had one; this one shipped as CSS only. - A CSS comment edit is a code edit. Closing a comment early orphans text and the parser drops the rule that follows. Happened twice in one session, and brace-balance checks pass happily both times.

    @edmozley edmozley committed Aug 9, 2026
  • Mobile: Knowledge round 3 (#1002) + three widget-wrangling techniques Module page gains a "Round 3" section: the editor footer reaching the bottom edge, and full-screen text editing. Three things promoted into Techniques: - A JS-mounted widget injects its stylesheet at RUNTIME, so it beats yours on source order whatever the specificity. TinyMCE's skin lands after mobile.css; .tox-* rules need !important. The tell is a fix that looks like it HALF worked -- hiding the upsell badge succeeded while flex-wrap on the menubar did nothing, which read as "mostly fixed" until it was measured. Measure which half. - Reclaim a third-party widget's own chrome before adding your own. Four wrapped menubar rows plus an upsell badge were ~130px of a 720px screen; scrolling the menubar rather than hiding it returned 78px of typing area with every menu still reachable. - Build your own full screen, don't borrow the widget's. TinyMCE's fullscreen plugin was one line away but had no reachable exit in this init -- a phone user could get stuck. A fixed overlay with your own Close plus a pushState back-button exit cannot trap anyone.

    @edmozley edmozley committed Aug 9, 2026
  • Mobile: Knowledge round 2 (#1001) + three more techniques Module page gains a "Round 2" section: Back onto the action row, the Gmail-style collapsible meta block, and the sticky peek-through fix. Three things promoted into Techniques so the next module inherits them: - The sticky peek-through has now happened in TWO unrelated modules. A sticky element sticks to the top of its scroll container's CONTENT box, below its padding-top. Check the container's padding first; move the space onto something that scrolls away rather than deleting it; make any negative margin match the card's padding exactly. - A collapsible summary should BE the tap target, not sit beside a chevron -- bigger target, and its accessible name is the visible text, so it needs no aria-label and therefore no new string in 24 languages. Draw the chevron with borders; a glyph renders as a dot at 11px. - Harvest a translated word rather than writing one. common.back took each locale's own existing translation from change-management.php -- no EN-only key, no silent fallback, and the generic word lands in common where the next module finds it.

    @edmozley edmozley committed Aug 9, 2026
  • Mobile: Knowledge (#1000) + three lessons for the next module New page Mobile-Friendly-Knowledge. Linked from the overview (status table, honest assessment, layer count), the sidebar, all three sibling module pages, the Techniques reference table and Knowledge.md. Three things added to Techniques so the next module inherits them: - A wide table that "fits" hasn't been fixed, it has been crushed. display:block + overflow-x is only half the rule; without nowrap on the cells the browser wraps every column to one word per line, which passes the overflow measurement and is unreadable. - Grep a module for localStorage before bringing it along. Two of four modules have carried a saved DESKTOP mode that re-applies itself on a phone (tickets #762, knowledge editor pop-out #1000). Invisible in the markup; breaks for one user and not the rest. - The Share dropdown is a second instance of re-positioning a JS-positioned element in pure CSS. Also recorded on the module page: `let` globals are not window properties (so a harness cannot read them from outside), and a desktop-width overflow on a page that never opted into mobile.css is the control, not the bug.

    @edmozley edmozley committed Aug 9, 2026
  • Mobile: Calendar (#998) + the two lessons it produced New page Mobile-Friendly-Calendar. Linked from the overview (status table, honest assessment, layer count), the sidebar, both sibling module pages, the Techniques reference table and Calendar.md. Two things worth carrying forward, both written up: - "docScrollW === innerWidth proves the page won't reflow to desktop. It does not prove the page is usable." The settings page passed every measurement while still being a four-column table you had to drag sideways -- the container's overflow-y:auto had quietly made it a horizontal scroller, so the table genuinely WAS contained. - A rule that "already covers this" is worth measuring. LAYER 3's 16px anti-zoom rule had never applied to any typed input, losing on specificity to inbox.css, app-wide, since the tickets rollout. Also recorded: every opted-in page must declare its own scroller (LAYER 2 makes body a 100dvh flex column and flex items shrink by default), and getComputedStyle beats getBoundingClientRect for anything inside a container that animates in with a transform.

    @edmozley edmozley committed Aug 9, 2026
  • Add Mobile: Techniques & Tricks page (CSS/JS deep-dive); cross-link + refresh overview

    @edmozley edmozley committed Jul 15, 2026