Mobile follow up number 4 #77

Closed
opened 2026-04-08 17:16:43 +00:00 by maxtkc · 0 comments
Owner

Summary

Follow-up polish pass on mobile support (#74). Three remaining issues: (1) Desktop right-panel scroll container collapses to near-zero height because DaisyUI v5's .tabs component sets height: auto, breaking the height: 100% chain for all descendants. The Phase 2 fix (#right-panel .tab-content { height: 100%; } in @layer components) may also lose to DaisyUI's layers. Fix: add unlayered CSS to give .tabs a definite height — this unblocks the entire height chain. (2) The three basemap control buttons (basemap FAB, projection toggle, shape toggle) are visually behind the mobile dock because they use position: absolute relative to the MapLibre map container. Switching to position: fixed (same mechanism as the dock) makes them viewport-relative and immune to any parent container sizing/overflow issues. (3) On mobile there are 1-2px of x and y scrollability. overflow: hidden is only set on body, not html. Adding it to both seals the gap.

Approach: all three changes are in src/styles/main.css only. No JS changes.

Relevant Context

  • src/styles/main.css:13-16 — the existing html, body { overscroll-behavior: none; } rule to extend
  • src/styles/main.css:29-69 — the @media (max-width: 767px) block; .basemap-control rule is at lines 38-41
  • src/styles/main.css:71-81@layer components block containing #right-panel .tab-content { height: 100%; } at lines 73-75
  • src/modules/basemap-control.ts:144-156createControl() sets inline style.cssText = 'position: absolute; bottom: 40px; right: 10px; ...'; our CSS !important rule overrides these on mobile
  • DaisyUI v5 .tabs: display: flex; flex-wrap: wrap; height: var(--tabs-height) where --tabs-height: auto. Tab inputs are flex row 1; .tab-content has order: 1; width: 100%; height: calc(100% - var(--tab-height)). The 100% in that calc resolves against .tabs' height — which is auto, causing the entire chain to collapse to 0 in strict CSS implementations.
  • DaisyUI v5 .dock: uses position: fixed; bottom: 0; z-index: 50 (the stable positioning the user is referencing)

Phase 1: Fix Web Scroll Container Height

Goal: Make the right-panel scroll container fill the full available height on desktop.

Root cause: .tabs has height: auto (set by DaisyUI via --tabs-height: auto). Children's height: 100% or height: calc(100% - ...) cannot resolve against an auto parent, so the scroll container collapses to content height. The Phase 2 fix in @layer components may also be overridden by DaisyUI's own layer declarations.

src/styles/main.css

  • Outside any @layer block (unlayered CSS wins over all layered CSS), add:

    #right-panel .tabs {
      height: 100%;
    }
    

    Place it immediately after the @layer components block (around line 82). Unlayered rules always beat layered rules, so this overrides DaisyUI's height: var(--tabs-height) = auto with a definite 100% (which resolves against #right-panel's grid-determined height). Once .tabs has a definite height, DaisyUI's built-in height: calc(100% - var(--tab-height)) on .tab-content resolves correctly.

  • No change needed to the existing #right-panel .tab-content { height: 100%; } in @layer components — it remains as belt-and-suspenders for mobile (where DaisyUI's tab-height calc may differ).

Gotcha: on desktop the drag handle is md:hidden, so .tabs is effectively the only child of #right-panel and height: 100% fills it exactly. On mobile the drag handle is visible (~32px), but #right-panel has overflow: hidden which clips any overflow at the bottom of .tabs. Mobile scroll still works because the tab-content has its own overflow-y: auto.

Phase 2: Fix Basemap Buttons Beneath Dock

Goal: Ensure the three basemap control buttons (basemap FAB, projection toggle, shape toggle) are always visible above the dock on mobile.

Root cause: The control uses position: absolute relative to MapLibre's map container (set in inline style.cssText). Even though bottom: calc(var(--dock-height) + 10px) is correct, position: absolute inside a potentially-clipping map container is fragile. The dock itself uses DaisyUI's position: fixed; bottom: 0 (viewport-relative), which is why it's stable.

