Background image moving when the address bar disappears on iOS/Android/Mobile Chrome

I am currently in the process of developing a responsive website using Twitter Bootstrap.

The website features a full-screen background image that rotates and fades through different images on mobile, tablet, and desktop. This effect is achieved using two divs.

Everything seems to be working perfectly, except for one issue. When users scroll down the page on iOS Safari, Android Browser, or Chrome on Android, the background slightly jumps and causes the address bar to hide.

You can view the website here:

If you visit the site on a mobile device and scroll down, you should notice the image resize/move.

Below is the code I am using for the background DIV:

#bg1 {
    background-color: #3d3d3f;
    background-repeat:no-repeat;
    background-attachment:fixed;
    background-position:center center;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover; 
    position:fixed;
    width:100%;
    height:100%;
    left:0px;
    top:0px;
    z-index:-1;
    display:none;
}

I would appreciate any suggestions or feedback - this issue has been bothering me for quite some time!

Answer №1

The issue at hand stems from the dynamic nature of URL bars causing shifts in size and position, impacting the dimensions of #bg1 and #bg2 divs set to 100% height and "fixed". This alteration triggers adjustments to the background image size and alignment due to its "cover" setting, adapting to changes in the containing area.

Given the site's responsive design requirements, a need for background scaling arises. Two potential solutions are contemplated:

1) Setting the heights of #bg1 and #bg2 to 100vh presents an elegant fix conceptually. Nonetheless, complications arise with iOS's vh bug (). Despite attempts using max-height parameters to counter this issue, it persists.

2) By utilizing Javascript to determine viewport size unaffected by the URL bar, a static height assignment for #bg1 and #bg2 based on viewport dimensions becomes feasible. While not an ideal CSS-only resolution and resulting in slight image displacement on page load, it stands as a practical recourse in light of persistent iOS "vh" bugs (reportedly unresolved in iOS 7).

var bg = $("#bg1, #bg2");

function resizeBackground() {
    bg.height($(window).height());
}

$(window).resize(resizeBackground);
resizeBackground();

An observation worth noting pertains to the recurrent challenges posed by resizing URL bars on iOS and Android devices. Acknowledging their purpose is essential, yet reconsideration of their operational peculiarities and disruptive impact on web functionalities seems imperative. The recent development prohibiting URL bar concealment upon page load via scroll maneuvers further complicates matters.

EDIT: Although the aforementioned script effectively mitigates background resizing issues, a noticeable gap emerges during user scrolling. This anomaly arises from maintaining background proportions relative to screen height minus the URL bar. Incorporating a +60px adjustment proposed by swiss eliminates this setback, albeit sacrificing visibility of the bottom 60px of the background image when the URL bar is visible—it however ensures seamless interface experience without revealing any gaps.

function resizeBackground() {
    bg.height( $(window).height() + 60);
}

Answer №2

After experimenting with different solutions, I discovered that the approach suggested by Jason wasn't completely eliminating the issue of the background jumping when the browser address bar disappeared/reappeared. In addition to implementing JavaScript to remove the gap at the top of the page, I also added transition: height 999999s to the div. This technique creates a transition effect with an extremely long duration, effectively preventing any movement in the element.

Answer №3

We are encountering a similar issue with the header on our website.

html, body {
    height:100%;
}
.header {
    height:100%;
}

On Android Chrome, there is a jumpy scrolling experience as the .header-container rescales when the URL bar hides and the finger is lifted from the screen.

CSS Fix:

To prevent the URL bar from hiding and allow for vertical scrolling, add the following CSS lines:

html {
    overflow: hidden;
}
body {
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
}

Answer №4

To address the issue at hand, a media query combined with some mathematical calculations can provide a solution. Below is an approach tailored for a portrait orientation:

@media (max-device-aspect-ratio: 3/4) {
  height: calc(100vw * 1.333 - 9%);
}
@media (max-device-aspect-ratio: 2/3) {
  height: calc(100vw * 1.5 - 9%);
}
@media (max-device-aspect-ratio: 10/16) {
  height: calc(100vw * 1.6 - 9%);
}
@media (max-device-aspect-ratio: 9/16) {
  height: calc(100vw * 1.778 - 9%);
}

