iT邦幫忙

2025 iThome 鐵人賽

DAY 14
3
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 14

Day 14 - 用 Screen Orientation、Wake Lock、Vibration API 讓網頁控制螢幕方向、保持常亮與震動

  • 分享至 

  • xImage
  •  

今天要介紹三個 Web API——Screen OrientationWake LockVibration——很有趣! ✨✨✨ 因為它們把「原生 App 的感覺」搬進瀏覽器:

  • Screen Orientation:把畫面鎖成直向或橫向,好像在打電玩或看影片時自動轉向。📲
  • Wake Lock:讓螢幕不會進入睡眠模式,做計時器、導航、或展示板時螢幕會持續顯示不會自動關閉。🔆
  • Vibration:讓手機震動,做簡單的「觸覺回饋」。📳

它們特別適合應用在手機瀏覽器上(Android 效果最明顯),但在桌面端也有一定的用武之地(例如展示畫面、Kiosk、教學現場的 Demo)。整體來說:

  • Mobile:體驗最好(螢幕旋轉與震動本來就是手機原生功能),Wake Lock 也最常見。
  • Desktop:Orientation 與 Wake Lock 在特定場景仍實用(全螢幕展示、教學投影、看板),Vibration 通常沒有可感知的硬體回饋。

概覽

API 典型用途 是否需要使用者手勢 常見限制 備註
Screen Orientation 鎖定螢幕直向/橫向、監聽旋轉變化 鎖定通常需要手勢觸發;部分瀏覽器需全螢幕 支援度依裝置/瀏覽器而異;iOS 歷史上受限較多 可用 @media (orientation) 做 CSS 兜底處理
Wake Lock (Screen) 保持螢幕不進入睡眠模式 通常需要手勢觸發 失焦或螢幕鎖定會被釋放;需 HTTPS 記得監聽 visibilitychange 重新申請
Vibration 按鈕回饋、提醒、簡易節奏 通常需要手勢觸發 iOS Safari 傳統上不支援;桌面多半無回饋 節制使用,顧及無障礙與使用者環境

注意事項

  1. 通常用 使用者手勢 才能成功。
  2. 支援度不穩定,一定要有 失敗降級try/catch

一、Screen Orientation:鎖定/監聽螢幕方向

1) 能做什麼?

  • 讀取目前螢幕方向:screen.orientation.type(ex: 直向模式 portrait-primary、橫向模式 landscape-primary)。
  • 監聽螢幕方向改變:screen.orientation.onchange
  • 嘗試鎖定螢幕方向:await screen.orientation.lock('landscape')unlock()

提醒有些瀏覽器規定,只有在 全螢幕模式 下或在 使用者有點擊、觸控等手勢 時,才允許鎖定螢幕方向。如果直接用程式碼鎖定,沒有符合這些條件,瀏覽器會拒絕並拋出 DOMException 錯誤。

2) 最小可行範例

<button type="button" id="lock-landscape">鎖定橫向</button>
<button type="button" id="unlock">解除鎖定</button>

<script type="module">
  // 讀取目前螢幕方向 & 角度
  console.log('type:', screen.orientation?.type, 'angle:', screen.orientation?.angle);

  // 監聽螢幕方向改變(新)
  screen.orientation?.addEventListener?.('change', () => {
      console.log('changed:', screen.orientation.type, screen.orientation.angle);
    });
    
  // 嘗試鎖定為橫向(需使用者手勢;部分瀏覽器可能會被拒絕)
  async function lockLandscape() {
    try {
      await screen.orientation?.lock?.('landscape');
    }  catch (e) {
      console.warn('lock failed:', e?.name || e);
    }
  }

  // 解除鎖定
  function unlockOrientation() {
    try {
      screen.orientation?.unlock?.();
    } catch {
      console.warn('unlock failed');
    }
  }

  // 綁定手勢
  document.getElementById('lock-landscape')?.addEventListener('click', lockLandscape);
  document.getElementById('unlock')?.addEventListener('click', unlockOrientation);
</script>

3) CSS 降級:不支援螢幕鎖定也能用 CSS 布局

/* 直向時調整比例 */
@media (orientation: portrait) {
  .video {
      width: 100%;
      height: 56.25vw;
    }
}

/* 橫向時調整比例 */
@media (orientation: landscape) {
  .video {
      width: 56.25vh;
      height: 100%;
    }
}

4) 最佳實務

  • 僅在必要時鎖定(例如遊戲、影片、AR 體驗);用完就 unlock()
  • 避免「搶方向」:尊重使用者習慣,提供切換按鈕顯示狀態
  • 針對不支援或拒絕鎖定的情況,保持可用的 UI(用 CSS 響應式處理)。

