BardiaD
BardiaD

Reputation: 119

background:cover not scaling on mobile browsers

The project I'm working on is a 1 page website that is split up into sections, the first section is the masthead with a background image applied to it. My goal is to make this image responsive on resize, so I set the background-size property to cover

When scaling the viewport on a desktop browser, the image scales accordingly. However on mobile clients (tested on iOS 7 and Andriod Froyo/Kitkat) the image seems to stay at it's full width/height, becoming very pixelated and distorted.

example: http://www.bardiadoust.ca

At first I thought the problem was with the -500% margin and 500% padding I had on the left/right of each section (I'm using this to create full width sections while keeping the content inside my grid). I took out this code and was still getting the same result. If anyone has any clues as to what I'm doing wrong, that'd be great.

Update

I've been doing more investigating and thought that this might be an iOS issue due to image size limits (Read More Here) and swapped out my rather large 1.2mb image with a 500k gif. The problem however, persists.

Update 2

Haven't found a full solution yet, but I have found a fix I'm happy with.

In my global styles I have these background properties set on .masthead section:

background: $tangerine;

background:
  linear-gradient(
    rgba(232,85,4, .84),
    rgba(232,85,4, .84)
),

url("../images/pano2.png") no-repeat center center;
   -webkit-background-attachment: fixed;
   -moz-background-attachment: fixed;
   -o-background-attachment: fixed;
   -ms-backgroudn-attachment: fixed;
   background-attachment: fixed;

   -webkit-background-size: cover;
   -moz-background-size: cover;
   -o-background-size: cover;
   background-size: cover;

On my first media query break point I apply these styles to .masthead:

@media only screen and (max-width: 959px){
    -webkit-background-attachment: scroll;
    -moz-background-attachment: scroll;
    -o-background-attachment: scroll;
    -ms-backgroudn-attachment: scroll;
    background-attachment: scroll;
    -webkit-background-size: contain;
    -moz-background-size: contain;
    -o-background-size: contain;
    background-size: contain;
}

contain seems to give me the result on mobile that I'm looking for, but only if the background-attachment property is not set to fixed. This wasn't too big of a trade off for me since fixed backgrounds don't really work properly on mobile devices anyway.

Upvotes: 2

Views: 3309

Answers (2)

BardiaD
BardiaD

Reputation: 119

I have finally found a solution to this problem, and I'm posting it here in hopes that it'll help someone else.

While I originally thought my problem was that background-size was not scaling properly, it seems the issue was more related to background-attachment: fixed Having both of these properties caused the background to scale poorly, and also would not fix the image in place while the user scrolls (Kind of a lose/lose situation).

There are some legitimate draw backs to this method. I first learned about it on the Four Kitchens blog, and credit goes to Chris Ruppel for explaining this technique. (Original Article)

Why it doesn't work

Chris goes into a lot more detail about why position: fixed doesn't work on background elements in mobile browsers has to do with the amount of repaints the browser would need to do and how that negatively affects performance. Because of this, the background-attachment property doesn't work as expected on mobile browsers.

Solution

The basic idea behind this technique is to set the background image as you normally would, but instead of setting the attachment property to fixed, you add position:fixed to the div itself, effectively fixing it to the top/left of the body element.

Essentially combining this with the will-change property creates a new paint layer for mobile devices to draw the background (essentially does the same thing as translateZ(0)), without chugging/jumping (the result you often get when trying to do this with Javascript). Please read the linked article for more info on this technique.

HTML:

<section class="masthead">
   ...
</section>

CSS:

.masthead {
   overflow: hidden; // added for pseudo-element
   position: relative; // added for pseudo-element

// Fixed-position background image
   &::before {
      content: ' ';
      position: fixed; // instead of background-attachment
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
      background: url('/img/front/strategy.jpg') no-repeat center center;
      background-size: cover;
      will-change: transform; // creates a new paint layer
      z-index: -1; //ensures image is behind everything else
   }
}

I should mention that while Chris has set overflow and position properties on the parent element, from my research they have no effect. Relative positioning does not apply to fixed elements, and neither does overflow.

Drawbacks

This technique works correctly on my testing, but there are a few reasons why you may not want to use it:

  • No overflow control: Because this div is fixed relative to the viewport, overflow:hidden has no effect. That means you can't "clip" the image to fit inside its container div, it will always fill the entire background. This usually won't be a problem in practice, as any other content under <section class="masthead"> will be on top of the image (effectively hiding it under the rest of the content). However if for some reason you do need to cut/crop your background image as to not take up the entire background, you could try using the clip property. See the second answer to this question

  • Visible on scroll (Safari): This is purely an aesthetic thing, but because of the "bouncy" scrolling in Safari, if you scroll past the top or bottom of a page, the background will peep through. This doesn't happen in Chrome, just Safari.

  • One image per page: Someone else might have figured this out, but because the div this background image is attached to is fixed relative to the viewport (at x:0, y:0), I can't find a way to add multiple fixed images as part of 1 page. The issue being that it will simply stack on top of (or behind depending on it's z-index) the previous image. Setting its top value to a hard coded pixel/rem/em value will move it down, but there is no way to know exactly how far it needs to move down to line up with its assosicated content (especially on a responsive site, where content height is never fixed).

  • Kind of hacky: While this totally works, and I'm even using it on a current project I'm working on. It does feel hacky. background-attachment: fixed feels like it should be the best solution to this, if it worked.

Upvotes: 2

zchgdn
zchgdn

Reputation: 11

Have you set up so that your CSS selectors call for each browser? Some of the newer CSS3 attributes and selectors require prefixes in order to work cross-browser:

-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
-ms-filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/post_bg.jpg',    sizingMethod='scale')";

If that doesn't do the trick, I think you might be able to fix it by using background-size contain; in the viewports for smaller screen sizes.

Upvotes: 1

Related Questions