When the url bar disappears and affects the viewport's vertical height (vh), an alternative method must be devised to determine the correct height. By leveraging the constant width of the viewport and the limited range of mobile device aspect ratios, one can calculate the precise vh value using the following steps:

1) Establish a set of media queries targeting specific aspect ratios.

  • Utilize 'device-aspect-ratio' instead of 'aspect-ratio' to account for url bar disappearance.

  • Incorporate 'max' in the device-aspect-ratio to cover any unforeseen aspect ratios between popular ones. Though less exact, it will still yield satisfactory results for most users.

  • Remember to adjust the numbers when switching from landscape to portrait orientations.

2) For each media query, multiply the desired percentage of vertical height in vw by the inverse of the aspect ratio.

  • Calculate the product of the desired percentage (e.g., 100%) and the height-to-width ratio to obtain the correct vh value.

3) Account for the impact of the url bar height by subtracting it from the calculated height. While exact measurements may vary, using 9% as a standard for mobile devices in landscape orientation generally yields satisfactory outcomes.

While this solution may not be the most elegant, other alternatives such as encountering user bugs, incorrectly sized elements, or resorting to unnecessary JavaScript for basic styling are far less desirable. Despite potential variations in url bar heights among devices, adopting this methodology ensures a consistent experience compared to indiscriminate resizing during swiping interactions across all platforms.

For convenience, a SASS mixin has been created to streamline the process:

@mixin vh-fix {
  @media (max-device-aspect-ratio: 3/4) {
    height: calc(100vw * 1.333 - 9%);
  }
  @media (max-device-aspect-ratio: 2/3) {
    height: calc(100vw * 1.5 - 9%);
  }
  @media (max-device-aspect-ratio: 10/16) {
    height: calc(100vw * 1.6 - 9%);
  }
  @media (max-device-aspect-ratio: 9/16) {
    height: calc(100vw * 1.778 - 9%);
  }
}

Answer №5

Everybody seems to be fixated on using the window height, forgetting that the screen height is also a viable option.

Check out this jQuery solution I came up with:

$(function(){

  var $w = $(window),
      $background = $('#background');

  // Addressing background image jump on mobile devices
  if ((/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera)) {
    $background.css({'top': 'auto', 'bottom': 0});

    $w.resize(sizeBackground);
    sizeBackground();
  }

  function sizeBackground() {
     $background.height(screen.height);
  }
});

The addition of the .css() section ensures that the absolutely positioned element stays aligned at the bottom, eliminating any potential jumping issues. Although, it could simply be included in the CSS directly.

We're using the user agent sniffer because screen height on desktops wouldn't solve the problem.

Keep in mind that all of this assumes that #background is fixed-positioned and fills the window.

For those who prefer pure JavaScript (caution: untested):

var background = document.getElementById('background');

// Fix background image jump on mobile
if ((/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera)) {
  background.style.top = 'auto';
  background.style.bottom = 0;

  window.onresize = sizeBackground;
  sizeBackground();
}

function sizeBackground() {
  background.style.height = screen.height;
}

UPDATE: Apologies for not directly addressing your specific issue with multiple backgrounds. This post may come in handy when searching for solutions to fixed background images jumping on mobile screens.

Answer №6

I have found a solution that involves checking the userAgent during $(document).ready to identify problematic browsers. If one of these browsers is detected, I suggest following these steps:

  1. Adjust the relevant heights to match the current viewport height rather than using '100%'
  2. Save the current horizontal viewport value
  3. Subsequently, on $(window).resize, update the relevant height values only if the new horizontal viewport dimension differs from the initial value
  4. Keep track of the new horizontal and vertical values

Additionally, consider allowing vertical resizes only when they exceed the height of address bars.

It's worth noting that the address bar has an impact on $(window).height. For more information, you can visit: Mobile Webkit browser (chrome) address bar changes $(window).height(); making background-size:cover rescale every time JS "Window" width-height vs "screen" width-height?

