191

I'm currently developing a responsive site using Twitter Bootstrap.

The site has a full screen background image across mobile/tablet/desktop. These images rotate and fade through each, using two divs.

It's nearly perfect, except one issue. Using iOS Safari, Android Browser or Chrome on Android the background jumps slightly when a user scrolls down the page and causes the address bar to hide.

The site is here: http://lt2.daveclarke.me/

Visit it on a mobile device and scroll down and you should see the image resize/move.

The code I'm using for the background DIV is as follows:

#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;
}

All suggestions welcome - this has been doing my head in for a while!!

Dave Clarke
  • 2,677
  • 4
  • 22
  • 35

23 Answers23

115

This issue is caused by the URL bars shrinking/sliding out of the way and changing the size of the #bg1 and #bg2 divs since they are 100% height and "fixed". Since the background image is set to "cover" it will adjust the image size/position as the containing area is larger.

Based on the responsive nature of the site, the background must scale. I entertain two possible solutions:

1) Set the #bg1, #bg2 height to 100vh. In theory, this an elegant solution. However, iOS has a vh bug (http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/). I attempted using a max-height to prevent the issue, but it remained.

2) The viewport size, when determined by Javascript, is not affected by the URL bar. Therefore, Javascript can be used to set a static height on the #bg1 and #bg2 based on the viewport size. This is not the best solution as it isn't pure CSS and there is a slight image jump on page load. However, it is the only viable solution I see considering iOS's "vh" bugs (which do not appear to be fixed in iOS 7).

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

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

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

On a side note, I've seen so many issues with these resizing URL bars in iOS and Android. I understand the purpose, but they really need to think through the strange functionality and havoc they bring to websites. The latest change, is you can no longer "hide" the URL bar on page load on iOS or Chrome using scroll tricks.

EDIT: While the above script works perfectly for keeping the background from resizing, it causes a noticeable gap when users scroll down. This is because it is keeping the background sized to 100% of the screen height minus the URL bar. If we add 60px to the height, as swiss suggests, this problem goes away. It does mean we don't get to see the bottom 60px of the background image when the URL bar is present, but it prevents users from ever seeing a gap.

function resizeBackground() {
    bg.height( $(window).height() + 60);
}
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
Jason
  • 4,079
  • 4
  • 22
  • 32
  • Thanks for this. I'll give it a whirl tomorrow and let you know how I get on :) – Dave Clarke Jul 31 '14 at 01:12
  • 5
    This is wonderful. I've implemented your second solution, which worked nearly perfectly with just a few pixel gap between the footer & the background image. I changed your 4th line of code to: `bg.height(jQuery(window).height() + 60);` which works beautifully across all my devices! Thanks :) – Dave Clarke Aug 05 '14 at 13:02
  • Got this working, but like swiss I had to add the + 60. Without that, there is a visible 60px gap at the bottom of the page. – Kelderic Aug 29 '14 at 16:11
  • 8
    the iOS vh bug is fixed in iOS8 but the problem on Android isn't. I'm using `vh`units and of course `100vh` is bigger when the address bar is hidden. It's stupid that this jump occurs after the scrolling stops. It just looks buggy. I ended up using transition on the height to make it seem intentional. – ProblemsOfSumit Oct 28 '14 at 11:41
  • 1
    I was able to solve this problem by moving the background from the `body` to a wrapper `
    ` wrapping the entire page's content. No jumping backgrounds on iOS or Android!
    – Marius Schulz Nov 12 '14 at 10:35
  • This works on load for me but doesn't resize when I landscape my (Samsung S6) phone – RJB Nov 19 '15 at 05:51
  • 2
    The JS solution is not working for me (Android). Confirmed that the script is setting the height, but the issue persists. – jwinn May 02 '16 at 18:48
  • So JavaScript is returning the viewport size with visible browser bar? – Andy Jun 07 '16 at 13:21
  • I had to remove the quotes in the line `jQuery(window).resize("resizeBackground");` to `jQuery(window).resize(resizeBackground);`, otherwise I would have dozens of uncaught type errors in the console. However, the JS solution did nothing overall to improve my situation on Android, and on iPhone the 100vh seems to be sufficient. – Alexander Rechsteiner Oct 17 '16 at 12:10
  • The JS solution work for Android and Chrome but doesn't work on samsung browser or IOS 10.2 with safari and chrome. Arggggggggg!! Why??? – YoBre Feb 16 '17 at 10:50
  • A nice trick that I added, is setting a css-variable using JavaScript which contains the window height. And in css instead of using 100vh is use the css-variable which contains the correct height. Of course with the 100vh fallback above it for non supporting browsers(which are mostly desktop only and don't have the issue to begin with). You can also use the variable inside `calc` if you need less than 100vh. – René Dec 13 '17 at 17:32
  • The JavaScript solution doesn't seem to work for me on Android. – Simon-Teodor Mărăcine Mar 25 '22 at 07:57
62

I found that Jason's answer wasn't quite working for me and I was still getting a jump. The Javascript ensured there was no gap at the top of the page but the background was still jumping whenever the address bar disappeared/reappeared. So as well as the Javascript fix, I applied transition: height 999999s to the div. This creates a transition with a duration so long that it virtually freezes the element.

AlexKempton
  • 1,648
  • 15
  • 28
  • 26
    You sir deserve +1 for the real out-of-the box thinking. Unfortunately this prevents adjusting the div size to any screen size changes, including for examples those caused by screen rotation. – tobik Feb 15 '15 at 21:07
  • 1
    +1 for creativity! May have to use this for now as the issue compounds if you use `vw` or `vh` to set the font size inside of that parent container. – robabby Feb 28 '15 at 19:40
  • 6
    @tobik It is still possible to reduce the jump caused by viewport change by setting a 0.5 second or so transition – binaryfunt May 01 '15 at 09:45
  • 8
    try to rotate the phone now – prompteus Jun 29 '16 at 19:06
  • 1
    @tobik this actually makes it more a feature than a bug ;) good thinking – dimitrieh Jul 06 '16 at 15:53
