Fixed background attachment hack.

What options do you have if you want to keep the physical background in a fixed position where it stays on the scroll? background-attachment: fixed CSS, at best, doesn’t work well in mobile browsers, and worst of all, it is not supported by most used mobile browsers. You can skip this idea altogether and let the background scroll to the small screens using media queries.

Or get around it with a little customization. I think we can call it a “hack” because it’s a solution in the code that we shouldn’t do with the argument at all.

Issue

Before I fix you, let’s take a look at this issue. We can see this by looking at two different ways of CSS background.

  1. Background using a linear gradient
  2. Background using image

Linear gradient.

I want to keep the background tilt in a fixed position on the scroll, so let’s apply the basic CSS style to the body which does exactly that:

body {
  background: linear-gradient(335deg, rgba(255,140,107,1) 0%, rgba(255,228,168,1) 100%);
  background-attachment: fixed;
  background-position: center;
  background-repeat: no-repeat;
  height: 100vh;
}

Both Chrome and Firefox, on Android, have the following results:

Milan just scrolls with other content then jumps back. I have no idea why – maybe when the URL tab goes up or disappears on the scroll and the browser finds it difficult to reproduce the trend in real time? This is my best guess because it seems to only happen in mobile browsers.

If you’re thinking of iOS Safari, I haven’t personally tested it on iOS, but there’s a problem. Some have already reported this issue and it seems that this is how it is being treated.

Background image

This problem is no different with images.

body {
  background: url(../assets/test_pic.jpg);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
  height: 100vh;
}

Another interesting thing is that when background-attachment: fixed Is applied, the height is ignored even if we clearly define it. Because background-attachment Calculates a fixed background position compared to the viewport.

Even if we say the body is 100vh, background-attachment: fixed Not exactly according to that. Strange! Maybe that’s why. background-attachment: fixed relies on Smallest Possible view port while relying on elements. the biggest Possible view port David Boken explains,

The length specified in the viewport units (ie vh) The URL bar will not resize in response to being shown or hidden. Instead, vh The units will be adjusted according to the height of the viewport as if the URL bar is always hidden. That is, vh The size of the units will be “the largest possible viewport”. It means 100vh The URL will be larger than the visible height when displayed.

The issues are well documented:

  • Firefox does not appear to support local values when applied to the texture element.
  • Chrome has a problem when using it. will-change Property on a selector that also has. background-attachment: fixed This determines the size of the image and the white space around it.
  • There is a problem preventing iOS. background-attachment: fixed Used with background-size: cover.

Let’s fix it

Call it a temporary hack if you want. Some of you may have already tried it. Either way, it fixes the linear gradient and background image problems we’ve just seen.

So, as you know, we’re in trouble. background-attachment: fixed Property and, as you may have guessed, we are removing it from our code. If it is watching Smallest Possible view port, then maybe we should work with an element that seeks. the biggest Possible viewport and its position.

So, we’re creating two separate elements – for one. background-gradient And another for the rest of the material. We are changing. background-attachment: fixed with position: fixed.

<div class="bg"></div>
<div class="content">
  <!-- content -->
</div>
.bg {
  background: linear-gradient(335deg, rgba(255,140,107,1) 0%, rgba(255,228,168,1) 100%);
  background-repeat: no-repeat;
  background-position: center;
  height: 100vh;
  width: 100vw;
  position: fixed;
  /* z-index usage is up to you.. although there is no need of using it because the default stack context will work. */
  z-index: -1; // this is optional
}

Now, wrap the rest of the material – except for the element that contains the background image – inside a central container.

.content{
  position: absolute;
  margin-top: 5rem;
  left: 50%; 
  transform: translateX(-50%);
  width: 80%;
}

Success!

We can use the same. Trick Hack with background images and it works fine. However, when the URL bar hides itself, you get some kind of background scrolling, but the white patch is no longer there.

.img {    
  background: url('../assets/test_pic.jpg');
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  position: fixed;
  height: 100vh;
  width: 100vw;
}

.content {
  position: absolute;
  left: 50%; 
  margin-top: 5rem;
  transform: translateX(-50%);
  width: 80%;
}

Here are my takeaways.

A fixed position element whose height is set to 100 behaves exactly like an element. background-attachment: fixed The property, which is clearly shown in the example below! Just look at the right bar (purple) in the video.

However, David Boken stated in his article:

That is, position: fixed The element containing the block ICB will resize in response to showing or hiding the URL bar. For example, if its height. 100% This will always fill in the visible height, even if the URL bar is shown. For the same vh Length, they will resize to match the visible height according to the URL bar position.

If we keep this last sentence in mind, it seems that this is not the case here. Elements with fixed positioning and 100vh height do not change their height regardless of whether the URL bar is displayed or not. In fact, the height corresponds to the height of the “largest possible viewport”. This is clear in the example below. Just look at the light blue bar in the video.

So, it appears that, when working with 100vh containers, background-attachment: fixed Considers Smallest Possible view port height while generally considering elements. the biggest Possible view port height.

For example, background-attachment: fixed Stops working when repaint is needed, such as when the mobile browser’s address bar scrolls. The browser adjusts the background according to the largest possible viewport (which, in fact, is the smallest possible viewport as the URL bar is hidden) and the browser is not as efficient at repainting on the fly. Is, resulting in a large gap.

Our hack addresses this by making the background an element instead of an actual background. We give an absolute position to the element containing the content so that we stack it on top of the element containing the image, then put a fixed position later. Hey, it works!

Note that the height of the viewport is calculated by leaving the navigation bar below (if any). Chrome has a comparison between the presence and absence of a navigation bar at the bottom of Android.

Is there a shortage? Probably! We are using a general. <div> Instead of a real one <img> Tag, so I wouldn’t say markup is semantic. And it can lead to access problems. If you are working with an image that adds meaning or context to the content, then one. <img> Using the right method, is the right way to go. alt Description for screen readers

But if we go properly. <img> By the way, then we’re back to where we started. Also, if you have a navigation bar at the bottom that hides itself, I can’t help it. If the hack doesn’t cut it, then maybe JavaScript can save it.

Leave a Reply

Your email address will not be published.