Insight
After delving deeper into the subject, I have discovered that this behavior is not a glitch but rather it adheres to the standards.
Initially, the expected behavior was in line with what you (and most of us) believed: setting background-attachment: fixed
should fix the background relative to the viewport.
However, it appears that implementing the fixing behavior becomes quite challenging when the transform
property is applied. As a result, the specification authors resolved to modify the spec for simplicity.
As per the current specification:
Fixed backgrounds on the root element are influenced by any specified transform for that element. Whereas, for other elements with an enforced transform (i.e., having a transform on them or any of their ancestors), setting the "background-attachment" property to "fixed" is considered equivalent to "scroll".
This essentially indicates that transform
overrides the effect of background-attachment: fixed
.
Resolution
My suggestion would be to utilize a fixed-size scroll container, matching the viewport's dimensions, with overflow: scroll
. This container will act as the background carrier, enabling you to apply transformations to it.
Since it mirrors the viewport's size, vertical scrolling won't exhibit any variance. Yet, you can still manipulate it using transform: translateX(n)
at will.
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>