Drawing toolbar: fix iPhone portrait and landscape

Two separate faults, both reported from an iPhone running v16.

Portrait showed no toolbar at all. On iOS Safari an element that both blurs its
backdrop and scrolls frequently fails to paint, and v16's strip did both:
backdrop-filter inherited from the rail, plus overflow-x for the horizontal
scroll. The rail has no overflow, which is why the same build rendered fine in
landscape. The strip now paints an opaque background and switches the blur off.
`-webkit-overflow-scrolling: touch` goes with it — obsolete since iOS 13 and
implicated in the same class of bug.

Landscape showed the desktop rail. The breakpoint was width-only, and a phone
in landscape is 844px wide, so it did not qualify as a phone — but it leaves
only ~270px of map height, and the rail is 396px tall. The layout now switches
on either axis: `(max-width: 576px), (max-height: 560px)`. 560px is the point
below which the rail plus the navbar and dock no longer fit. The matchMedia
query that disables dragging on the docked strip matches the new condition.

Verified across all three states: narrow-and-tall and wide-and-short both give
the strip with no blur and no grip; wide-and-tall keeps the rail.

Service Worker v16 -> v17.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ekke 2026-08-20 16:18:16 +02:00
parent 19dc000efe
commit d165b57853
9 changed files with 58 additions and 19 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

20
dist/index.html vendored
View File