Answer №7

Encountered a similar issue while attempting to create a fullscreen entrance screen for the viewport. Unfortunately, the suggested solution no longer functions as intended.

1) Elements set with a height of 100vh are constantly resized whenever the viewport dimensions change, such as when the URL bar appears or disappears.

2) The use of $(window).height() is also affected by changes in the size of the URL bar.

One workaround involves "freezing" the element by using transition: height 999999s, as proposed in AlexKempton's response. However, this approach disables responsiveness to all viewport size adjustments, including those resulting from screen rotation.

My solution entails manually handling viewport changes through JavaScript. This way, I can disregard minor alterations likely caused by the URL bar and only respond to significant adjustments.

function greedyJumbotron() {
    var HEIGHT_CHANGE_TOLERANCE = 100; // Approximate URL bar height in Chrome on tablets

    var jumbotron = $(this);
    var viewportHeight = $(window).height();

    $(window).resize(function () {
        if (Math.abs(viewportHeight - $(window).height()) > HEIGHT_CHANGE_TOLERANCE) {
            viewportHeight = $(window).height();
            update();
        }
    });

    function update() {
        jumbotron.css('height', viewportHeight + 'px');
    }

    update();
}

$('.greedy-jumbotron').each(greedyJumbotron);

EDIT: I combine this method with height: 100vh. The page renders correctly initially, and then the JavaScript takes over to manage the height manually. This eliminates any flickering during page load or afterwards.

Answer №8

I came across a simple solution that doesn't require the use of Javascript:

transition: height 1000000s ease;
-webkit-transition: height 1000000s ease;
-moz-transition: height 1000000s ease;
-o-transition: height 1000000s ease;

Basically, this just slows down the movement so much that it's practically imperceptible.

Answer №9

To solve this issue, I implemented a clever javascript solution. By keeping the div at 100% or 100vh initially, we prevent it from not appearing on page load. Then, on page load, I used javascript to grab the window height and applied it to the element in question. This approach eliminates any jumping by ensuring a static height for the div.

var $hero = $('#hero-wrapper'),
    h     = window.innerHeight;

$hero.css('height', h);

Answer №10

I have devised a simple vanilla JavaScript solution for utilizing VH units without experiencing any glitches when address bars minimize on scroll. To address the jankiness that occurs during page redraws, I've crafted this JavaScript snippet that targets elements using VH units (if they are assigned the class .vh-fix) and assigns them inline pixel heights to freeze them at the desired height. This can be triggered upon rotation or viewport size changes to maintain responsiveness.

var els = document.querySelectorAll('.vh-fix')
if (!els.length) return

for (var i = 0; i < els.length; i++) {
  var el = els[i]
  if(el.nodeName === 'IMG') {
    el.onload = function() {
      this.style.height = this.clientHeight + 'px'
    }
  } else {
    el.style.height = el.clientHeight + 'px'
  }
}

This approach has effectively addressed all of my use cases, and I hope it proves to be helpful for you as well.

Answer №11

Here is my approach to solving the issue at hand, with detailed comments included directly in the code. I have thoroughly tested this solution and it functions smoothly. Hopefully, it proves helpful to others facing a similar problem.

// To begin with, we eliminate the height property from the file's CSS as it will be set dynamically upon page load
// Insert the following code snippet into a script after declaring your scripts in the index file

var setHeight = function() {    
  var windowHeight = $(window).height();   
  $('#bg1, #bg2').css('height', windowHeight);
};

setHeight(); // Initially, set the CSS height with a fixed value on the first page load

if(typeof window.orientation !== 'undefined') { // This method intelligently detects mobile devices, as desktop does not support this property
  var query = window.matchMedia("(orientation:landscape)"); // It helps verify if the device is in landscape mode
  var changeHeight = function(query) {                      
    if (query.matches) {                                    
      setHeight(); // Adjust height for landscape mode
    } else {                                                
      setHeight(); // Reset height for portrait mode
    }
  }
  query.addListener(changeHeight);                          // Add a listener for this event
} 
else { // This section is tailored for desktop use only                                     
  $( window ).resize(function() {                           
    setHeight();                                            // Ensure responsiveness by resizing when the browser window changes
  }); 
};

