
pull-to-refresh (iOS 15+)
沒有辦法透過 onscroll
或是任何方法知道 user 正在 pull-to-refresh,沒錯,沒有任何方法 (ref from: https://developer.apple.com/documentation/webkitjs/)
解決方法:當 scrollY
在 0 的時候, touchmove
是負數當作開始嘗試 pull-to-refresh (正在 overscroll) 的狀態
let startTouchY
function onTouchStart(event) {
// We're going to try to guess whether the user is trying to pull-to-refresh only.
if (event.touches.length > 1 || window.scrollY !== 0) {
return
}
const [touch] = event.touches
startTouchY = touch.clientY
}
function onTouchMove(event) {
if (event.touches.length > 1 || !this.startTouchY) {
return
}
const [touch] = event.touches
const offsetY = this.startTouchY - touch.clientY
// Pulling to refresh, offsetY smaller than 0 means scrolling down.
if (offsetY < 0) {
// ...Do anything you want when user pulling to refresh.
}
}
function onTouchEnd(event) {
startTouchY = null
}
Navigation bar/Address bar 縮放 (iOS 15+)
同樣的也沒有任何 event 可以知道 user 目前的操作使 navigation bar 變小還是變大,如果需要做出 full screen 效果,唯一的方式是透過 resize
event 通知需要重新計算高度,而高度則需要借助 CSS variable 調整 (作法參考來自 https://zenn.dev/tak_dcxi/articles/2ac77656aa94c2cd40bf)
let vw
let vh
function setFillHeight() {
if (vw === window.innerWidth && vh === window.innerHeight) {
// 畫面尺寸沒有更動,所以不做任何事
return
}
// 畫面尺寸有更動的時候重新計算高度
vw = window.innerWidth
vh = window.innerHeight
const vhUnit = window.innerHeight * 0.01
document.documentElement.style.setProperty('--vh', `${vhUnit}px`)
}
window.addEventListener('resize', setFillHeight)
// 記得手動初始化
setFillHeight()
// 沒有用到的時候也要記得回收 listener
window.removeEventListener('resize', setFillHeight)
另外也可以透過 safe-area-inset-bottom
來預留 address bar 的空間

有些實作元素像是 drag&drop 的操作因為上下移動會造成 navigation bar (address bar) 變動,目前沒有相對應的處理方法 (像是 disable address bar 縮放的任何手段)
↓ 範例:navigator resize 造成的 dragging 中斷
https://user-images.githubusercontent.com/1218900/160944477-cae01126-b2bd-4555-a6f9-5d864637f1a9.mov
swipe-to-back
直接電死系列第三彈,透過手勢回到前/後一頁的功能沒有 event 可以知道開始手勢/觸發,所以當有 swipe 手勢偵測實作的時候,建議可以留左右 edge 的空間,避免手勢重疊 (大約 50px 的空間,如果有官方文件清楚定義 swipe-to-back 的空間 pixel 請告知小弟,非常感謝)
以上是避免手勢重複的部分,而如果想要 disable swipe-to-back 手勢的話,可以參考 https://pqina.nl/blog/blocking-navigation-gestures-on-ios-13-4/
基本上就是在想要 disable 手勢的元素上接收 touchstart
event
<div style="height:100px">Our element that prevents navigation</div>
<script>
const element = document.querySelector('div');
element.addEventListener('touchstart', (e) => {
// prevent swipe to navigate gesture
e.preventDefault();
});
</script>
Wrap it up
以上特別是 navigator (address bar) 花了小弟特別多時間,最令人難過的是沒有解決方法...雖然我也是比較喜歡 iPhone 帶給我的使用體驗,但開發起來真的只能芭比Q了
