ストップウォッチを動かしたまま他のアプリに切り替えて戻したら、秒が進んでいない。あるいは画面を消したら止まっていた。これは端末の故障ではなく、ブラウザとOSが電池を節約するために正しく働いた結果です。
結論から言うと、止まっているのは「計測」ではなく「画面の更新」であることがほとんどです。ブラウザは裏に回ったページで requestAnimationFrame を止め、setInterval / setTimeout の実行を間引きます。Chrome は裏のページのタイマーを1秒に1回、条件がそろうと1分に1回まで落とします(Chrome Developers)。したがって、経過時間を毎フレーム足し算していく作りのストップウォッチは本当に遅れますが、開始時刻との差で計算している作りなら、表示に戻った瞬間に正しい値へ揃います。まず自分が使っているものがどちらなのかを見分けるのが、いちばん早い解決です。
「遅れたまま」と「飛んで追いつく」は別物
同じ「裏で止まる」症状でも、中身の作りが2通りあります。表示に戻した後の挙動を1回見るだけで判別できます。
実装方式 | 裏に回っている間 | 表示に戻した直後 | 計測値として信頼できるか |
|---|---|---|---|
加算方式(一定間隔ごとに経過時間を足していく) | 間引かれた回数ぶん足し算が抜ける | 遅れたまま、そこから再開する | ×(裏に回した時間ぶん短く出る) |
開始時刻の差分方式(開始の時刻を覚えておき、今の時刻との差を取る) | 表示は固まるが、内部の基準時刻は動かない | 正しい値へ一気に飛んで追いつく | ○(裏に回しても結果は変わらない) |
つまり「戻ったら値が飛んでいた」のは正常で、むしろ正確な作りの証拠です。逆に「戻っても遅れたまま進み続ける」なら、そのツールの実装が加算方式で、計測結果そのものが短く出ています。ストップウォッチで記録を残す用途なら、ここを確認せずに使い続けるのは危険です。
ブラウザ側で起きていること(3つの仕組み)
1. setInterval / setTimeout が間引かれる
表示を1秒ごと・10ミリ秒ごとに書き換えている処理は、裏に回った時点でその頻度を守れなくなります。Firefox は非アクティブタブの最小間隔を1秒としており、Firefox for Android では15分まで落ちた上でタブ自体が破棄されることもあります(MDN)。Chrome の「集中的な間引き(intensive throttling)」は、ページが5分以上非表示・タイマーの連鎖が5回以上・30秒以上無音・WebRTC 未使用の条件がすべてそろったときに発動し、チェックが1分に1回まで落ちます。
裏を返せば音を鳴らし続けているタブは「30秒以上無音」の条件を外れるため、集中的な間引きの対象になりません。作業用BGMを流しているタブで症状が出にくいのは、これが理由です。
2. requestAnimationFrame はそもそも呼ばれない
画面の滑らかな更新に使う requestAnimationFrame は、通常ディスプレイのリフレッシュレート(多くは60Hz=毎秒60回)に合わせて呼ばれますが、「背面タブや非表示の iframe では、ほとんどのブラウザで一時停止される」と明記されています(MDN)。100分の1秒まで表示するストップウォッチはこの仕組みに頼っていることが多く、裏に回ると表示が完全に凍ります。これは「止まった」ように見える代表的な原因です。
3. 画面を消すと、ページは「非表示」になる
ここが Web の正直な限界です。ブラウザがページを「非表示(hidden)」と判断する条件には、タブの切り替えやウィンドウの最小化だけでなく「端末の画面がオフになっている」ことが含まれます(MDN Page Visibility API)。さらに Chrome では、非表示のページがフリーズ(frozen)状態に入るとタスクキューの実行そのものが停止し、破棄(discarded)されればJavaScriptは一切動きません(Page Lifecycle API)。
したがってロック画面でWebのストップウォッチを「動かし続ける」ことは、設定では解決できません。できるのは「画面を消さない」か「戻った時に時刻の差から正しい値を復元する」かの2つだけです。
回避策になるのは Web Worker と時刻の差分
処理をメインスレッドから Web Worker に移すと、タブが裏に回っても刻みが続きやすくなります。Mihataの集中時計も、複数のタイマーを同時に走らせるために専用の Worker(/clock/timer-worker.js)を置き、250ミリ秒ごとに残り時間を本体へ返す作りにしています。ただしこれも画面オフやフリーズの前では万能ではないため、最後の保険は常に「時刻の差で計算し直す」ことになります。
なお、時刻の基準には2種類あります。Date.now() は1970年起点の壁時計なので、計測中に端末の時刻設定が変わると値がずれる可能性があります。一方 performance.now() は単調増加で、時刻の調整やずれの影響を受けないと定義されています(MDN)。分や秒の計測では差は出ませんが、実験計時のように厳密さが要る場面では知っておく価値があります。
端末(OS)側の原因と直し方
ブラウザではなく専用アプリで止まる場合は、原因はOSの省電力機能にあります。こちらは設定で改善できる余地があります。
Android:電池の最適化とDoze
Android は「ユーザーが端末を電源から外し、画面をオフにして動かさない状態が続くと Doze モードに入る」と公式に説明されています。Doze 中はネットワークアクセスが停止し、ウェイクロックが無視され、setExact() や setWindow() を含む通常のアラームが次のメンテナンス時間枠まで先送りされます(Android Developers)。
対処は[設定]→[アプリ]→対象アプリ→[バッテリー]から、電池の最適化を「最適化しない」に変えることです。ただし公式ドキュメントは、一部免除されたアプリでもネットワークとウェイクロックが使えるようになるだけで「通常の AlarmManager のアラームは発火しない」と明記しています。目覚まし用の setAlarmClock() だけは通常どおり配信され、その直前にシステムが Doze を抜けます。つまり「除外設定にしたのに直らない」ときは、設定ではなくアプリ側の作りの問題です。
iPhone:低電力モードとバックグラウンド更新
iPhone の低電力モードは、Apple の公式ページで制限内容が列挙されています。自動ロックが30秒に設定され、ディスプレイの明るさが低下し、一部のビジュアルエフェクトがオフになり、「アプリのバックグラウンド更新」がオフになるという内容です(Appleサポート)。
ストップウォッチの用途で痛いのは自動ロック30秒です。ブラウザで計っている最中に30秒触らなければ画面が消え、前述のとおりページは非表示になります。計測中だけ低電力モードを切るか、[設定]→[画面表示と明るさ]→[自動ロック]を長めにして、充電しながら使うのが現実的です。
ブラウザとOS標準アプリの住み分け
ここまでの事情を踏まえると、「どちらが優れているか」ではなく用途で住み分けるのが正解です。
観点 | ブラウザのストップウォッチ | OS標準の「時計」アプリ |
|---|---|---|
画面を消した状態 | ページが非表示になり表示は止まる(復元は実装次第) | 別のアプリに切り替えても、端末がスリープしても計測は続く |
ロック画面・コントロールセンターでの確認 | できない | できる |
準備の手間 | URLを開くだけ・インストール不要 | 最初からある |
大きな画面で見せる | PCやタブレットでそのまま全画面にできる | 端末の画面サイズまで |
複数同時・ラップの一覧性 | 画面が広いぶん扱いやすい | 端末の仕様に依存 |
向いている場面 | 数秒〜数十分を画面を見ながら計る/会議・授業・配信で見せる | 画面を消して長時間・ポケットに入れて計る |
iPhone の「時計」アプリのストップウォッチについては、他のアプリを開いても、iPhone がスリープしても計測が続くとAppleのユーザガイドに書かれています(iPhoneユーザガイド)。ポケットに入れて走る、鍋を火にかけて別室へ行く、といった用途はこちらが本命です。
自分のケースを切り分ける
上から順に当てはめれば、どこに原因があるかは3分で分かります。
症状 | 原因の層 | 打ち手 |
|---|---|---|
表示に戻した瞬間、値が正しい時間まで飛んだ | 異常なし(表示の更新だけが止まっていた) | そのまま使ってよい |
表示に戻しても遅れたまま進む | ツールが加算方式 | 開始時刻の差分で計算するツールに替える |
同じタブを表示している間は正常。別タブに移すと止まる | ブラウザの間引き | そのタブを表示したままにする/音を鳴らしておく |
画面を消すと止まる | ページが非表示(Web共通の限界) | 自動ロックをオフにして充電しながら/OS標準アプリへ |
専用アプリなのに画面オフで止まる | OSの省電力(Doze・低電力モード) | 電池の最適化から除外/低電力モードを切る |
どれも直らない | アプリ側の実装 | OS標準アプリを本命に、Webを表示用の保険にする二重化 |
画面を消さずに計るやり方は、端末側の設定だけに頼らない手もあります。Webには画面のスリープを抑止する Screen Wake Lock という仕組みがあり、Mihataの集中時計では既定で有効にしたうえで、この仕組みが使えない環境(低電力モード中や古いiOSなど)では無音の極小動画を再生して代替する二段構えにしています。スマホのスリープで止まる症状そのものの切り分けはスマホのタイマーが勝手に止まる原因と直し方、時間は合っているのに音だけ出ない場合はタイマーが鳴らない時に上から順に試す手順にまとめてあります。
私たちも無料のWebストップウォッチを公開しています。実装は上で説明した開始時刻の差分方式で、開始の時刻と積み上げた経過時間だけを持ち、表示に戻ったタイミングで計算し直すため、裏に回しても値がずれません(状態はブラウザ内に保存するので、うっかりタブを再読み込みしても続きから戻ります)。記事の途中で恐縮ですが、登録もインストールも不要でそのまま開けるので、よろしければ試してみていただけたら嬉しいです。