26

I've got a similar issue on a header of our website.

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

This will end up in a jumpy scrolling experience on android chrome, because the .header-container will rescale after the url-bar hides and the finger is removed from screen.

CSS-Solution:

Adding the following two lines, will prevent that the url-bar hides and vertical scrolling is still possible:

html {
    overflow: hidden;
}
body {
    overflow-y: scroll;
    -webkit-overflow-scrolling:touch;
}
mat
  • 1,367
  • 1
  • 13
  • 18
  • 4
    Yeah this does solve it like you say, but it sucks that the nav bar is always showing. On some phones this can take up a chunk of valuable screen space! – Dave Clarke Nov 09 '15 at 16:43
  • 1
    That's true, to prevent this, you can additionally use a JavaScript-Workaround. But this example works without JS at all. – mat Nov 09 '15 at 20:00
  • 5
    Scroll is disabled completely when I tried this solution. – Nithin Baby Aug 01 '16 at 12:48
  • 1
    Thanks, that worked great for my situation! Should be mentioned for anyone else that might miss it that the html and body tags have to be set to 100% height for this to work (I initially just skimmed your answer at first and jumped to the first mention of "solution"). – gburning Oct 10 '16 at 07:52
  • -webkit-overflow-scrolling should not be used on production sites. https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-overflow-scrolling – Fredrik Westerlund Dec 12 '16 at 21:36
  • @FredrikWesterlund Safari disagrees as p. 2019 – Rick Stanley Jun 13 '19 at 15:52
17

The problem can be solved with a media query and some math. Here's a solution for a portait 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%);
}

Since vh will change when the url bar dissapears, you need to determine the height another way. Thankfully, the width of the viewport is constant and mobile devices only come in a few different aspect ratios; if you can determine the width and the aspect ratio, a little math will give you the viewport height exactly as vh should work. Here's the process

1) Create a series of media queries for aspect ratios you want to target.

  • use device-aspect-ratio instead of aspect-ratio because the latter will resize when the url bar dissapears

  • I added 'max' to the device-aspect-ratio to target any aspect ratios that happen to follow in between the most popular. THey won't be as precise, but they will be only for a minority of users and will still be pretty close to the proper vh.

  • remember the media query using horizontal/vertical , so for portait you'll need to flip the numbers

2) for each media query multiply whatever percentage of vertical height you want the element to be in vw by the reverse of the aspect ratio.

  • Since you know the width and the ratio of width to height, you just multiply the % you want (100% in your case) by the ratio of height/width.

3) You have to determine the url bar height, and then minus that from the height. I haven't found exact measurements, but I use 9% for mobile devices in landscape and that seems to work fairly well.

This isn't a very elegant solution, but the other options aren't very good either, considering they are:

  • Having your website seem buggy to the user,

  • having improperly sized elements, or

  • Using javascript for some basic styling,

The drawback is some devices may have different url bar heights or aspect ratios than the most popular. However, using this method if only a small number of devices suffer the addition/subtraction of a few pixels, that seems much better to me than everyone having a website resize when swiping.

To make it easier, I also created a SASS mixin:

