Make WebViews edge-to-edge. Make your WebViews compatible with… | by Ash Nohe | Android Developers | Mar, 2025

Make WebViews edge-to-edge. Make your WebViews compatible with… | by Ash Nohe | Android Developers | Mar, 2025

Home » News » Make WebViews edge-to-edge. Make your WebViews compatible with… | by Ash Nohe | Android Developers | Mar, 2025
Table of Contents

Guarantee your WebViews are appropriate with Android 16, as Android 16 removes the power to opt-out of drawing your app edge-to-edge. The best way you deal with insets for WebViews is dependent upon whether or not or not your app owns the net content material.

This submit assumes primary information of dealing with insets and is relevant in case your WebViews are drawing beneath system bars or show cutouts. See the Compose and Views documentation, and the Inset dealing with suggestions weblog for steerage on dealing with insets.

If you happen to’re searching for steerage on find out how to make your webpage edge-to-edge on Chrome, see the Chrome on Android edge-to-edge migration information as a substitute.

This submit covers the next matters:

  • Find out how to deal with WebViews in case your app doesn’t personal the net content material
  • Find out how to deal with WebViews in case your app owns the net content material
  • Dealing with IME insets in WebViews

WebViews displaying exterior content material can not simply draw edge-to-edge and will as a substitute be inset to keep away from the system bars and show cutout. The implementation is totally different relying on in case you’re utilizing Compose or Views, however typically follows these steps:

  1. Wrap the WebView in a container and apply insets as padding on that container.
  2. Set the app’s background colour in a best-effort try to match the webpage.
Three app screenshots showing WebView layout issues and fixes.
Determine 1. Left to proper. (a) The left picture reveals a full display screen WebView in an app focusing on SDK 35, at which level edge-to-edge is enforced. The highest of the WebView collides with standing bar icons. (b) The center picture reveals the results of padding the WebView’s mum or dad. The app’s background is ready to crimson to make it obvious that the WebView is inset. (c) The precise picture is the specified outcome. The app’s background is ready to white in a best-effort try to match the webpage.

See the next code samples.

Apply insets to a WebView in a Compose app

To make sure a WebView in Compose avoids overlapping with system bars, show cutout and keyboard, apply Modifier.windowInsetsPadding(WindowInsets.safeDrawing) to its wrapper (e.g. AndroidView). This offers the required padding to maintain the WebView content material inside the secure space of the display screen.

@Composable
enjoyable WebViewInCompose() {
AndroidView(
modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing),
manufacturing unit = { context ->
WebView(context).apply {
// Configure WebView choices right here
}
}
)
}

Then, replace your app’s background so it matches the WebView’s background as a lot as doable.

Apply insets to a WebView in a Views app

To make sure a WebView in Views avoids overlapping the system bars, show cutout and keyboard, wrap the WebView in a container like a FrameLayout and do one of many following:

  • Set android:fitsSystemWindows="true"
  • Use ViewCompat.setOnApplyWindowInsetsListener() and apply systemBars, displayCutout, and ime insets on the container. See the Views documentation for a code pattern utilizing the listener.

Lastly, replace android:windowBackground in your themes.xml so it matches the WebView’s background if doable.

In case your app owns the net content material, both pad the WebView’s mum or dad as described above; or, use JavaScript to inject padding into the net web page to attract the web page edge-to-edge as described under.

To inject padding into the net web page, first add <meta identify=”viewport” content material=”viewport-fit=cowl”> to your HTML.

<meta identify="viewport" content material="viewport-fit=cowl, initial-scale=1" />

Second, outline CSS variables for high, proper, backside and left secure space insets, because the env(safe-area-inset-*) variables return 0px on Android on the time of penning this weblog.

/* CSS */
physique {
padding-top: var(--safe-area-inset-top);
padding-right: var(--safe-area-inset-right);
padding-bottom: var(--safe-area-inset-bottom);
padding-left: var(--safe-area-inset-left);
}

