Skip to content

Mobile Friendly Checklists

Ed Mozley edited this page Sep 19, 2026 · 4 revisions

Mobile‑Friendly: Checklists & SOPs

Scope: all four pages β€” the list, the editor, settings, and the guide. Layers: mobile.css LAYERS 40-40e, and mobile.js LAYERS 40c-40e (the editor's footer, and the list's filter sheet). Parent: Mobile‑Friendly Β· Techniques: Β§9, Β§14, Β§30, Β§32


The module that arrived half‑converted

Checklists is the first module contributed from outside the project, and it was built with mobile.css already linked on every page. Three of its four pages therefore measured clean before anything was done to them, which is a genuinely good starting position and also the reason two faults went unnoticed for a release.

What was missing was not rules but scoping: not one of the four pages carried a data-mobile-page marker, so nothing in mobile.css could be aimed at the module even if it had needed to be.

⚠️ And on the list page the link sat above the page's own <style> block:

<link rel="stylesheet" href="../assets/css/mobile.css?v=148">   <!-- line 71 -->
<style> .chk-layout { display: flex; height: calc(100vh - 48px); } </style>

That is Β§9 exactly β€” every same‑specificity rule in mobile.css loses on document order β€” and it is easy to miss precisely because the link is there. A page with no link at all announces itself; a page with the link in the wrong place looks done.

πŸ”‘ "mobile.css is linked" is not the check. "mobile.css is linked after the page's own stylesheet" is.


The list page: three faults, each hiding the next

This is the useful part of the round, and it is written up in full as Techniques Β§32.

.chk-card   left=296  w=340      <- first card starts 296px in, on a 360px screen
main.chk-main         w=100      <- the pane holding it
  1. The grid has a floor. repeat(auto-fill, minmax(340px, 1fr)) reads as at least 340px, so auto-fill lays out a 340px track on a 360px screen and the cards overflow. A real fault β€” fixed first, and it changed nothing measurable.
  2. Because the pane was already 100px. .chk-layout is a flex row whose 260px sidebar carries flex-shrink: 0, leaving .chk-main one hundred pixels wide. A 1fr track inside 100px is 100px. This is the fixed‑sidebar shape for the fifth time in the rollout, and the treatment is the usual one: stack, cap the sidebar, hand the scroller role to the main pane explicitly.
  3. And the card still would not shrink. With the track at 1fr inside a full‑width pane, .chk-card measured 489px in a 336px track β€” because a grid item has min-width: auto just as a flex item does (Β§14). The track was right and the item ignored it.

⭐ The lesson is the order, not any of the three rules. When a fix that should have moved something moves nothing, look outward before you look again at the rule you just wrote. §9 teaches this for load order; a correct rule inside a container that is already the wrong size behaves identically.


What was done

All four pages data-mobile-page markers added (checklists, checklists-help, checklists-edit, checklists-settings)
Three pages mobile.css moved below the page's own <style>
List page layout stacks, sidebar capped at 32vh with the house 12px padding, .chk-main given the scroller role, grid to one column, card allowed to shrink
Settings, guide nothing β€” they measured clean and still do
List page, round two the scope panel became a sheet and the step role badges stopped spilling β€” see below
Editor measured clean, then gained a sticky footer and the 16px rule β€” see below

Desktop control at 1400px, run after moving the stylesheet because moving a stylesheet changes the cascade: flex row, 260px sidebar with its right border and 20px padding, main at 28px/36px, grid three 342px columns, card min-width: auto β€” all untouched.


⚠️ For whoever reviews the next contributed module

Both faults here came from the same place: the module was written by somebody following the pattern from the outside, and the pattern's two invisible parts are the marker and the link's position. Neither shows up in a screenshot, and one of them makes the whole stylesheet silently lose ties.

  • Grep for data-mobile-page on every new page, not for mobile.css.
  • Check the link is after the page's <style>.
  • Then measure β€” three of these four pages needed nothing, and knowing that quickly is worth more than guessing at rules.

The editor, and the zoom (LAYER 40c/40d)

