46

I have a project that I am using the fixed background image. It works great on everything except ios7. On the ipad the background image is zoomed in and blurry. Here is the CSS code I am using -

.header {
  display: table;
  height: 100%;
  width: 100%;
  position: relative;
  color: #fff;
  background: url(../images/boston2.jpg) no-repeat center center fixed; 
  -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
  }

here is a link to the live page - www.wdeanmedical.com

What am I missing?

Saranjith
  • 9,547
  • 2
  • 55
  • 102
user2560895
  • 1,401
  • 3
  • 13
  • 11

11 Answers11

50

Using background-attachment: fixed with background-size: cover causes issues on most mobile browsers (as you've seen). You can try using background-attachment: scroll. This won't give your desired effect, but you'll see the images at least. You could use a media-query or two to limit it to devices that are tablets or phones by using @media screen and (max-device-width: 1024px){}

OR

You can use background-position: scroll and include some javascript that will keep the image at the scrolled position (keeping it at the top of the window): DEMO

brouxhaha
  • 3,693
  • 1
  • 17
  • 22
  • 4
    But if you have parallax happening, *not* using 'fixed' will break the parallax. A question marked as a 'duplicate' of this one has much more info and references to workarounds. See here: http://stackoverflow.com/questions/23236158/how-to-replicate-background-attachment-fixed-on-ios – JosephK Feb 18 '15 at 03:24
  • Say I had several horizontal sections on my page and I wanted to use this effect in the bottom div, how can I make this work? This code only works if the image is on the top of the page. – ObedMarsh Jan 20 '16 at 01:57
  • You probably need to either ask a new question or provide more detail because I have no idea what you're trying to do. – brouxhaha Jan 20 '16 at 19:10
14

Know this is an old thread, but wanted to provide an updated solution that builds on the solution from @Cruz-Nunez

Relying on viewport size is liable to fail. For example, relying on a 767px viewport won't work on iPads, and increasing the size negates the benefit of this approach.

Instead, you can check if the device has hover capabilities, and if it doesn't, override like this:

@media (hover: none) {
   .homeHero {
       background-attachment: initial;
   }
}

You can also check if the device has a coarse pointer (e.g. a finger) instead of a fine one (e.g. a mouse):

@media (pointer: coarse) { ... }
Gianfranco P.
  • 6,858
  • 3
  • 40
  • 56
Tim
  • 986
  • 6
  • 23
11

I had a very simple solution for this, after struggling with all the methods of fixing this.

i had the problem on my mobile IOS devices.

css (desktop)

#ci-hero-11 .widget-wrap , #ci-hero-12 .widget-wrap {
background-size: auto;
background-attachment: fixed;
}

.widget-wrap {
background-attachment: scroll;
}

Then i overwrite it with media query removing "fixed" as background attachment.

css (mobile)

/*-------- iPads (portrait and landscape) --------*/
@media only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) {
#ci-hero-11 .widget-wrap , #ci-hero-12 .widget-wrap {

    background-attachment: initial;

}
}

initial - Sets this property to its default value. I think because IOS doesn't accept 'fixed' it falls back to a default value it accepts, scroll.

This worked for me on every device. Hope it helps someone else as well.

Ylama
  • 2,040
  • 19
  • 44
  • Could you make a live demo? (Not on CodePen or JSFiddle because they work with iframes, in which iOS will not fixate anything.) – Frank Conijn Apr 07 '18 at 02:19
8

Try this:

HTML

<div class="container">
  <div class="fixed-img"></div>
  <h1>Words that go over text</h1>
</div>

css

.fixed-img {
  position: fixed;
  z-index: -1;
}

JSFiddle example

Live example

Cruz Nunez
  • 2,430
  • 1
  • 19
  • 30
  • 6
    You can use a pseudo element instead: `.container::before{content: "";display: block;position: fixed;z-index: -1;height: 100%;width: 100%}`, and you don't need to add any element in DOM – mems Mar 14 '16 at 11:25
  • @BjørnBørresen -- The JSFiddle indeed does not work, but that is because it works with iframes and iOS will not fixate anything in iframes, regardless of the code. The Live example Cruz is linking to does work on my iPad Pro 11.3. Or for a more bare-bones example, check out https://newskiinstruction.com/bgtest.html. – Frank Conijn Apr 07 '18 at 02:38
  • doesnt work on safari mobile, well unless you want the image resizing and bouncing around the screen – Beanie Sep 07 '20 at 19:21
  • Summary of this solution: Instead of using `background-attachment: fixed;`, add a background image to a `position: fixed;` div. – mike Jan 05 '21 at 14:16
  • This answer should be accepted - would have saved me time. – wkille Feb 19 '21 at 12:24
5
.header {
    background-position: -99999px -99999px;
}
.header:before {
    content: ""; 
    background-image: inherit;
    position: fixed; 
    top: 0; 
    left: 0; 
    height: 100vh; 
    width: 100%; 
    -webkit-background-size: cover !important; 
    -moz-background-size: cover !important; 
    -o-background-size: cover;
    background-size: cover !important; 
    z-index: -1;
}