As an alternative of making use of insets on the WebView’s container, use JavaScript to cross the insets to your CSS variables to pad the webpage. The implementation is totally different relying on in case you’re utilizing Compose or Views, nevertheless it typically follows these steps:

  1. Retrieve the highest, proper, backside and left system bar, show cutout and IME insets as uncooked pixel values.
  2. Convert the uncooked pixel values to density unbiased pixels.
  3. Inject the density unbiased pixels into the CSS variables as CSS pixels. When the web site renders on the Android gadget, the WebView converts the CSS pixels again to density unbiased pixels. See Assist totally different screens in internet apps for extra data.
  4. In Compose, recompose when the software program keyboard expands or collapses if relevant.
  5. In Views, dispatch insets when the webpage first hundreds.
Two app screenshots. Top: WebView overlapping system bars and cutout. Bottom: WebView correctly padded using JavaScript.
Determine 2. Prime to backside. (a) The highest picture reveals a full display screen WebView in an app focusing on SDK 35, at which level edge-to-edge is enforced. The WebView collides with system bars and show cutout. (b) The underside picture reveals the results of utilizing JavaScript to inject padding into the webpage, which is the edge-to-edge outcome we would like.

See the next code samples.

Utilizing Compose and JavaScript to inject insets into internet pages

A code pattern exhibiting find out how to use JavaScript to inject insets into webpages in a Compose app.

import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.basis.format.WindowInsets
import androidx.compose.basis.format.ime
import androidx.compose.basis.format.safeDrawing
import androidx.compose.ui.unit.Dp
...

@Composable
enjoyable MainScreen() {
Field(modifier = Modifier.fillMaxSize()) {

// Retrieve insets as uncooked pixels
val insets = WindowInsets.safeDrawing
WebViewInCompose(
initialUrl = "file:///android_asset/instance.html",
insets = insets
)
}
}

@SuppressLint("SetJavaScriptEnabled")
@Composable
enjoyable WebViewInCompose(
initialUrl: String,
insets: WindowInsets,
density: Density = LocalDensity.present,
layoutDirection: LayoutDirection = LocalLayoutDirection.present,
myWebViewClient: CustomWebViewClient = keep in mind { CustomWebViewClient(
insets, density, layoutDirection
) }
) {

// Do not apply insets to the container
AndroidView(
manufacturing unit = { context ->
WebView(context).apply {
webViewClient = myWebViewClient
settings.javaScriptEnabled = true
loadUrl(initialUrl)
}
}, replace = { view ->

// Updates webpage when software program keyboard expands or collapses.
// In case your webpage does not have an enter discipline that opens the
// software program keyboard, take away this line.
applySafeAreaInsetsToWebView(insets, density, layoutDirection, view)
}
)
}

class CustomWebViewClient(
non-public val insets: WindowInsets,
non-public val density: Density,
non-public val layoutDirection: LayoutDirection
) : WebViewClient(){

override enjoyable onPageFinished(view: WebView?, url: String?) {
tremendous.onPageFinished(view, url)

// Inject insets into the webpage as soon as the web page has absolutely loaded
applySafeAreaInsetsToWebView(insets, density, layoutDirection, view)
}
}

non-public enjoyable applySafeAreaInsetsToWebView(
insets: WindowInsets,
density: Density,
layoutDirection: LayoutDirection,
webView: WebView?){

// Convert uncooked pixels to density unbiased pixels
val high = insets.getTop(density).toDp(density).worth
val proper = insets.getRight(density, layoutDirection).toDp(density).worth
val backside = insets.getBottom(density).toDp(density).worth
val left = insets.getLeft(density, layoutDirection).toDp(density).worth

val safeAreaJs = """
doc.documentElement.type.setProperty('--safe-area-inset-top', '${high}px');
doc.documentElement.type.setProperty('--safe-area-inset-right', '${proper}px');
doc.documentElement.type.setProperty('--safe-area-inset-bottom', '${backside}px');
doc.documentElement.type.setProperty('--safe-area-inset-left', '${left}px');
"""

// Inject the density unbiased pixels into the CSS variables as CSS pixels
webView?.evaluateJavascript(safeAreaJs, null)
}

non-public enjoyable Int.toDp(density: Density): Dp = with(density) { [email protected]() }

Utilizing Views and JavaScript to inject insets into internet pages