キーボードだけで開始・ラップ・停止を操作したい場合は手を離さずに操作できるストップウォッチのキー割り当ても合わせてご覧ください。ブラウザ版はWebのストップウォッチからそのまま開けます。
正確な計測が要る場面での注意
裏で止まる問題を解決しても、計測そのものの誤差は別に残ります。人間がボタンを押して計る手動計時には、反応時間による誤差が必ず乗ります。スポーツの計時や実験のように記録が意味を持つ場面では、次の3点を先に決めておくと後の揉め事が減ります。
- 何を公式記録にするか:手動計時の値は目安として扱い、記録として残すなら計測方法を併記する
- 誰が押すか:複数人で計って中央値を採る、あるいは同じ人が通して計る
- ラップの基準:区間タイム(スプリット)と累積タイムのどちらを見せるかを揃える
陸上など競技の計時における具体的な進め方は陸上のタイム計測とストップウォッチの使い方で詳しく扱っています。
まとめ:どれを使えばいいか
- 数秒〜数十分を画面を見ながら計る:ブラウザで十分。むしろ大きな画面で見せられる利点がある
- 画面を消して長時間計る・持ち歩く:OS標準の「時計」アプリが本命
- 記録として残す:開始時刻の差分方式かどうかを一度確認し、計測方法を併記する
- 何度も止まって困っている:設定を詰めるより、止まる前提で二重化するほうが早い
社内の複数端末で同じ症状が出ている、計測の手順そのものを業務として整えたい、という場合はご相談ください。
よくある質問
スマホでストップウォッチがバックグラウンドで止まるのは故障ですか?
故障ではありません。ブラウザは裏に回ったページの requestAnimationFrame を一時停止し、setInterval / setTimeout の実行を間引きます。Chrome は裏のページのタイマーを1秒に1回、条件がそろうと1分に1回まで落とします。多くの場合、止まっているのは計測ではなく画面の更新です。
表示に戻したら値が大きく飛びました。壊れていますか?
むしろ正確な作りの証拠です。開始時刻を覚えておき現在時刻との差で経過時間を出す実装なら、裏で表示が止まっていても戻った瞬間に正しい値へ追いつきます。逆に戻しても遅れたまま進む場合は、一定間隔で足し算する加算方式で、計測値が実際より短く出ています。
画面を消してもブラウザで計測を続ける方法はありますか?
設定では解決できません。ブラウザは端末の画面がオフになっている状態もページの「非表示」に含めて扱い、Chrome では非表示のページがフリーズすればタスクの実行自体が止まります。画面を消さずに置く(自動ロックを長くして充電しながら使う)か、OS標準の時計アプリを使うかの二択になります。
Android で専用アプリが画面オフだと止まります。
Doze モードが原因です。電源から外して画面をオフにし動かさない状態が続くと Doze に入り、setExact() を含む通常のアラームが次のメンテナンス時間枠まで先送りされます。対象アプリを電池の最適化から除外すると改善しますが、公式ドキュメントには一部免除でも通常の AlarmManager のアラームは発火しないと明記されているため、それでも直らない場合はアプリ側の実装の問題です。
iPhone の低電力モードは計測に影響しますか?
影響します。Apple の公式ページによると、低電力モード中は自動ロックが30秒に設定され、アプリのバックグラウンド更新がオフになります。ブラウザで計っている最中に30秒触らないと画面が消え、ページが非表示になって表示が止まります。計測中は低電力モードを切り、自動ロックを長めにしておくのが安全です。