二、Wake Lock:讓螢幕別睡著

1) 能做什麼?

  • 申請「螢幕常亮」權限:const lock = await navigator.wakeLock.request('screen')
  • 監聽被釋放:lock.addEventListener('release', ...)
  • 失焦或裝置鎖定後,鎖可能被系統釋放,需要回到可見時重新申請

2) 最小可行範例

<button type="button" id="wk-on">保持常亮</button>
<button type="button" id="wk-off">釋放常亮</button>

<script type="module">
  let wakeLock = null;
    
  // 使用者是否已要求保持常亮
  let keepAwakeRequested = false;

  // 申請螢幕常亮(需 HTTPS + 使用者手勢)
  async function requestWakeLock() {
    keepAwakeRequested = true;
    try {
      wakeLock = await navigator.wakeLock?.request?.('screen');
        
      // 當 Wake Lock 被釋放(例如切換分頁、裝置鎖定)時觸發
      wakeLock?.addEventListener('release', () => { wakeLock = null; });
    } catch (e) {
    console.warn('request failed:', e?.name || e);
    }
  }

  // 釋放(取消)螢幕常亮
  async function releaseWakeLock() {
    keepAwakeRequested = false;
    try {
        await wakeLock?.release();
    } finally {
        wakeLock = null;
    }
  }

  // 回到可見時,如使用者曾要求保持常亮且已被釋放,則再嘗試一次
  document.addEventListener('visibilitychange', () => {
    if (document.visibilityState === 'visible' && keepAwakeRequested && !wakeLock) {
      requestWakeLock();
    }
  });

  document.getElementById('wk-on')?.addEventListener('click', requestWakeLock);
  document.getElementById('wk-off')?.addEventListener('click', releaseWakeLock);
</script>

3) 最佳實務

  • 顯示醒目的狀態提示關閉按鈕,避免忘記釋放。
  • 需 HTTPS 與使用者手勢,失敗時提供替代方案(例如 UI 提示「請關閉自動鎖屏」)。
  • 避免長時間常亮造成耗電與烙印風險,按需啟用、離場即關。

三、Vibration:簡單的觸覺回饋

1) 能做什麼?

  • 單次震動:navigator.vibrate(200)(毫秒)。
  • 節奏震動:navigator.vibrate([100, 50, 100, 200])(震動-停頓-震動…)。
  • 停止震動:navigator.vibrate(0)

提醒支援度以 Android 為主;iOS Safari 傳統上不支援。桌機多半無回饋

2) 最小可行範例

<button id="btn-tap">輕觸回饋</button>
<button id="btn-success">成功提示</button>
<button id="btn-stop">停止震動</button>

<script type="module">
  const vibrate = (pattern) => navigator.vibrate?.(pattern) ?? false;

  // 輕微震動一下
  document.querySelector('#btn-tap').addEventListener('click', () => {
    vibrate(30);
  });

  // 嘀-停-嘀(成功感)
  document.querySelector('#btn-success').addEventListener('click', () => {
    vibrate([40, 40, 80]);
  });

  document.querySelector('#btn-stop').addEventListener('click', () => vibrate(0));
</script>

3) 最佳實務

  • 節制使用:避免干擾他人與引發誤解。
  • 尊重系統與使用者設定(靜音、勿擾模式、無障礙偏好)。
  • 若不支援或被拒絕,確保仍有視覺回饋(例如按鈕變化、Toast)。

範例 Demo

上面用簡單程式碼示範了「螢幕方向鎖定」、「保持螢幕常亮」、「震動觸覺回饋」的基本流程。
想直接體驗完整互動,請看這個線上範例:


注意事項

  • 需要使用者手勢:把 lock()request()vibrate() 綁在 click 之類事件內。
  • 全螢幕依賴:有些瀏覽器鎖方向前要先 requestFullscreen(),失敗就降級。
  • 可見性變化:Wake Lock 回到頁面時記得重新申請
  • 權限/裝置限制:公司設備策略、系統省電模式、瀏覽器旗標都可能影響。
  • iOS 差異:歷史上對 Orientation Lock、Vibration 支援有限;務必測你要支援的實機版本。

什麼情境該用哪一個?

  • 沉浸式媒體/遊戲:Orientation(+ Fullscreen)
  • 導航/計時/展示板:Wake Lock
  • 輕量觸感回饋:Vibration(Android 為主,iOS 以視覺替代)

👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 13 - Web Share API 用原生分享面板把網頁變得像 App
下一篇
Day 15 - 用 Notification API 讓網頁也能推播作業系統級通知
系列文
從 Canvas 到各式各樣的 Web API 之旅15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言