A code pattern exhibiting find out how to use JavaScript to inject insets into webpages in a Views app.

import androidx.core.util.TypedValueCompat.pxToDp
import
androidx.core.view.WindowInsetsCompat.Kind.displayCutout
import androidx.core.view.WindowInsetsCompat.Kind.ime
import androidx.core.view.WindowInsetsCompat.Kind.systemBars
...

override enjoyable onCreate(savedInstanceState: Bundle?) {
...

val myWebView: WebView = findViewById(R.id.webView)
myWebView.settings.javaScriptEnabled = true
myWebView.loadUrl("file:///android_asset/instance.html")

ViewCompat.setOnApplyWindowInsetsListener(myWebView) { _, windowInsets ->

// Retrieve insets as uncooked pixels
val safeDrawingInsets = windowInsets.getInsets(
systemBars() or displayCutout() or ime()
)
val displayMetrics = myWebView.context.sources.displayMetrics

// Convert uncooked pixels to density unbiased pixels
val high = pxToDp(safeDrawingInsets.high.toFloat(), displayMetrics)
val proper = pxToDp(safeDrawingInsets.proper.toFloat(), displayMetrics)
val backside = pxToDp(safeDrawingInsets.backside.toFloat(), displayMetrics)
val left = pxToDp(safeDrawingInsets.left.toFloat(), displayMetrics)

val safeAreaJs = """
doc.documentElement.type.setProperty('--safe-area-inset-top', '${high}px');
doc.documentElement.type.setProperty('--safe-area-inset-right', '${proper}px');
doc.documentElement.type.setProperty('--safe-area-inset-bottom', '${backside}px');
doc.documentElement.type.setProperty('--safe-area-inset-left', '${left}px');
"""

// Inject the density unbiased pixels into the CSS variables as CSS pixels
myWebView.evaluateJavascript(safeAreaJs, null)

windowInsets
}

myWebView.webViewClient = object : WebViewClient() {
override enjoyable onPageFinished(view: WebView, url: String) {
tremendous.onPageFinished(myWebView, url)
// dispatch insets as a result of insets aren't utilized when the webpage first hundreds.
view.requestApplyInsets()
}
}
}

Be aware: If the injected insets look too giant, it may be as a result of your web site’s Viewport initial-scale is greater than 1. On this case, divide the highest, proper, backside, and left variables by the dimensions.

To make sure your internet web page appropriately adjusts when the on-screen keyboard (IME) seems, you need to additionally account for IME insets. The supplied Compose and Views code instance already contains this by retrieving WindowInsets.safeDrawing() in Compose or WindowInsetsCompat.Kind.ime() in Views:

// Getting IME insets from the above Compose code pattern
// safeDrawing contains ime, systemBars, and displayCutout
WindowInsets.safeDrawing

// Getting IME insets from the above Views code pattern
val safeDrawingInsets = windowInsets.getInsets(
systemBars() or displayCutout() or ime()
)

Omitting IME insets will result in points the place the webpage content material is obscured by the keyboard. For instance, when the person faucets an HTML textual content enter and the IME expands, the webpage gained’t resize, stopping the person from seeing content material hidden behind the keyboard. By together with IME insets, the webpage dynamically adjusts its format when the IME is displayed, guaranteeing all content material stays accessible to the person.

Determine 3. Left (incorrect implementation) to proper (appropriate implementation). (a) The left GIF reveals a full-screen WebView the place IME insets aren’t dealt with. When the IME seems, the person can not scroll to view content material behind it. (b) The precise picture reveals the identical WebView with appropriate IME inset dealing with. After the IME seems, the person can scroll to entry the complete webpage content material.

In abstract, guaranteeing WebViews are appropriate with an edge-to-edge show requires totally different approaches relying on whether or not the app owns the net content material. For exterior content material, wrap the WebView in a container and apply insets as padding. For owned content material, both pad the container or inject JavaScript to deal with insets inside the webpage.

Supply hyperlink

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 
share this article.

Enjoying my articles?

Sign up to get new content delivered straight to your inbox.

Please enable JavaScript in your browser to complete this form.
Name