Answer №12

This solution has proven to be the most effective and straightforward out of all the methods I have attempted.

However, it does not maintain the original look and feel of the address bar!

To achieve this effect, you can utilize CSS to set the height to 100% initially and then dynamically adjust it to 90% of the window height using JavaScript upon document load.

For instance, utilizing jQuery:

$("#element").css("height", 0.9*$(window).height());

Keep in mind that relying solely on CSS may not yield the desired results and it's important to note that vh and vw units may be inconsistent on iPhones - opting for percentages is recommended.

Answer №13

For those seeking a solution to a bug caused by the hidden address bar in the browser interface, this answer is for you.

When the address bar is hidden, the resize event is triggered. Unlike other resize events, such as switching to landscape mode, this does not change the width of the window. To address this issue, I recommend hooking into the resize event and checking if the width remains the same.

// Keep track of window width
let myWindowWidth = window.innerWidth;

window.addEventListener( 'resize', function(event) {

    // If width is the same, assume hiding address bar
    if( myWindowWidth == window.innerWidth ) {
         return;
    }

    // Update the window width
    myWindowWidth = window.innerWidth;

    // Do your thing
    // ...
});

Answer №14

Using JavaScript, I successfully adjusted the width element and then set the height to be equal to a percentage of the viewport height.

HTML

<div id="gifimage"><img src="back_phone_back.png" style="width: 100%"></div>

CSS

#gifimage {
    position: absolute;
    height: 70vh;
}

JavaScript

imageHeight = document.getElementById('gifimage').clientHeight;

// if (isMobile)       
document.getElementById('gifimage').setAttribute("style","height:" + imageHeight + "px");

This method worked perfectly for me without using jQuery or similar libraries, as I wanted to ensure quick loading times.

Answer №15

After investing a few hours into unraveling the intricacies of this issue and devising the most effective solution, I discovered that only iOS Chrome was affected as of April 2016. Surprisingly, Android Chrome and iOS Safari performed flawlessly without requiring any adjustments. To address the issue on iOS Chrome, I employed the following script:

$(document).ready(function() {
   var screenHeight = $(window).height();
   $('section-with-background-image').css('height', screenHeight + 'px');
});

Answer №16