@ -1607,7 +1607,7 @@
user-select: none; user-select: none;
} }
/* No dragging on phones — the strip is docked above the dock bar. */ /* No dragging on phones — the strip is docked above the dock bar. */
@media (max-width: 576px) { @media (max-width: 576px), (max-height: 560px) {
.ol-editbar-rail .ol-rail-grip { .ol-editbar-rail .ol-rail-grip {
display: none; display: none;
} }
@ -1776,7 +1776,10 @@
above the bottom dock. Scrolling replaces the previous two-row above the bottom dock. Scrolling replaces the previous two-row
wrap, so every tool stays reachable at full touch size. wrap, so every tool stays reachable at full touch size.
---------------------------------------------------------------- */ ---------------------------------------------------------------- */
@media (max-width: 576px) { /* Narrow OR short. A phone in landscape is 844px wide but leaves only
~270px of map height, where the 395px rail cannot fit — so the strip is
chosen on either axis, not on width alone. */
@media (max-width: 576px), (max-height: 560px) {
/* `.ol-left` is repeated here for specificity: ol-ext's own /* `.ol-left` is repeated here for specificity: ol-ext's own
`.ol-control.ol-bar.ol-left` sets top/transform, and without matching `.ol-control.ol-bar.ol-left` sets top/transform, and without matching
it the rail stays vertically centred and stretches to `bottom`. */ it the rail stays vertically centred and stretches to `bottom`. */
@ -1800,8 +1803,17 @@
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
overscroll-behavior-x: contain; overscroll-behavior-x: contain;
-webkit-overflow-scrolling: touch;
scrollbar-width: none; scrollbar-width: none;
/* No backdrop-filter here. On iOS Safari an element that both blurs its
backdrop and scrolls frequently fails to paint at all — which is why
this strip was invisible in portrait while the rail, which does not
scroll, rendered fine in landscape. An opaque background gives the
same legibility without the blur.
`-webkit-overflow-scrolling: touch` is deliberately absent too: it is
obsolete since iOS 13 and implicated in the same class of bug. */
backdrop-filter: none;
-webkit-backdrop-filter: none;
background: var(--card);
} }
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left::-webkit-scrollbar { .ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left::-webkit-scrollbar {
display: none; display: none;
@ -1875,7 +1887,7 @@
} }
</style> </style>
<script type="module" crossorigin src="/assets/index-4Lh4FMTD.js"></script> <script type="module" crossorigin src="/assets/index-C3r_p8o6.js"></script>
<link rel="modulepreload" crossorigin href="/assets/openlayers-J9qS6Th1.js"> <link rel="modulepreload" crossorigin href="/assets/openlayers-J9qS6Th1.js">
<link rel="modulepreload" crossorigin href="/assets/pako-Xa-UToif.js"> <link rel="modulepreload" crossorigin href="/assets/pako-Xa-UToif.js">
<link rel="modulepreload" crossorigin href="/assets/geotiff-BaoeLn6q.js"> <link rel="modulepreload" crossorigin href="/assets/geotiff-BaoeLn6q.js">

8
dist/sw.js vendored
View File

@ -89,7 +89,13 @@
// covered the left off-canvas toggle, which sits at exactly the position // covered the left off-canvas toggle, which sits at exactly the position
// ol-ext docks a left bar to — so the rail now starts clear of it and can // ol-ext docks a left bar to — so the rail now starts clear of it and can
// be dragged anywhere by its grip, with the position remembered. // be dragged anywhere by its grip, with the position remembered.
const CACHE_VERSION = 'v16'; // v17: iPhone fixes. In portrait the toolbar did not paint at all: on iOS an
// element that both blurs its backdrop and scrolls often renders blank,
// and v16's strip did both. The strip now uses an opaque background and no
// blur. In landscape the phone is 844px wide, so the width-only breakpoint
// handed it the 396px-tall rail inside a ~270px map; the layout now
// switches on height as well as width.
const CACHE_VERSION = 'v17';
const SHELL_CACHE = `shell-${CACHE_VERSION}`; const SHELL_CACHE = `shell-${CACHE_VERSION}`;
const MODULES_CACHE = `modules-${CACHE_VERSION}`; const MODULES_CACHE = `modules-${CACHE_VERSION}`;
const API_CACHE = `api-${CACHE_VERSION}`; const API_CACHE = `api-${CACHE_VERSION}`;

View File

@ -1607,7 +1607,7 @@
user-select: none; user-select: none;
} }
/* No dragging on phones — the strip is docked above the dock bar. */ /* No dragging on phones — the strip is docked above the dock bar. */
@media (max-width: 576px) { @media (max-width: 576px), (max-height: 560px) {
.ol-editbar-rail .ol-rail-grip { .ol-editbar-rail .ol-rail-grip {
display: none; display: none;
} }
@ -1776,7 +1776,10 @@
above the bottom dock. Scrolling replaces the previous two-row above the bottom dock. Scrolling replaces the previous two-row
wrap, so every tool stays reachable at full touch size. wrap, so every tool stays reachable at full touch size.
---------------------------------------------------------------- */ ---------------------------------------------------------------- */
@media (max-width: 576px) { /* Narrow OR short. A phone in landscape is 844px wide but leaves only
~270px of map height, where the 395px rail cannot fit — so the strip is
chosen on either axis, not on width alone. */
@media (max-width: 576px), (max-height: 560px) {
/* `.ol-left` is repeated here for specificity: ol-ext's own /* `.ol-left` is repeated here for specificity: ol-ext's own
`.ol-control.ol-bar.ol-left` sets top/transform, and without matching `.ol-control.ol-bar.ol-left` sets top/transform, and without matching
it the rail stays vertically centred and stretches to `bottom`. */ it the rail stays vertically centred and stretches to `bottom`. */
@ -1800,8 +1803,17 @@
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
overscroll-behavior-x: contain; overscroll-behavior-x: contain;
-webkit-overflow-scrolling: touch;
scrollbar-width: none; scrollbar-width: none;
/* No backdrop-filter here. On iOS Safari an element that both blurs its
backdrop and scrolls frequently fails to paint at all — which is why
this strip was invisible in portrait while the rail, which does not
scroll, rendered fine in landscape. An opaque background gives the
same legibility without the blur.
`-webkit-overflow-scrolling: touch` is deliberately absent too: it is
obsolete since iOS 13 and implicated in the same class of bug. */
backdrop-filter: none;
-webkit-backdrop-filter: none;
background: var(--card);
} }
.ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left::-webkit-scrollbar { .ol-control.ol-bar.ol-editbar.ol-editbar-rail.ol-left::-webkit-scrollbar {
display: none; display: none;

View File

@ -89,7 +89,13 @@
// covered the left off-canvas toggle, which sits at exactly the position // covered the left off-canvas toggle, which sits at exactly the position
// ol-ext docks a left bar to — so the rail now starts clear of it and can // ol-ext docks a left bar to — so the rail now starts clear of it and can
// be dragged anywhere by its grip, with the position remembered. // be dragged anywhere by its grip, with the position remembered.
const CACHE_VERSION = 'v16'; // v17: iPhone fixes. In portrait the toolbar did not paint at all: on iOS an
// element that both blurs its backdrop and scrolls often renders blank,
// and v16's strip did both. The strip now uses an opaque background and no
// blur. In landscape the phone is 844px wide, so the width-only breakpoint
// handed it the 396px-tall rail inside a ~270px map; the layout now
// switches on height as well as width.
const CACHE_VERSION = 'v17';
const SHELL_CACHE = `shell-${CACHE_VERSION}`; const SHELL_CACHE = `shell-${CACHE_VERSION}`;
const MODULES_CACHE = `modules-${CACHE_VERSION}`; const MODULES_CACHE = `modules-${CACHE_VERSION}`;
const API_CACHE = `api-${CACHE_VERSION}`; const API_CACHE = `api-${CACHE_VERSION}`;

View File

@ -1134,7 +1134,10 @@ export class MapView {
*/ */
_makeToolbarDraggable(bar, grip) { _makeToolbarDraggable(bar, grip) {
const STORAGE_KEY = 'editbar-position'; const STORAGE_KEY = 'editbar-position';
const phone = window.matchMedia('(max-width: 576px)'); // Must stay in step with the media query in index.html that swaps the rail
// for the docked strip — narrow OR short, because a phone in landscape is
// wide but has no room for a 395px-tall rail.
const phone = window.matchMedia('(max-width: 576px), (max-height: 560px)');
const clamp = (value, min, max) => Math.min(Math.max(value, min), max); const clamp = (value, min, max) => Math.min(Math.max(value, min), max);