@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%);
  }
}
Jordan Los
  • 179
  • 1
  • 2
12

All of the answers here are using window height, which is affected by the URL bar. Has everyone forgotten about screen height?

Here's my jQuery solution:

$(function(){

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

  // Fix background image jump on mobile
  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);
  }
});

Adding the .css() part is changing the inevitably top-aligned absolute positioned element to bottom aligned, so there is no jump at all. Although, I suppose there's no reason not to just add that directly to the normal CSS.

We need the user agent sniffer because screen height on desktops would not be helpful.

Also, this is all assuming #background is a fixed-position element filling the window.

For the JavaScript purists (warning--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;
}

EDIT: Sorry that this does not directly answer your specific problem with more than one background. But this is one of the first results when searching for this problem of fixed backgrounds jumping on mobile.

cr0ybot
  • 3,960
  • 2
  • 20
  • 22
  • 3
    I tried a million of these answers and this is by far the best. I originally was trying to use this on just as that had the background. Using a div to wrap the whole page caused other issues. Using an empty div with z-index: -1 as the background seemed to be the best solution combined with the above. I took out the mobile detection since doing this on the desktop doesn't hurt for my site. No math (which can guess the size of the tabs wrong), no handler needed for resize. Background is just the whole screen, anchored to the bottom. Done. Love it! – Evan Langlois Jan 22 '17 at 12:22
  • This solution seems to lock the browser navbar in place on latest Chrome today. – Tom Jun 06 '21 at 05:09
8

The solution I'm currently using is to check the userAgent on $(document).ready to see if it's one of the offending browsers. If it is, follow these steps:

  1. Set the relevant heights to the current viewport height rather than '100%'
  2. Store the current viewport horizontal value
  3. Then, on $(window).resize, only update the relevant height values if the new horizontal viewport dimension is different from it's initial value
  4. Store the new horizontal & vertical values

Optionally, you could also test permitting vertical resizes only when they are beyond the height of the address bar(s).

Oh, and the address bar does affect $(window).height. See: Mobile Webkit browser (chrome) address bar changes $(window).height(); making background-size:cover rescale every time JS "Window" width-height vs "screen" width-height?

Community
  • 1
  • 1
m-p
  • 326
  • 2
  • 7
  • I haven't tried this but would your first point not work for iOS? (http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/) – Dave Clarke Aug 05 '14 at 15:50
  • I was fixing he value in the first step, but I'm surprised that you found Jason's response to solve the problem. As noted I found, along with the other user in the earlier question I linked, that the $(window).height() method value DOES change when the address bar in chrome on android is or is not visible. I threw together this little site that just reveals the $(window).height() result in an alert, and it definitely provides different values on my nexus 4 in chrome when the address bar is/is not visible: http://stormy-meadow-5908.herokuapp.com/ – m-p Aug 05 '14 at 20:44
  • This 100% fixes the issue on my Android device although I'm seeing a similar issue on my iPad which this doesn't appear to fix which I'm still looking into. – Dave Clarke Aug 05 '14 at 22:30
  • Are you able to provide some code for your solution and I'll try it out? – Dave Clarke Aug 05 '14 at 22:34
8

I ran into this issue as well when I was trying to create an entrance screen that would cover the whole viewport. Unfortunately, the accepted answer no longer works.

1) Elements with the height set to 100vh get resized every time the viewport size changes, including those cases when it is caused by (dis)appearing URL bar.

2) $(window).height() returns values also affected by the size of the URL bar.

One solution is to "freeze" the element using transition: height 999999s as suggested in the answer by AlexKempton. The disadvantage is that this effectively disables adaptation to all viewport size changes, including those caused by screen rotation.

So my solution is to manage viewport changes manually using JavaScript. That enables me to ignore the small changes that are likely to be caused by the URL bar and react only on the big ones.

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

    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 actually use this technique together with height: 100vh. The page is rendered properly from the very beginning and then the javascript kicks in and starts managing the height manually. This way there is no flickering at all while the page is loading (or even afterwards).

simmer
  • 2,639
  • 1
  • 18
  • 22
