I have been wanting to use a fixed background on my websites for quite a while now. It is effortless to implement and is a great visual enhancement; who doesn't like the content effortlessly floating on the background image and the next section sliding over top as it is scrolled into the viewport?
As well as this effect, one of the hidden benefits of the using background-attachment is the image gets constrained to the viewport, which helps with background images in sections that are longer than the viewport. See the following image for what I mean.
background-attachment: fixed doesn't work on iOS
Cool, but what are some caveats? Well, there aren't any, except, wait for it, it doesn't work on iOS, yes for once it's not the long gone IE, it is now iOS Safari.
In the age of fast phones, you may wonder what is going on here, and you would be right to do so. As far as I can see, with “liquid glass,” this is something Apple needs to get on to. However, in the meantime, we need a fix.
In the rest of this article, we will look at some solutions so you can cater for iOS. The solutions we use will be very beneficial too, because the concepts use fundamentals such as positioning and z-index, as well as other properties such as mask-image.
Moreover, if you stay to the end, I will look at how we can re-write a template in Twig for use in the Drupal component that started this endeavour.
Disable the effect on iOS
Before we make this work on iOS, I would like to point out that the simplest solution is to unset the background-attachment value or set it back to scroll, and do this only for iOS.
I think this is essential as even though background-attachment: fixed doesn't work on iOS, setting it does stretch the image, and setting the value back to the default value at least makes things look acceptable.
How do I target iOS only?
We can target iOS only using an @supports rule. One property that is specific to iOS is the -webkit-touch-callout property; it is not supported on any other OSes.
We can check for -webkit-touch-callout with the value none in a @supports rule, like in the following snippet.
@supports(-webkit-touch-callout: none) {
.bg-attachment-fixed {
background-attachment: unset;
}
}Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-touch-callout
Below is an image showing the improvement this can make.
This is a great solution, and since on small devices, the fixed background is somewhat lost in this design, I think it is acceptable.
But I really want a Fixed Background
Research and Testing
It's a good idea to start by doing a basic test in vanilla HTML and CSS, a proof of concept. Knowing that if it works in the most basic set-up, then it will work with a Drupal twig template re-write or any other framework for that matter. This is a good practice in general. It is also good to do a little research before you start.
Setting Up the Proofing of Concept Markup
After a little research and with a few ideas in mind, I started with what seemed the simplest, and that was to stack absolute and fixed positioned elements inside a relative positioned wrapper. Then have the other content, the title in this case, in a sibling element to the absolute positioned wrapper of the fixed image.
The basic markup needs to change from the first block of markup shared below to the second block.
In this first block, the background image is added to the wrapper with the section's content inside the section. The background-attachment: fixed property in added using the fixed-bg class. The reason the image is added inline is that it can be uploaded to the site using the Drupal backend, the same is true for the background-position, background-size, and background-repeat; they are all configurable in the backend UI.
<div class="node__content">
<div class="layout fixed-bg" style="background-image: url(../files/2025-01/coffee-love-hero-pexels-tamas-marton-4616753.jpg);
background-position: center center;
background-size: cover;
background-repeat: no-repeat;">
<div class="container">
<div class="layout__region">
<div class="block">
[ HEADING ]
</div>
<div class="block">
[ CONTENT ]
</div>
</div>
</div>
</div>
<div class="layout">
[ CONTENT ]
</div>
<div class="layout">
[ CONTENT ]
</div>
</div>In this second block, the background image in added to a div that is isolated in a wrapper div. The wrapper is a sibling to the section's content. I have included a schematic following to show the difference. To get the same background fixed effect, we then need to use four rules.
<main>
<div class="section-1 container-fixed-bg">
<div class="fixed-bg-wrapper">
<div class="fixed-bg" style="background-size: cover;
background-position: center center;
background-image: url(https://designkojo.com/demos/drupal/web/sites/default/files/2025-01/coffee-love-hero-pexels-tamas-marton-4616753.jpg);">
</div>
</div>
<div class="layout__region fixed-bg-content">
[ HEADING ]
</div>
<div class="layout__region fixed-bg-content">
[ CONTENT ]
</div>
</div>
<div class="section-2">
[ CONTENT ]
</div>
<div class="section-3">
[ CONTENT ]
</div>
</main>The following image shows the difference in the markup, where the pink is the element with the background image, and the yellow the content that sits on top of the image.
This was the best method, too, as I wanted to do this with what I already had; an image added to the div element style attribute. This is because the image is added dynamically and can be uploaded via the Drupal UI as mentioned earlier.
Now we have some markup; we need to style it.
CSS Positioning
The core of the CSS has to do with positioning or using the position property.
If you are unfamiliar with positioning in CSS, I have a positioning basic article, CSS Positioning Using the Position Property, that shows how to use relative and absolute values to isolate and position elements on the page.
The CSS to make Background-attachment fixed work on iOS
This solution is smart and 100% solves the issue. It uses a stack of relative, absolute and then fixed div elements to isolate the element with the background image. And then clips or masks it to the size of the parent wrapper div.
/* Background-attachment: fixed for iOS*/
.container-fixed-bg {
width: 100%;
height: auto;
position: relative;
}
.fixed-bg-wrapper {
mask-image: url("mask-bg.svg");
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.fixed-bg {
position: fixed;
display: block;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* transform: translateZ(0);
will-change: transform;
*/
}
.fixed-bg-content {
position: relative;
}The content for the section is then placed in a sibling element and set to relative, which makes the element full into the document's natural flow.
Other sections then are left as is; they now naturally render in the nature flow.
This solution was from an older Stack overflow answer, however I have updated it to replace an unsupported property; I switch out the clip property for a mask.
And for now, I have also removed the transform: translateZ() and will-change: transform. I want to test if the transform and will-change properties are needed here.
Generally, people recommend using translate3d() for hardware acceleration, however maybe the Z axis value is all you need to benefit from the hardware acceleration technique; so in time, I will test this. If you want to implement this on your site, maybe at least adding the translate rule wouldn't hurt, but then again, it is for an iOS device which should be able to handle what we are doing here.
For the full code and a demo, please check out the following links:
Code: https://github.com/siramsay/iSO-background-attachment-fixed
Demo: https://designkojo.com/demos/iSO-background-attachment-fixed
Conclusion
So with a bit of template re-write, we can replicate the effect, which is good to know for future projects. The solution relies on separating the section into two separate elements; one for the background image and one for the other content.
What I don't like about the solution is that it totally needs to un-use background-attachment: fixed. I know that might sound picky, but needing to create a new solution only to work on iOS is a little disappointing; background-attachment: fixed is so simple and elegant.
I wish Apple would get their s**ff together, being able to create glass effects on mobile and not this, is a cop-out. It is pointless to dwell on this, however, as needing to do this has allowed me to play around and learn, so the fact that iOS spat the dummy has in fact benefited me and hopefully you too.
In the next article, we will look at rewriting a Twig template, so this solution can be used in a Drupal template. In the meantime, to get more great content like this delivered to your inbox, sign up below to my newsletter, I share a mix of front-end development and design lessons, thoughts, and new technology.