Fixing iOS Chrome Overlay Gap in WooCommerce Flatsome Theme

Summary

This post analyses a fixed‑position overlay bug that manifests only on iOS Chrome when a WooCommerce “Add to Cart” AJAX call is triggered in the Flatsome theme. The overlay does not fill the expanded viewport after the native bottom‑bar auto‑hides, leaving a visible gap. The root cause is a transient CSS transform applied by the theme that creates a new stacking context, causing the overlay to behave as absolute instead of filling the viewport.

Root Cause

  • Flatsome’s JavaScript adds transform: translate3d(0,0,0); to #wrapper/body when the minicart animation starts.
  • The transform implicitly creates a new CSS containing block for positioned descendants.
  • A position: fixed element inside that block no longer references the root viewport; it references the transformed element, whose height has not yet been updated to the new viewport size.
  • On iOS, when the bottom navigation bar shrinks the viewport, the browser does not immediately propagate the new size up the cascade to elements inside a transformed ancestor.

As a result, the overlay appears with the old height, leaving a bottom gap until a manual resize or scroll forces a layout re‑calc.

Why This Happens in Real Systems

  • Transform‑induced stacking contexts are common for off‑canvas menus and modals.
  • Mobile browsers often delay viewport updates when dynamic UI chrome changes (e.g., auto‑hide browser bars).
  • The interplay between CSS transforms and position: fixed is well‑documented but rarely anticipated in complex themes that manipulate the DOM on mount.

Real-World Impact

  • Users see an incomplete overlay, exposing page content during loading.
  • Affects perceived performance and usability, especially during checkout.
  • Can lead to accidental interactions when the overlay does not block touches.

Example or Code (if necessary and relevant)

No additional executable code required for explanation. The intent was to show the overlay CSS:

.overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0,0,0,.5);
  z-index: 9999;
}

How Senior Engineers Fix It

  • Force the overlay into the root stack by adding transform: translateZ(0); to the overlay itself – this creates an independent stacking context that bypasses the parent transform.
  • Temporarily disable the theme’s transform during the overlay’s lifecycle:
    // Before showing the overlay
    const wrapper = document.querySelector('#wrapper');
    wrapper.style.transform = '';
    // Show overlay
    overlay.style.display = 'block';
    // After overlay hides
    wrapper.style.transform = 'translate3d(0,0,0)';
  • Use position: fixed; with height: 100dvh; and trigger requestAnimationFrame after the browser bar change is detected.
  • Leverage the VisualViewport API to read the updated viewport height after the resize event specific to iOS:
    window.visualViewport.addEventListener('resize', () => {
        overlay.style.height = `${window.visualViewport.height}px`;
    });

Why Juniors Miss It

  • They overlook how transform creates new containing blocks for position: fixed.
  • They assume viewport units (vh, dvh) are always accurate; iOS Chrome’s delayed viewport adjustment is rarely considered.
  • There is a bias toward “cleaning up CSS” instead of manipulating DOM styles dynamically during component lifecycle.
  • They may not test on actual mobile devices, missing subtle bugs that only appear with browser UI changes.

Leave a Comment