background-attachment: fixed breaking with translateX(0)

396 Views Asked by At

I have a scrolling element with a fixed background:

.my-element {
   background: url(/foo.png) no-repeat right bottom;
   background-attachment: fixed;
}

It works great! Normally. However, if I apply a translate transform (even of 0) to it (which I need for an animation), the background shifts to be non-fixed (it anchors to the bottom of .my-element, which is scrolled out of view:

.my-element {
   background: url(/foo.png) no-repeat right bottom;
   background-attachment: fixed;
   transform: translateX(0); // this breaks the "fixed" behavior
}

There was a similar question about this here, but the answers from 4 years ago say the bug has been fixed, and that it was only firefox. This is happening to me in Firefox and Chrome.

Is there a way I can avoid this? Or is there a way to get the same behavior w/o the background-attachment property? Thanks!

edit: just added a jsfiddle demonstrating the issue: https://jsfiddle.net/mozges0k/7/

5

There are 5 best solutions below

7
JBS On

I had a pretty hard time finding a workaround. Extracting the background image to its own container and adding position: sticky to it seemed like a viable solution, but it didn't work out in the end.

There is one more solution that came to my mind: What if you extract transform to its own class and remove that class when the animation has finished? It seems like background-attachment starts working again when transformis removed, even at runtime. Then the background-attachment can do its magic and your animation can run too.

<div class="my-element animate">Lorem ipsum</div>
.my-element {
    background: url(/foo.png) no-repeat right bottom;
    background-attachment: fixed;
}

.animate {
    transform: translateX(0);
}
function animationFinished() {
    const target = document.querySelector('.animate');
    target.classList.remove('animate')
}

While its not as easy and direct as I would like it to be, this would be a solution. Let me know what you think, and good luck!

1
Upendra Nath Dubey On

Please check the code it is working for me fine I have already faced that issue. I have added background-size: cover; & transform: translateX(0) in keyframe and I think it is working for you too.

.my-element {

.my-element {
  padding: 10px;
  border-radius: 10px;
  background: url("https://i.imgur.com/PcqkZxh.jpg") no-repeat;
  min-height: 500px;
  background-attachment: fixed;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  animation: mymove .1s alternate ;
  -webkit-animation: mymove .1s alternate ;
}
@-webkit-keyframes mymove {
  from {
    transform: translateX(0);
    -webkit-transform:translateX(0);
  }
} 

@keyframes mymove {
  from {
    transform: translateX(0);
    -webkit-transform:translateX(0);
  }
} 
<h1 style="text-align: center">
Scroll to see the difference
</h1>

<div class="my-element">
   <h1>
   This works (fixed bg)
   </h1>
  <div>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
  </p>
  </div>

  </div>

1
YupMa On

If you don't mind adding a 2 containers(elements) then you can try below work around:

Creating a parent container for the element which you are transforming(translate)

--> You can position the parent element as relative

--> Create an another container for the image position it absolute

   .container-image {
  position: absolute;
  top: 0;
  left: 0;
  background: url("https://i.imgur.com/PcqkZxh.jpg") no-repeat;
  background-attachment: fixed;
  width: 100%;
  height: 100%;
  z-index: -1;
}

Then you are good to go with any transform animation on the container with a fixed background image

.foo {
  display: "none";
  flex-direction: "row";
}

.container-parent-broken {
  position: relative;
}

.container-broken {
  padding: 10px;
  border-radius: 10px;
  transform: translateX(0);
}

.container-image {
  position: absolute;
  top: 0;
  left: 0;
  background: url("https://i.imgur.com/PcqkZxh.jpg") no-repeat;
  background-attachment: fixed;
  width: 100%;
  height: 100%;
  z-index: -1;
}
<h1 style="text-align: center">
  Scroll to see the difference
</h1>

<div style="display: flex; column-gap: 20px;">

  <div class="container-parent-broken">
    <div class="container-image"></div>

    <div class="container-broken">
      <h1>
        This doesn't (translateX(0))
      </h1>
      <div>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
          in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
      </div>
    </div>

  </div>

</div>

0
thehuijb On

another way of working around this could be done using a grid layout inside the containers.

Using a grid of 1 column and 1 row and then assign both the image (a div with a background image in this example), and the content (wrapped in another div) to the same row and column.

You can then use position sticky on the image to have it stick when scrolling and use z-index: 0 on the content so it is visible on top.

difference would be that the background image would only start sticking when the container has reached the top of the viewport and stop sticking when scrolling past the element altogether.

You would now be able to use translateX to animate everything

.container-working, .container-broken {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
}

.container-broken {
  transform: translateX(0);
}

.container-image, .container-content {
  grid-row: 1;
  grid-column: 1;
}

.container-image {
  position: sticky;
  
  top: -10px; /* because of border-radius it has to stick a bit higher */
  border-radius: 10px;
  height: calc(100vh + 20px); /* increase height by twice the border-radius */
    
  background: url("https://i.imgur.com/PcqkZxh.jpg") no-repeat;
  background-size: cover;
}

.container-content {
  z-index: 0;
  padding: 10px;
}
<h1 style="text-align: center">
Scroll to see the difference
</h1>

<div style="display: flex; gap: 20px; position:relative;">
  <div class="container-working">
    <div class=container-image></div>
    <div class=container-content>
      <h1>
        This works (fixed bg)
      </h1>
      <div>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
      </div>
    </div>
  </div>
  <div class="container-broken">
    <div class=container-image></div>
    <div class=container-content>
      <h1>
       This doesn't (translateX(0))
      </h1>
      <div>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
        <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        </p>
      </div>
    </div>
  </div>

</div>

0
hackape On

Background

I dig into the topic a bit, and I find that this behavior is NOT a bug. It's actually conforming to the spec.

In the beginning things used to behave like you (and most of us) thought it should: background-attachment: fixed should fix the background relative the the viewport.

Turns out it's simply too hard to implement the fixing behavior when transform is involved, and thus the spec authors decided that "we might just change the spec to make things easier."

And now the spec says:

Fixed backgrounds on the root element are affected by any transform specified for that element. For all other elements that are effected by a transform (i.e. have a transform applied to them, or to any of their ancestor elements), a value of "fixed" for the "background-attachment" property is treated as if it had a value of "scroll".

which basically say transform invalidates background-attachment: fixed, explains everything.

Solution

I'd propose use a fixed-size scroll container, which is the same size as the viewport, with overflow: scroll. It serves as the a background bearer, and you apply transform to it.

Now because it's same size as viewport, vertical scroll wouldn't behave any different. But you can still transform: translateX(n) it however you want.

var text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.'

const scrollContainer = document.querySelector('.scroll-container')
const contentContainer = document.querySelector('.content-container')

const p = document.createElement('p')
p.innerText = text.repeat(20)

contentContainer.appendChild(p)

const btn = document.getElementById('btn')

btn.addEventListener('click', () => {
  scrollContainer.style = 'transform: translateX(-1000px);'
})
body {
  margin: 0;
  padding: 0;
}

.scroll-container {
  box-sizing: border-box;
  padding: 10px;
  border-radius: 10px;
  border: 2px solid red; 
  height: 100vh;
  width: 100vw;
  
  overflow: scroll;
  
  background: url("https://i.imgur.com/PcqkZxh.jpg") no-repeat;
  background-attachment: fixed;
  transition: 1s;
  transform: translateX(0);
}
<div class="scroll-container">
  <div class="content-container">
    <button id="btn">
      move
    </button>
  </div>
</div>