Back and Save move to a sticky footer as icons (Ed). The top bar carried Back, the title, an unsaved-changes flag and Save, which at 360px left the title almost nothing - and Save is the control you reach for after scrolling to the bottom of a long template, the far end of the page from where it lived.

The real nodes are relocated, not copied: #edSave has a click handler bound in the page's own script and #edBack is an <a> carrying the href, so a clone would be a control that does nothing beside an original that still works. Each one's own label is harvested into aria-label, because an icon with no text has no accessible name, and everything is restored exactly above 768px.

πŸ”΄ And the zoom, which is not cosmetic

Tapping Search templates zoomed the page. .chk-search is 13px, and Β§3 is unambiguous about what that costs:

iOS zooms on focus for any field under 16px β†’ the page spills wider than the screen β†’ Safari reflows the layout to a desktop width β†’ the whole max-width: 768px block stops matching.

So the symptom is not a bit of zoom, it is every mobile rule switching off at once. Fixed for the module rather than the one box: there are 21 focusable fields across these pages and the next one added would inherit the fault. No TinyMCE here, so the pointer: coarse content_style case does not arise.

Verified at 360x740: 21 fields, none under 16px, the search box exactly 16.


The list page, round two (LAYER 40e)

Both from Ed, using it.

πŸ”΄ The badge that spilled

The teal pill on each step β€” a suggested role, reading things like Tier 2 support β€” was pushing the page sideways.

.chk-step-row    a tick Β· the step title Β· the role badge      (space-between)
.chk-step-role   white-space: nowrap
.chk-step-main   min-width: (auto)        <- the fault

Β§14 again: a flex item's automatic minimum is its content width, so the title would not shrink and the badge was pushed past the card's edge. The badge now drops to its own line, indented under the title β€” a role is a property of the step, not a continuation of its name, and at 336px there is no arrangement that fits both on one line.

⚠️ Those rows are styled INLINE, and an inline style beats any selector without !important. See §9's note on !important for the third option that was taken here: the markup was given three class names and nothing else changed, so desktop renders identically and the mobile layer has something to aim at.

The scope panel becomes a sheet

A New button, a search box and three filter groups β€” scope, categories, roles β€” is most of a phone screen before a single template is shown. Β§4: a crowded panel gets its own screen. A Filters button in a sticky footer opens it full‑screen.

The real .chk-sidebar is relocated in and out, not cloned β€” the calendar's 16a move β€” and here the reason is concrete: the filter links call setScopeFilter(..., this) with this, and the active‑link bookkeeping walks .scope-link / .cat-link / .role-link. Two copies would be two sets of links disagreeing about which one is active.

πŸ”‘ The sheet closes on a filter tap and not on a search keystroke. A filter is an arrival β€” you have chosen, and the thing you chose is behind the sheet. A keystroke is not. The System Wiki round is why that distinction is written down: closing on every tap there would have made a whole branch of the tree unreachable.

Verified by driving it at 360Γ—740: 20 step rows with zero badges past the edge, one sidebar copy, the sheet full‑screen when open and display: none when closed, still open after typing in search, and a tap on Task both closed it and took the list from 5 cards to 3. Desktop at 1400px: no sheet, no bar, sidebar still in the layout, step rows back to nowrap.

⬜ Noted, not fixed: this module is English‑only in the browser

Checklists calls t() in PHP but never loads i18n.js and never exports window.translations, so window.t does not exist on these pages and the client‑side strings are hard‑coded English. Pre‑existing β€” the labels added here fall back to English to match rather than inventing a second mechanism β€” but it is a real gap if the module is ever to be translated.


Reference

  • assets/css/mobile.css (LAYERS 40, 40b, 40c, 40d) and assets/js/mobile.js (LAYER 40c - the editor's footer).
  • Pages: checklists/index.php, checklists/edit/, checklists/settings/, checklists/help.php.
  • Changelog: #1770-#1772.
  • Parent: Mobile‑Friendly Β· Siblings: Mobile: Tickets, Mobile: Knowledge.

FreeITSM

Getting Started

Modules

Multi-tenancy (planned)

Blue sky thinking

Bugs resolved

Links

Clone this wiki locally