src/styles/main.css

  • In the @media (max-width: 767px) block, update the .basemap-control rule to use position: fixed:
    .basemap-control {
      position: fixed !important;
      bottom: calc(var(--dock-height) + 10px) !important;
      right: 10px !important;
      z-index: 40 !important;
    }
    
    Adding position: fixed !important overrides the inline position: absolute (CSS !important beats inline styles). Adding right: 10px !important makes it explicit (was already set inline, but now declared in CSS alongside the other layout properties). The bottom and z-index lines are unchanged from before.

Gotcha: position: fixed elements are removed from the map container's stacking context — this is intentional. The control stacks in the root stacking context at z-index: 40, which is below the dock (z-50) and right panel (z-50). When the bottom sheet opens at full height, it correctly overlays the buttons.

Gotcha: rebuildControl() in basemap-control.ts re-appends the container to mapContainer. With position: fixed, being inside mapContainer has no effect on visual position — the element is always viewport-relative. No JS change needed.

Gotcha: this @media rule already has !important on bottom and z-index, so the pattern is consistent.

Phase 3: Fix Mobile Micro-Scrollability

Goal: Eliminate the 1-2px x and y scrollability on mobile.

Root cause: overflow: hidden is only set on body. The html element is not constrained. On mobile browsers, the html element can be slightly scrollable even when body is clipped.

src/styles/main.css

  • Extend the existing html, body rule at lines 13-16 to include overflow: hidden:
    html,
    body {
      overscroll-behavior: none;
      overflow: hidden;
    }
    
    One line addition. overscroll-behavior: none prevents rubberbanding/swipe-to-refresh; overflow: hidden prevents any actual scroll from happening on either element.
