Prevent fixed-position background-image: cover from resizing in mobile browsers upon address bar hide

25,008

Solution 1

Almost 5 years later, there is finally a fix for this, due to changes in how Safari and now Chrome for Android calculate vh units. Check it out! https://developers.google.com/web/updates/2016/12/url-bar-resizing

I implemented it on this website (can't really show this off on any of the code playgrounds due to them always embedding results in iframes): https://www.cochranesupply.com

Just used the following code on a background element:

#background {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    background-image: url(../images/background.jpg);
    background-size: cover;
    z-index: -1;
}

And that's all there is to it! Just need Chrome for Android 56, or Safari for iOS (not certain which version but this may have been in Safari for a long time now).

Solution 2

I ended up creating a workaround for mobile. It may not degrade gracefully, but it's working well for the time being.

window.mobilecheck = function() {
  var check = false;
  (function(a){if(/(android|bb\d+|meego).+mobile|android|ipad|playbook|silk|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
 }

 if (window.mobilecheck() == true) {
  var newHeight = $(window).height() + 70;
  $("#background").css("height", newHeight);
 }

I found that mobilecheck function on the internet ( http://detectmobilebrowsers.com/ ). If it returns true, I take my fixed background image container and add 70 to its height. Then when you drag the screen up and the web browser's address bar auto-hides (thus increasing the window height), it has enough extra height such that background-size: cover does not have to jarringly resize the background image to fit the screen again.

I could have just put the entire page into a fixed container and prevented mobile address bars from ever hiding, but I don't like sidestepping an otherwise neat feature of mobile browsers, and I know iOS isn't exactly thrilled with fixed containers that have their own scrollbars (there are workarounds of course, but I'd prefer my content to be in a more standard container).

EDIT: However, this workaround introduces this issue: CSS CHALLANGE: Background-Image with 100% height - White Space when Scrolling Mobile

Solution 3

For those still looking around for an answer, you can use the new vw and vh attributes with an element that is position: fixed.

This scrolls while the address bar moves/shrinks/etc., then remains fixed on the page.

#bgimg {
  display: block;
  background: no-repeat url(bg.png);
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 120vh;
}

Solution 4

For mobile safari you must, unintuitively, attach fixed backgrounds to the html element like so.

html {
    background: url(../img/bg.jpg) no-repeat center center fixed;
    background-size: cover;
    height: 100%;
    overflow: hidden;
}

Then set the scrolling to the body.

body {
    height: 100%;
    overflow: scroll;
}

You'll still need the background div for IE 8 since it doesn't support the background-size property, so mobile browsers should hide it. The cleanest way to do this is to exploit IE 8's inability to read a media query

@media only screen { #background { display: none; }}
Share:
25,008

Related videos on Youtube

addMitt
Author by

addMitt

Updated on July 09, 2022

Comments

  • addMitt
    addMitt almost 2 years

    Sorry for a lack of example on this one, but I figure it's easy enough to understand.

    I have a fixed background on my site, which is currently implemented like this:

    #background {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background-color: #28305e;
        background-image: url(../images/background.jpg);
        background-size: cover;
        -moz-background-size: cover;
        background-position: center center;
        z-index: -10;
    }
    
    <div id="background"></div>
    

    This is great in all browsers so far except for mobile browsers where they hide the address bar upon scroll-down. When the address bar is hidden, the viewport expands vertically, and the background-image jarringly resizes itself. On this particular site it will be common for users to scroll up and down, and the effect is distracting.

    Any ideas or strategies on working around this or implementing the background in a different way?

    I could wrap the entire thing in a fixed container, and set the overflow-y to scroll, which prevents the address bar from ever being hidden, but I'd prefer not to do this (Google Glass can't scroll through those containers, haha... Would like to demo on there as well).

    I've been trying to think of something that provides background-image: cover functionality with some sort of buffer, so that it renders larger than the viewport, and won't re-render unless the viewport is expanded beyond that buffer, but I'm not sure how to implement that.

    EDIT: I actually did implement this and detailed the process in an answer below. However, even with this buffer setup (which extends the height of the background image to be 60+ pixels larger than the viewport height), upon the address bar hiding, it still shows a blank background-color segment that gets revealed, and once you stop scrolling, it renders the rest of the background image.

    Still looking for a way to keep the native address bar hide functionality (which has now been expanded to iOS Safari on iPad in iOS 8), and also have a fullscreen background image that always fully renders even if the viewport changes height when hiding the address bar. Starting to wonder if I should just be filing bug reports for all the browsers...

    • addMitt
      addMitt almost 10 years
      And this has just become an even larger issue, as Safari on iOS 8 for iPad, now does the same thing: shrinks the browser header upon scrolling down.
    • Ashish Ranjan
      Ashish Ranjan over 7 years
      hey @addMitt, none of the solution seems to work perfectly. have you found any fix for the issue?
    • addMitt
      addMitt over 7 years
      I have not, and recent tests show the same issues are still occurring. I have stopped developing mobile pages with fullscreen background images. The only way this will ever work normally is if we are allowed to make fixed containers larger than the viewport height, and when you scroll down and hide the address bar, the browser properly renders the remainder of the background image, instead of showing it as completely white until you stop scrolling. This will need to be fixed in browsers however.
  • addMitt
    addMitt about 10 years
    It's more about how the background-size: cover works, where it takes and image and makes it fit while keeping image aspect ratio. So, if you have a portrait viewport, it will center the image, enlarge it until it fits the vertical resolution, and allow the horizontal edges of the picture to be cropped. I like this functionality, but due to the previously described behavior, it resizes every time a mobile browser increases the viewport size and hides its address bar.
  • xno
    xno about 10 years
    It is still possible to add a div container to hold and scroll your content as I explained above so that the scrolling isn't happening within your background div- therefore not resizing your image. I didn't suggest that you change anything with your background-size:cover. Just add the scrolling to a div that sits on top of your background div so it doesn't interfere when the scroll bar appears. Also, I believe your edit contains an unrelated question to your original that you should ask separately in order to get an accurate answer.
  • Gutblender
    Gutblender over 9 years
    Welcome to Stack Overflow! Looks like a good answer! Nice. However your last sentence looks like a question. Do you mean to say the user cannot get the A.B. (I'm assuming Address Bar) back? If you are not sure, it would be better to say something like "However I'm not sure you could get it back if you could make it disappear."
  • Mike Arledge
    Mike Arledge over 9 years
    Thanks Glut. Yes it is a question. If you make the A.B. (address bar) dissappear what would one do to get the A.B. to reappear. Hope that helps. The most important point ibwant to get across is the Address Bar will not hide at all with this technique.
  • addMitt
    addMitt over 9 years
    This is why I have been hesitant to accept any answers. The only workaround really is to prevent it from hiding at all. Ideally, there would be a solution that allows for auto-hide, and also for the newly exposed section of the background-image (which is set to "cover"), to render properly, and not as an empty blank space that is later filled in upon ceasing scrolling.
  • 2540625
    2540625 over 9 years
    This doesn't stop the BG image from resizing upon show/hide of the url-bar. It stops the show/hide of the url-bar. It also kills inertial scrolling.
  • addMitt
    addMitt almost 9 years
    Unfortunately this still does not get past the problems outlined here when using background-size cover: stackoverflow.com/questions/23776999/… When it scrolls it reveals an empty background-colored space, which is then filled in once you stop scrolling (at least on iOS Safari).
  • tjklemz
    tjklemz almost 9 years
    Ok. Good to know... In Android's Chrome this works great. I'll have to test on iOS. Thanks.
  • addMitt
    addMitt almost 9 years
    I can confirm that it reveals itself without showing the background color in Android's Chrome as well (now... it didn't do that months ago, haha). However, whenever it resizes the viewport height due to the hiding of the address bar, the background-size: cover triggers again, and stretches itself to be 120vh of the current viewport height. This means every time you scroll up/down the background image jarringly resizes itself (back to the original problem! @_@ )
  • tjklemz
    tjklemz almost 9 years
    It works perfectly for me on the latest Android Chrome which is on Lollipop. It wouldn't surprise me if this didn't work on KitKat. :P
  • addMitt
    addMitt almost 9 years
    I'm using a Nexus 5 with Lollipop and the latest Chrome as well. Are you using background-size: cover? Your answer doesn't include it in the CSS.
  • Sarpe
    Sarpe about 4 years
    This works great on Chrome for Android, so thank you! Unfortunately the problem persists on the latest Firefox for Android. Any advice to fix it on Firefox as well?
  • scravy
    scravy almost 4 years
    As of July 2020 this does work on Chrome in Android, Safari in iOS, and I assume all webkit/blink based browsers (Edge, Opera, ...). It does not work however in Firefox.
  • Alex Rummel
    Alex Rummel almost 4 years
    This is a good solution if you have only a single fixed background, but if you're attempting a parallax effect with multiple fixed backgrounds (much like this example) then you're probably straight out of luck.
  • D Joyce
    D Joyce almost 4 years
    Firefox on Android have recently rolled out a new feature that allows the user to have the address bar at the bottom. So far it looks like it helps the situation.