I believe I have achieved the desired effect on my own site using the above in conjunction with a fix to allow 100vh to work on ios devices.

Dharman
  • 21,838
  • 18
  • 57
  • 107
MugenFTW
  • 51
  • 1
  • 4
5

EDIT: Sep 2020 This broke for some iPads so I now use:

@supports (-webkit-touch-callout: inherit) {
  .paral {
  background-attachment: scroll;
  }
}

Original Post: Combining the ideas of @brouxhaha and @yllama: Use a media query that targets iOS, which is found at this SO post, to set

    background-attachment: scroll;

This way the fixed background image appears for non-iOS mobile and all other devices.

.widget-wrap {
   background-attachment: fixed;
   ...
   ...
}

@supports (-webkit-overflow-scrolling: touch) {
  .widget-wrap {
  background-attachment: scroll;
  }
}
LWRMS
  • 365
  • 3
  • 15
2

What about something like this? (i just noticed that @mems already proposed it)

    body {
      position: relative;
    }

    body:after {
      position: fixed;
      top: 0;
      left: 0;
      height: 100%;
      width: 100%;
      content: '';
      background-image: url(./img/YOUR_IMG.png);
      background-size: cover;
      background-repeat: no-repeat;
      background-color: #000;
      background-position: bottom right;
    }
Gianni Unz
  • 21
  • 2
2

I had the same issue you had and struggled with it almost 3 days. But as of June 2020 and improving on @AGrush's answer, here is a reliable solution I found for this that works on all devices and has 100% browser compatibility. It allows the desired effect in any place of the page and not just the top or bottom of the page, and you can create as many as you need or want.

This also addresses the different issues provided by @Ylama, @Cruz-Nunez, @Tim and @LWRMS answers that rely on device media queries that, as you know, have no standards and vary on many new devices. And also avoids the use of pseudo elements that I have never been really able to work with, as with the solutions proposed by @MugenFTW and @Gianni Unz.

The only known issue so far is with this option is in safari. The browser repaints the whole image on every scroll movement so it puts a heavy burden on graphics and most of the time makes the image flicker up and down some 10px. There is literally no fix for this, but i think there is also no better response for your inquire.

I hope this works for you. You can check the results live in www.theargw.com, where i have three different fixed background images.

body, .black {
  width: 100%;
  height: 200px;
  background: black;
}

.e-with-fixed-bg {
  width: 100%;
  height: 300px;
  
  /* Important */
  position: relative;
}

.bg-wrap {
  clip: rect(0, auto, auto, 0);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.bg {
  position: fixed;
  display: block;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-size: cover;
  background-position: center center;
  background-image: url(https://images.pexels.com/photos/949587/pexels-photo-949587.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500);
  transform: translateZ(0);
  will-change: transform;
}

.e-container {
  z-index: 1;
  color: white;
  background: transparent;
}
<div class="black"></div>
<div class="e-with-fixed-bg">
  <div class="bg-wrap">
     <div class="bg"></div>
  </div>
  <div class="e-container">
    <h1>This works well enought</h1>
  </div>
</div>
<div class="black"></div>

--------------------- EDIT --------------------- The code posted was missing the background wrapper that allows the background to not change size and maintain the fixed position. Sorry to post the wrong code this morning guys! But here is the change.

1

Or you can just put a transparent div that covers the screen and use overflow:scroll. Just for the sake of it you can rewrite the height of the div with javascript to screen.height.

#scrollbox {
 width: 100%;
 height: 100%;
 overflow: scroll;
 background: transparent;
}

document.getElementByID("scrollbox").style.height = screen.height;
Creedish
  • 11
  • 1
1

Use CSS perspective instead of JS or fixed background parallax for best performance and device compatibility.

body, html { 
  margin: 0;
  padding:0;
}

.wrapper {
  height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;
  perspective: 1px;
}

.section {
  position: relative;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 48px;
  color: white;
}

.parallax::after {
  content: " ";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  transform: translateZ(-1px) scale(2);
  background-size: 100%;
  z-index: -1;
  background-image: url('http://placeimg.com/640/480/any');
}

.content {
  height: 200vh;
  display: flex;
  justify-content: center;
  background: red;
}
<div class="wrapper">
  <div class="section parallax">
   <h1>Heading</h1>
  </div>
  <div class="content">
    <h1>Site Content</h1>
  </div>
</div>
AGrush
  • 805
  • 4
  • 25
0

My solution is a workaround. I created a div with 100%, fixed, and added the background image since iOS still ignores "background-attachment: fixed".

<div style="
 position: fixed;
 width: 100%;
 height: 100%;
 background-size: cover;
 background-position:center;
 top: 0; right: 0;
 z-index: -1000;
 background-image: url(image.jpg)">
</div>
tomDev
  • 5,436
  • 5
  • 27
  • 37