ヘッダーの文字が、時計と重なった
節約記録アプリで、こんな症状が出ました。
画面いちばん上のヘッダーの文字が、ステータスバーの時計やバッテリー表示と重なっていたのです。
アプリの画面が、ステータスバーの下まで潜り込んでいる状態です。
同時に、画面下の方でも同じことが起きていました。ジェスチャー操作用の帯が、画面の一番下に置いた広告バナーに重なりかけていました。
原因は Android 15 の「エッジツーエッジ」
調べると、原因は Android 15 の仕様変更でした。
アプリの対象バージョン(targetSdk)を 35 以上にすると、Android 15 以降の端末では、アプリの表示領域がステータスバーやナビゲーションバーの下まで強制的に広がります。これを「エッジツーエッジ」と呼びます。
画面の端から端まで使えるようになる代わりに、バーの下に隠れる部分をどう避けるかは、アプリ側の責任になりました。
まず CSS で直そうとした
私のアプリは、HTML で作った画面を Capacitor でアプリにしたものです。
こういうときの定番は CSS の env(safe-area-inset-top) です。ブラウザが「画面上端の安全な余白」を教えてくれるので、その分だけヘッダーを下げればいい。
ところが、直りませんでした。
CSS では直らなかった理由
ここが今回いちばんの落とし穴でした。
Android の WebView では、env(safe-area-inset-top) がステータスバーの高さを返さないことがあります。
WebView が反映しているのは、主に画面の切り欠き(ノッチやパンチホール)のほうでした。
そのため、切り欠きのない端末では値が 0 になります。検証に使ったエミュレーターの端末もそうでした。CSS を書いても、ずらす量が0なのですから、何も変わりません。
「CSS を書いたのに効かない」のではなく、「CSS が受け取る値そのものが0だった」のです。
Android の WebView と CSS の食い違いには、別の形でも足をすくわれたことがあります(たった1行のCSSが、Android WebViewのタッチスクロールを殺していた)。
同じ条件なのに、もう1本のアプリは平気だった
不思議なことに、ワードバトルは同じ targetSdk 36 なのに、この症状が出ていませんでした。
違いは、Capacitor のバージョンでした。
| アプリ | Capacitor | 症状 |
|---|---|---|
| ワードバトル | 8 系 | 出ない |
| 節約記録アプリ | 6 系 | 出る |
Capacitor 8 系では、フレームワークの側でステータスバーやナビゲーションバーの余白を処理してくれるようです。6 系ではその処理が効きませんでした。(公式の変更履歴までは追っていません。私の2本のアプリで起きた違いです。)
同じ Android、同じ targetSdk でも、Capacitor のバージョンで結果が変わる。これに気づくまでに時間がかかりました。
対処:Android 側で余白を渡す
Capacitor を 8 系に上げる手もありましたが、影響範囲が大きくなります。
そこで、Android 側の入口である MainActivity.java に、余白の処理を足すことにしました。修正はこの1ファイルだけです。
public class MainActivity extends BridgeActivity {
// ヘッダーの色。ステータスバーの背後の帯をこの色で塗り、ヘッダーとつながって見せる
private static final int SYSTEM_BAR_BACKGROUND = Color.parseColor("#1a3a2a");
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View content = findViewById(android.R.id.content);
content.setBackgroundColor(SYSTEM_BAR_BACKGROUND);
ViewCompat.setOnApplyWindowInsetsListener(content, (view, windowInsets) -> {
Insets bars = windowInsets.getInsets(
WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
view.setPadding(bars.left, bars.top, bars.right, bars.bottom);
// キーボードなどの余白は子に渡す必要があるので、ここでは消費しない
return windowInsets;
});
}
}
やっていることは3つです。
- システムのバー(ステータスバー・ナビゲーションバー)と切り欠きの大きさを、Android から直接受け取る
- その大きさを、画面全体の余白(padding)として与える
- 余白の部分が白く浮かないよう、背景をヘッダーと同じ色で塗る
CSS と違い、Android から受け取る値なので、切り欠きのない端末でもステータスバーの高さがきちんと入ります。
直ったことの確認
修正版(バージョン 1.2.1)で、次の2点を確かめました。
- ヘッダーの文字が時計と重ならない
- 画面下のジェスチャー用の帯が、広告バナーを隠さない
上と下、両方が同時に解決しました。

同じ症状で困っている方へ
HTML で作った画面をアプリにしていて、Android 15 でヘッダーがステータスバーに潜り込んだら、次の順で確認してみてください。
- Capacitor のバージョンを確認する。 8 系なら、フレームワーク側の設定を疑う
- 6 系なら、CSS の
env()にこだわらない。 受け取る値が0になっている可能性がある MainActivityに余白の処理を足す。 アップグレードより影響範囲が小さい
私は CSS で何度も試して時間を使いました。値が0なら、CSS をいくら書いても動きません。 そこに早く気づければ、遠回りせずに済みます。
この記事のアプリ:節約記録アプリ(紹介ページ)

コメント