tobik
  • 7,098
  • 7
  • 41
  • 53
  • 1
    I've used something similar, but rather than setting `height: 100vh` in the initial CSS, I set `min-height:100vh` and then on window resize I calculate the `min-height` and set it to the view-port height. This is handy when your site is viewed on tiny screens and the content is too large to fit on the viewport. A debounce/throttle setTimeout on the resize event helps improve performance on some browsers (resize tends to fire very often) – Troy Morehouse Apr 07 '15 at 13:32
  • I think that at a certain point I also tried using `min-height` instead but then I run into a problem when I needed to vertically center the inner content. Somehow vertical centering can get tricky when the outer element has `height` set to `auto`. So I came up with a fixed minimum height that should be enough to contain any kind of possible content and set it in the initial CSS. Since `min-height` has a higher priority than `height`, it works pretty well. – tobik Apr 07 '15 at 13:51
  • Ah yeah, I had that same problem, but fixed it by changing the jumbotron to `display: table` and then setting the internal container to `display: table-cell` with `vertical-align: middle`. Worked like a charm. – Troy Morehouse Apr 08 '15 at 14:39
  • Really? Because I tried the same approach but I failed. I don't really remember what the problem was but this might be relevant: http://stackoverflow.com/questions/7790222/css-display-table-min-height-not-working – tobik Apr 08 '15 at 15:03
  • Just make sure you avoid percentage padding or margins. Caused a few weird rendering issues on IE8, although modern browsers were OK. – Troy Morehouse Apr 09 '15 at 23:39
  • Firefox for Android has a 103 pixel height change when it hide's it's browser chrome on a tablet. I'd bump up the tolerance to at least that. – Brenton Oct 13 '15 at 16:37
  • Holy crap, this works! I'm going to see if I can add mobile detection (namely android and iOS) because that seems to be where the errors are occurring. –  Jan 20 '17 at 14:06
4

I found a really easy solution without the use of Javascript:

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

All this does is delay the movement so that it's incredibly slow that it's not noticeable.

Pav Sidhu
  • 6,724
  • 18
  • 55
  • 110
  • @Tyguy7 It works fine whenever your height is not set to a fixed value, i.e. `100%`, `100vh`. IE8 is the only major browser which doesn't support transitions. – Pav Sidhu Aug 02 '16 at 17:37
  • Great and simple solution! – zdarsky.peter Dec 16 '16 at 20:54
  • 3
    This works great until you're on a device where you can change from portrait to landscape. When this happens the design is ruined. – Nagy Nick Jan 10 '17 at 11:53
  • @NagyNick that wasn't such a big issue for me. You could detect the orientation change in Javascript and adjust the background image. – Pav Sidhu Jan 10 '17 at 16:12
3

My solution involved a bit of javascript. Keep the 100% or 100vh on the div (this will avoid the div not appearing on initial page load). Then when the page loads, grab the window height and apply it to the element in question. Avoids the jump because now you have a static height on your div.

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

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

I created a vanilla javascript solution to using VH units. Using VH pretty much anywhere is effected by address bars minimizing on scroll. To fix the jank that shows when the page redraws, I've got this js here that will grab all your elements using VH units (if you give them the class .vh-fix), and give them inlined pixel heights. Essentially freezing them at the height we want. You could do this on rotation or on viewport size change to stay responsive.

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 has solved all my use cases, hope it helps.

Geek Devigner
  • 349
  • 2
  • 12
3

this is my solution to resolve this issue, i have added comments directly on code. I've tested this solution and works fine. Hope we will be useful for everyone has the same problem.

//remove height property from file css because we will set it to first run of page
//insert this snippet in a script after declarations of your scripts in your index

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

setHeight(); // at first run of webpage we set css height with a fixed value

if(typeof window.orientation !== 'undefined') { // this is more smart to detect mobile devices because desktop doesn't support this property
  var query = window.matchMedia("(orientation:landscape)"); //this is is important to verify if we put 
  var changeHeight = function(query) {                      //mobile device in landscape mode
    if (query.matches) {                                    // if yes we set again height to occupy 100%
      setHeight(); // landscape mode
    } else {                                                //if we go back to portrait we set again
      setHeight(); // portrait mode
    }
  }
  query.addListener(changeHeight);                          //add a listner too this event
} 
else { //desktop mode                                       //this last part is only for non mobile
  $( window ).resize(function() {                           // so in this case we use resize to have
    setHeight();                                            // responsivity resisizing browser window
  }); 
};
lino
  • 190
  • 5
  • 1
    You are calling setHeight() inside of changeHeight Method if the query matches and also if it does not match. So just remove the if statement as it is not necessary. – Dennis Meissner Apr 21 '16 at 13:12
2

This is the best solution (simplest) above everything I have tried.

...And this does not keep the native experience of the address bar!

You could set the height with CSS to 100% for example, and then set the height to 0.9 * of the window height in px with javascript, when the document is loaded.

For example with jQuery:

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

)

Unfortunately there isn't anything that works with pure CSS :P but also be minfull that vh and vw are buggy on iPhones - use percentages.

1

