The Fixed Background Attachment Hack
如果您希望身体背景处于固定位置(放置在滚动中),您有什么选择? background-attachment: fixed在CSS中,这个在移动浏览器中效果不好,在最坏的情况下甚至没有得到使用最广泛的移动浏览器的支持。您可以完全抛弃这个想法,让背景使用媒体查询在小屏幕上滚动。
或者用一个小的修复绕过它。我想我们可以称之为 "hack", 因为它是代码中的解决方法, 可以说我们根本不应该这样做。
问题
在我告诉你修复方法之前,让我们来研究一下这个问题。我们可以通过查看两种不同的方法来了解 CSS 背景:
- 使用线性梯度的背景
- 使用图像的背景
线性梯度
我想将背景渐变保持在滚动的固定位置,因此,让我们将基本的 CSS 造型应用于执行该操作的主体:
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;
}
以下是分别在安卓系统上 Chrome 和 Firefox 的结果:
梯度只需与其他内容一起滚动,然后跳回。我不知道这是为什么 - 也许当 URL 选项卡上升或消失在滚动和浏览器发现很难实时重新渲染梯度?这是我最好的猜测, 因为它似乎只发生在移动浏览器。
如果你想知道 ios Safari, 我个人还没有在 ios 上测试过, 但问题也在那里。有些人已经报告了这个问题,而且似乎表现类似。
背景图像
图像的这个问题也不例外。
body {
background: url(../assets/test_pic.jpg);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
background-attachment: fixed;
height: 100vh;
}
顶部的灰色部分只是表示 Chrome 安卓系统中存在实际 URL 条。
另一个有趣的事情是,当应用background-attachment: fixed时,高度被忽略,即使我们明确指定它。这是因为background-attachment计算相对于视场的固定背景位置。
即使我们说主体是100vh,background-attachment: fixed也不完全符合它。奇怪!也许原因background-attachment: fixed是依赖于尽可能小的视图波特,而元素依赖于最大的可能视口。大卫·博坎解释道
视距单元(即
vh)中定义的长度不会因显示或隐藏的 URL 条而调整大小。相反,vh单元的大小将调整到视场高度,就好像网址栏始终隐藏一样。即,vh单元将大小为"最大可能的视图港"。这意味着当网址条显示时,100vh将大于可见高度。
这些问题在caniuse有很好的记录:
- 当应用于文本区域元素时,火狐似乎不支持本地值。
- Chrome 在选择器上使用
will-change属性时会出现问题,该选择器也已定义background-attachment: fixed。它会导致图像被切断,并获得周围的空白。- iOS 有一个问题,阻止
background-attachment: fixed和background-size: cover一起被使用
让我们来修复它
称之为临时黑客, 如果你会。你们中的一些人可能已经试过了。无论情况如何,它都会修复我们刚刚看到的线性渐变和背景图像问题。
所以,如你所知,我们遇到了麻烦的background-attachment: fixed属性,你可能已经猜到,我们正在从我们的代码中删除它。 如果它正在查看 smallest 可能的视口,那么也许我们应该使用一个元素来查找 largest 可能的视口并将其定位。
因此,我们创建了两个单独的元素——一个用于background-gradient,另一个用于其余内容。 我们正在将background-attachment: fixed 替换为 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
}
现在,将其余内容(包含背景图像的元素除外)包裹在主容器中。
.content{
position: absolute;
margin-top: 5rem;
left: 50%;
transform: translateX(-50%);
width: 80%;
}
成功!
我们可以使用相同的技巧兼容与背景图像,它的工作原理很好。但是,当 URL 条隐藏自己时,您确实会获得某种背景滚动,但白色补丁已不复存在。
.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%;
}
这是我的要点
高度设定为 100% 的固定位置元素的行为与background-attachment: fixed属性元素一样,这在下面的示例中显而易见!只需观察视频中最右侧的条形图(紫色)。
尽管如此,大卫·博坎在他的文章中说:
即,
position: fixed其包含块为 ICB 的元素将针对显示或隐藏的 URL 条进行调整大小。例如,如果它的高度是100%它总是会填补确切可见的高度,无论是否显示网址栏。同样,对于vh长度,它们也将调整大小,以匹配可见高度,同时考虑 URL 条位置。
如果我们考虑到最后一句话,这里似乎并非如此。具有固定定位和 100vh 高度的元素不会改变其高度,无论是否显示 URL 条。事实上,高度是根据"最大可能的视图港"的高度。这在下面的示例中显而易见。只需观察视频中的浅蓝色条形。
因此,在处理 100vh 的容器时,background-attachment: fixed似乎会考虑尽可能小的视场高度,而元素一般会考虑尽可能大的视场高度。
例如,background-attachment:fixed 只是在需要重绘时停止工作,比如移动浏览器的地址栏在滚动时消失。 浏览器根据最大的可能视场(事实上,现在隐藏的 URL 条是最小的视场)调整背景,浏览器的效率不足以在飞行中重新涂漆,从而导致重大滞后。
我们的黑客解决这个问题,使背景的元素,而不是,嗯,一个实际的背景。我们给包含内容的元素一个绝对位置,将其堆叠在包含图像的元素之上,然后在后者上应用固定位置。嘿, 成功了!
请注意,查看口高度的计算不包括底部的导航栏(如果存在)。以下是 Chrome Android 底部导航栏的存在与缺失之间的比较。
有什么缺点吗? 也许! 我们使用通用的 <div> 而不是实际的 <img> 标签,所以我不会说标记是语义的。 这可能会导致 可访问性问题。 如果您正在处理为内容添加含义或上下文的图像,那么使用 <img> 是正确的方法,为屏幕阅读器使用适当的 alt 描述。
但是,如果我们走正确的路线,那么我们就回到了我们开始的地方。此外, 如果你有一个导航栏在底部, 太自动隐藏自己, 那么我不能帮助它。如果黑客不会削减它,那么也许JavaScript可以来解决。<img>