Just like how @AlexKempton mentioned (couldn't leave a comment, sorry)

I've discovered a trick using long transition delays to avoid the element resizing.

For example:

transition: height 250ms 600s; /*10 minute delay*/

The downside is that it prevents the element from resizing, even when the device rotates. But you could always use some JavaScript to detect orientationchange and reset the height if needed.

Answer №17

If your background allows, consider setting the background-size property to cover the device width using media queries and combining it with the :after position: fixed; hack. You can find more information here.

For example, you could set background-size to 901px for screens less than 900px. While this may not be a perfect or responsive solution, it worked well for me on mobile screens smaller than 480px since I was using an abstract background.

Answer №18

After receiving the code snippet from @cr0ybot, I made some modifications to the background size and position settings in order to adapt it to my specific needs.

$(function(){
      var $w = $(window),
            $background = $('.slideshow-fullscreen');
      
      // Adjustment for smooth background image display on mobile devices
      if ((/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera)) {
            $background.css({'top': 'auto', 'bottom': 0});
            $w.resize(sizeBackground);
            sizeBackground();
      }
      
      function sizeBackground() {
            $background.height( $(window).height());
            $background.css({'background-size':'auto '+$(window).height()+'px'});
            $background.css({'background-position':'top center'});
      }
});

Answer №19

My simple workaround involves adjusting the height of bg1 on page load using this code snippet:

var BG = document.getElementById('bg1');
BG.style.height = BG.parentElement.clientHeight;

I then add a resize event listener to the Window that checks if the height difference after resizing is greater than 60px (excluding the URL bar height). If it is, I set bg1's height to match its parent's height again. Here's the full code snippet:

window.addEventListener("resize", onResize, false);
var BG = document.getElementById('bg1');
BG.style.height = BG.parentElement.clientHeight;
var oldH = BG.parentElement.clientHeight;

function onResize() {
    if(Math.abs(oldH - BG.parentElement.clientHeight) > 60){
      BG.style.height = BG.parentElement.clientHeight + 'px';
      oldH = BG.parentElement.clientHeight;
    }
}

It's frustrating having to deal with this bug!

Answer №20

Are you looking to track the inner height and vertical scroll of your window in real-time as the Chrome mobile browser transitions the URL bar? I have come across a unique solution that involves setting an interval function to monitor changes in the window.innerHeight.

Here is the code snippet:

var innerHeight = window.innerHeight;
window.setInterval(function ()
{
  var newInnerHeight = window.innerHeight;
  if (newInnerHeight !== innerHeight)
  {
    var newScrollY = window.scrollY + newInnerHeight - innerHeight;
    // ... implement any necessary actions with the updated scrollY value
    innerHeight = newInnerHeight;
  }
}, 1000 / 60);

I find this method quite useful. If you have any alternative approaches or suggestions, please feel free to share!

Answer №21

In a situation similar to this, I found a solution by adjusting the element's height to window.innerHeight whenever the touchmove event was triggered.

var lastHeight = '';

$(window).on('resize', function () {
    // Resetting height when a standard resize event occurs
    if (lastHeight) {
        $('#bg1').height(lastHeight = '');
    }
}).on('touchmove', function () {
    // Adjusting div's height when window height changes
    if (lastHeight != window.innerHeight) {
        $('#bg1').height(lastHeight = window.innerHeight);
    }
});

This adjustment ensures the element always fully spans the available screen, regardless of address bar hiding or showing.

It's unfortunate that we need these workarounds instead of simply using position: fixed.

Answer №22

Utilizing CSS custom properties (also known as variables) on iOS allows you to dynamically set and apply them exclusively on iOS.


const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if (iOS) {
  document.body.classList.add('ios');
  const vh = window.innerHeight / 100;
  document.documentElement.style
    .setProperty('--ios-10-vh', `${10 * vh}px`);
  document.documentElement.style
    .setProperty('--ios-50-vh', `${50 * vh}px`);
  document.documentElement.style
    .setProperty('--ios-100-vh', `${100 * vh}px`);
}

body.ios {
    .side-nav {
        top: var(--ios-50-vh);
    }
    section {
        min-height: var(--ios-100-vh);
        .container {
            position: relative;
            padding-top: var(--ios-10-vh);
            padding-bottom: var(--ios-10-vh);
        }
    }
}

Answer №23

My problem was fixed by simply removing the position: fixed; or position: absolute; from my background div.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing headless WordPress and React for an innovative web development approach, incorporating styles seamlessly in both the

I am looking to create a headless WordPress + React website. So far, I have successfully set up the "non-gutenberg" elements like the header and footer. Everything seems to be working fine on that front. However, I am facing an issue with the styling of t ...

When using localStorage.getItem in Angular 4, I am encountering an issue where it returns null even though I can clearly see

I'm currently using localStorage to save my authentication token. However, I've encountered an issue where I am unable to retrieve the item after setting it in storage, even though I can see it in my browser's local storage stack. Strangel ...

Handling Pop-up Windows in Python with Selenium

# Automation Setup from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.common.exceptions import NoSuchAttributeException, NoAlertPresentException from selenium.webdriver.support.ui import WebDriverWait from seleniu ...

Struggling with pinpointing the specific element

I'm struggling to select an element within a nested <ul>. In this code snippet, my goal is to pinpoint the <a> tag that follows the parent <li> <ul class="wc-block-product-categories-list wc-block-product-categories-list--dept ...

Android: ListView only shows the most recent entries stored in an array

Hi, I have been working on a piece of code that aims to capture user input values from an EditText and store them in an array within another activity for later display. Essentially, every time a user enters values into the EditText field of Activity01, I w ...

Using the `not()` CSS selector to target specific children elements

Is there a way to add a specific attribute to all input[type=text] elements while excluding certain elements that do not have a class but their parent does? Here is an example of the HTML structure: <tr class="filters"> <td> <i ...

Learn how to cycle through three different texts that appear in the same spot using smooth transitions

I am working with three different rows that contain the Typography component. My goal is to display the first row, followed by the second, then the third, and back to the first one in a continuous loop. All three rows should be shown in the same location, ...

Display the execution duration on an HTML document

Recently, I created a loan calculator using Javascript and now I'm contemplating on incorporating the time taken for the code to execute into the results. My intention is to have the execution time displayed on my HTML page, but I am unsure of how to ...

Player script does not contain a valid function signature according to XCDYouTubeKit

I need help finding a regular expression to match these Youtube links. I'm feeling lost and unsure of what to do. https://www.youtube.com/watch?v=2BS3oePljr8 http://www.youtube.com/watch?v=iwGFalTRHDA http://www.youtube.com/watch?v=iwGFalTRHDA& ...

Angular - when removing items from ngRepeat, the remaining elements do not transition smoothly; instead, they abruptly snap or jump into position

Currently using AngularJS v1.4.8 with ngAnimate injected into my controller. In the process of creating a dynamic list using ngRepeat, tied to an array. The addition and updating of items in the list function smoothly with animations working as intended. ...

Steps for using the ModelName.objects.filter method in HTML

I'm looking to streamline the amount of code needed in my view and aiming to achieve this directly in my HTML file: {% for committee in c %} {% for article in Article.objects.filter(committee=committee) %} <a class="post-link" hre ...

Altering row heights in Bootstrap

Here's the code snippet I'm working with: <body> <div class="container-fluid h-100 border"> <div class="row h-50"> <div class="col-sm-12 bg-danger">Row1</div> </div> < ...

Comparing Base64 and NSPropertyListSerialization

I am looking for a way to encode my image into text and came across this helpful class: Base64 for iOS with ARC After experimenting, I noticed that the NSPropertyListSerialization method produces the same result as base64 encoding when converting data. Sh ...

CSS descendant selector add style excluding child elements

My issue involves two divs each containing a table. When I apply the CSS class "table" to the first div, the second table in the div is impacted as well. .tbl-generic th:nth-child(-n+2),td:nth-child(-n+2) { background-color:red; width:25px; } ...

`Is it possible to dynamically position my TableLayout and its TableRow elements in specific locations?`

I've encountered some difficulties while setting up my TableRow dynamically with TextViews in TableLayout. I have provided two images - one depicting my current situation and the other showing the mockup of the expected outcome that I am aiming for. I ...

When using the if-else statement to check the typeof value, it is returning as undefined

update Hello, I conducted a test on your code and found that it breaks for another scenario when the mobileVersion is set as sample.pdf. In this case, I am getting skyCloudmageProfilePic as pdfProfilePic without removing the typeof condition. Here is the ...

Active Menu Design in CSS

Is there a way to efficiently incorporate an active class into the CSS code for my menu? .vertical-nav{ width:200px; height:auto; list-style:none; float:left; margin-right:40px; } .vertical-nav li{ width:200px; height:25px; ...

Users are able to navigate to a non-interactive UITextField using the tab key

I've taken the necessary steps to disable user interaction in a UITextField: textField.isUserInteractionEnabled = false However, I've noticed that despite this setting, users are still able to tab into the field and input data (at least in the ...

Tips for creating and implementing a C library in an iOS application

As a newcomer to iOS programming, I am faced with the task of creating an iOS app that utilizes a C library currently used in my Android app. However, most of the resources I have found so far are focused on Objective-C, presenting me with various methods ...

Tips for avoiding the need to reload a single page application when selecting items in the navigation bar

I am in the process of creating a simple Single Page Application (SPA) which includes a carousel section, an about us section, some forms, and a team section. I have a straightforward question: How can I prevent the page from reloading when clicking on nav ...