I set my width element, with javascript. After I set the de vh.

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 works for me. I don't use jquery ect. because I want it to load as soon as posible.

Johan Hoeksma
  • 3,534
  • 5
  • 28
  • 40
1

It took a few hours to understand all the details of this problem and figure out the best implementation. It turns out as of April 2016 only iOS Chrome has this problem. I tried on Android Chrome and iOS Safari-- both were fine without this fix. So the fix for iOS Chrome I'm using is:

$(document).ready(function() {
   var screenHeight = $(window).height();
   $('div-with-background-image').css('height', screenHeight + 'px');
});
littlequest
  • 329
  • 2
  • 7
1

Similar to @AlexKempton answer. (couldn't comment sorry)

I've been using long transition delays to prevent the element resizing.

eg:

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

The tradeoff with this is it prevents resizing of the element including on device rotating, however, you could use some JS to detect orientationchange and reset the height if this was an issue.

Devraj Gadhavi
  • 3,541
  • 3
  • 38
  • 67
1

Simple answer if your background allows, why not set background-size: to something just covering device width with media queries and use alongside the :after position: fixed; hack here.

IE: background-size: 901px; for any screens <900px? Not perfect or responsive but worked a charm for me on mobile <480px as i'm using an abstract BG.

EasterMedia
  • 53
  • 1
  • 12
1

My answer is for everyone who comes here (like I did) to find an answer for a bug caused by the hiding address bare / browser interface.

The hiding address bar causes the resize-event to trigger. But different than other resize-events, like switching to landscape mode, this doesn't change the width of the window. So my solution is to hook into the resize event and check if the width is 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
    // ...
});
Erik Joling
  • 126
  • 4
  • 8
0

I am using this workaround: Fix bg1's height on page load by:

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

Then attach a resize event listener to Window which does this: if difference in height after resizing is less than 60px (anything more than url bar height) then do nothing and if it is greater than 60px then set bg1's height again to its parent's height! complete code:

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;
    }
}

PS: This bug is so irritating!

0

For those who would like to listen to the actual inner height and vertical scroll of the window while the Chrome mobile browser is transition the URL bar from shown to hidden and vice versa, the only solution that I found is to set an interval function, and measure the discrepancy of the window.innerHeight with its previous value.

This introduces this code:

var innerHeight = window.innerHeight;
window.setInterval(function ()
{
  var newInnerHeight = window.innerHeight;
  if (newInnerHeight !== innerHeight)
  {
    var newScrollY = window.scrollY + newInnerHeight - innerHeight;
    // ... do whatever you want with this new scrollY
    innerHeight = newInnerHeight;
  }
}, 1000 / 60);

I hope that this will be handy. Does anyone knows a better solution?

Édouard Mercier
  • 485
  • 5
  • 12
0

The solution I came up with when having similar problem was to set height of element to window.innerHeight every time touchmove event was fired.

var lastHeight = '';

$(window).on('resize', function () {
    // remove height when normal resize event is fired and content redrawn
    if (lastHeight) {
        $('#bg1').height(lastHeight = '');
    }
}).on('touchmove', function () {
    // when window height changes adjust height of the div
    if (lastHeight != window.innerHeight) {
        $('#bg1').height(lastHeight = window.innerHeight);
    }
});

This makes the element span exactly 100% of the available screen at all times, no more and no less. Even during address bar hiding or showing.

Nevertheless it's a pity that we have to come up with that kind of patches, where simple position: fixed should work.

Paul
  • 3,186
  • 1
  • 19
  • 22
0

With the support of CSS custom properties (variables) in iOS, you can set these with JS and use them on iOS only.

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);
        }
    }
}
Stephen Saucier
  • 1,925
  • 17
  • 20
0

Removing position: fixed; or position: absolute;, if you have any of them in your background div, solved the issue for me.

Kiri
  • 11
  • 3
  • This does not really answer the question. If you have a different question, you can ask it by clicking [Ask Question](https://stackoverflow.com/questions/ask). To get notified when this question gets new answers, you can [follow this question](https://meta.stackexchange.com/q/345661). Once you have enough [reputation](https://stackoverflow.com/help/whats-reputation), you can also [add a bounty](https://stackoverflow.com/help/privileges/set-bounties) to draw more attention to this question. - [From Review](/review/late-answers/32838766) – Arusekk Oct 06 '22 at 13:42
0

I got the code from @cr0ybot and added a few changes in the background size and position to make it work for me.

$(function(){
      var $w = $(window),
            $background = $('.slideshow-fullscreen');
      
      // Fix background image jump on mobile
      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'});
      }
});

RFerreira
  • 58
  • 9