## Summary Follow-up polish pass on mobile support (#74). Three remaining issues: (1) Desktop right-panel scroll container collapses to near-zero height because DaisyUI v5's `.tabs` component sets `height: auto`, breaking the `height: 100%` chain for all descendants. The Phase 2 fix (`#right-panel .tab-content { height: 100%; }` in `@layer components`) may also lose to DaisyUI's layers. Fix: add unlayered CSS to give `.tabs` a definite height — this unblocks the entire height chain. (2) The three basemap control buttons (basemap FAB, projection toggle, shape toggle) are visually behind the mobile dock because they use `position: absolute` relative to the MapLibre map container. Switching to `position: fixed` (same mechanism as the dock) makes them viewport-relative and immune to any parent container sizing/overflow issues. (3) On mobile there are 1-2px of x and y scrollability. `overflow: hidden` is only set on `body`, not `html`. Adding it to both seals the gap. Approach: all three changes are in `src/styles/main.css` only. No JS changes. ## Relevant Context - `src/styles/main.css:13-16` — the existing `html, body { overscroll-behavior: none; }` rule to extend - `src/styles/main.css:29-69` — the `@media (max-width: 767px)` block; `.basemap-control` rule is at lines 38-41 - `src/styles/main.css:71-81` — `@layer components` block containing `#right-panel .tab-content { height: 100%; }` at lines 73-75 - `src/modules/basemap-control.ts:144-156` — `createControl()` sets inline `style.cssText = 'position: absolute; bottom: 40px; right: 10px; ...'`; our CSS `!important` rule overrides these on mobile - DaisyUI v5 `.tabs`: `display: flex; flex-wrap: wrap; height: var(--tabs-height)` where `--tabs-height: auto`. Tab inputs are flex row 1; `.tab-content` has `order: 1; width: 100%; height: calc(100% - var(--tab-height))`. The `100%` in that calc resolves against `.tabs`' height — which is `auto`, causing the entire chain to collapse to 0 in strict CSS implementations. - DaisyUI v5 `.dock`: uses `position: fixed; bottom: 0; z-index: 50` (the stable positioning the user is referencing) ## Phase 1: Fix Web Scroll Container Height **Goal:** Make the right-panel scroll container fill the full available height on desktop. **Root cause:** `.tabs` has `height: auto` (set by DaisyUI via `--tabs-height: auto`). Children's `height: 100%` or `height: calc(100% - ...)` cannot resolve against an `auto` parent, so the scroll container collapses to content height. The Phase 2 fix in `@layer components` may also be overridden by DaisyUI's own layer declarations. **`src/styles/main.css`** - [x] Outside any `@layer` block (unlayered CSS wins over all layered CSS), add: ```css #right-panel .tabs { height: 100%; } ``` Place it immediately after the `@layer components` block (around line 82). Unlayered rules always beat layered rules, so this overrides DaisyUI's `height: var(--tabs-height) = auto` with a definite `100%` (which resolves against `#right-panel`'s grid-determined height). Once `.tabs` has a definite height, DaisyUI's built-in `height: calc(100% - var(--tab-height))` on `.tab-content` resolves correctly. - [x] No change needed to the existing `#right-panel .tab-content { height: 100%; }` in `@layer components` — it remains as belt-and-suspenders for mobile (where DaisyUI's tab-height calc may differ). Gotcha: on desktop the drag handle is `md:hidden`, so `.tabs` is effectively the only child of `#right-panel` and `height: 100%` fills it exactly. On mobile the drag handle is visible (~32px), but `#right-panel` has `overflow: hidden` which clips any overflow at the bottom of `.tabs`. Mobile scroll still works because the tab-content has its own `overflow-y: auto`. ## Phase 2: Fix Basemap Buttons Beneath Dock **Goal:** Ensure the three basemap control buttons (basemap FAB, projection toggle, shape toggle) are always visible above the dock on mobile. **Root cause:** The control uses `position: absolute` relative to MapLibre's map container (set in inline `style.cssText`). Even though `bottom: calc(var(--dock-height) + 10px)` is correct, `position: absolute` inside a potentially-clipping map container is fragile. The dock itself uses DaisyUI's `position: fixed; bottom: 0` (viewport-relative), which is why it's stable. **`src/styles/main.css`** - [x] In the `@media (max-width: 767px)` block, update the `.basemap-control` rule to use `position: fixed`: ```css .basemap-control { position: fixed !important; bottom: calc(var(--dock-height) + 10px) !important; right: 10px !important; z-index: 40 !important; } ``` Adding `position: fixed !important` overrides the inline `position: absolute` (CSS `!important` beats inline styles). Adding `right: 10px !important` makes it explicit (was already set inline, but now declared in CSS alongside the other layout properties). The `bottom` and `z-index` lines are unchanged from before. Gotcha: `position: fixed` elements are removed from the map container's stacking context — this is intentional. The control stacks in the root stacking context at `z-index: 40`, which is below the dock (`z-50`) and right panel (`z-50`). When the bottom sheet opens at full height, it correctly overlays the buttons. Gotcha: `rebuildControl()` in `basemap-control.ts` re-appends the container to `mapContainer`. With `position: fixed`, being inside `mapContainer` has no effect on visual position — the element is always viewport-relative. No JS change needed. Gotcha: this `@media` rule already has `!important` on `bottom` and `z-index`, so the pattern is consistent. ## Phase 3: Fix Mobile Micro-Scrollability **Goal:** Eliminate the 1-2px x and y scrollability on mobile. **Root cause:** `overflow: hidden` is only set on `body`. The `html` element is not constrained. On mobile browsers, the `html` element can be slightly scrollable even when `body` is clipped. **`src/styles/main.css`** - [x] Extend the existing `html, body` rule at lines 13-16 to include `overflow: hidden`: ```css html, body { overscroll-behavior: none; overflow: hidden; } ``` One line addition. `overscroll-behavior: none` prevents rubberbanding/swipe-to-refresh; `overflow: hidden` prevents any actual scroll from happening on either element.
maxtkc self-assigned this 2026-04-08 17:16:43 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
gtfs.zone/coloring-book#77
No description provided.