为什么在父级上应用 CSS-Filter 会破坏子级定位? [英] Why does applying a CSS-Filter on the parent break the child positioning?

查看:64
本文介绍了为什么在父级上应用 CSS-Filter 会破坏子级定位?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有这个标题屏幕动画";标题居中在全屏页面上,当您向下滚动时,它会变小并保持在页面顶部.这是一个具有预期行为的工作示例,我从中删除了所有不必要的代码以使其最小化:

So I have this title-screen "animation" that has the title centered on a fullscreen page and when you scroll down it becomes smaller and remains at the top of the page. Here is a working example with the expected behavior, from which I stripped all unnecessary code to make it minimal:

$(window).scroll( () => {
    "use strict";
    let windowH = $(window).height();
    let windowS = $(window).scrollTop();
    let header  = $("#header").height(); 
    
    if (windowS < windowH-header) {
        $("#title").css("transform", "scale("+(2-(windowS/($(document).outerHeight()-windowH))*2.7)+")");
        $("#header").css("transform", "translateY(0)");
        $("#inside, #content").css({
            "position": "static",
            "margin-top": 0
        });
    } else {
        $("#inside").css({
            "position": "fixed",
            "margin-top": -windowH+header
        });
        $("#content").css("margin-top", windowH);
    }
  
    $("#header").css("position", windowS > (windowH-header)/2 ? "fixed" :"static");
});

.fixed {
    position: fixed!important;
}
.wrapper {
    width: 100%;
    text-align: center;
}
.wrapper:before {
    display: table;
    content: " ";
}
.wrapper:after {
    clear: both;
}
#inside {
    width: 100%;
    height: 100vh;
    background-color: lightcoral;
    display: flex;
    align-items: center;
    justify-content: center;
}
#header {
    height: 90px;
    top: 0;
    position: sticky;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.5s;
}
#title {
    width: 100%;
    color: #fff;
    transform: scale(2);
}
#content {
    height: 1000px;
    background-color: lightblue;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>  
    <div class="wrapper">
        <div id="inside">
            <div id="header">
                <h1 id="title">Title</h1>
            </div>
        </div>
    <div id="content"></div>
</body>

接下来是完全相同的片段,但添加了一个:我应用了一个过滤器,就我而言,它纯粹是装饰性的:filter:brightness(1.3);.

Next up is the exact same snippet but with one addition: I applied a filter, which is, as far as I'm concerned, purely cosmetic: filter: brightness(1.3);.

正如您在动画"中滚动到一半时所看到的那样.标题就消失了.当您检查元素时,它仍然具有所有属性,但不知何故它消失了.这在 Firefox 和 Chrome 中是一样的,我不知道为什么.如果有人可以发布一个应用了过滤器的工作片段并解释为什么它以前不起作用,我将不胜感激.

As you can see below when you scroll half-way through the "animation" the title just disappears. When you inspect the element it still has all its properties but somehow it's gone. This is the same in Firefox and Chrome and I have no idea why. I would appreciate it a lot if someone could post a working snippet with the filter applied and explain why it didn't work before.

$(window).scroll( () => {
    "use strict";
    let windowH = $(window).height();
    let windowS = $(window).scrollTop();
    let header  = $("#header").height(); 
    
    if (windowS < windowH-header) {
        $("#title").css("transform", "scale("+(2-(windowS/($(document).outerHeight()-windowH))*2.7)+")");
        $("#header").css("transform", "translateY(0)");
        $("#inside, #content").css({
            "position": "static",
            "margin-top": 0
        });
    } else {
        $("#inside").css({
            "position": "fixed",
            "margin-top": -windowH+header
        });
        $("#content").css("margin-top", windowH);
    }
  
    $("#header").css("position", windowS > (windowH-header)/2 ? "fixed" :"static");
});

.fixed {
    position: fixed!important;
}
.wrapper {
    width: 100%;
    text-align: center;
}
.wrapper:before {
    display: table;
    content: " ";
}
.wrapper:after {
    clear: both;
}
#inside {
    width: 100%;
    height: 100vh;
    background-color: lightcoral;
    filter: brightness(1.3);        /*<<<<<<<<<<<<<<<<*/
    display: flex;
    align-items: center;
    justify-content: center;
}
#header {
    height: 90px;
    top: 0;
    position: sticky;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.5s;
}
#title {
    width: 100%;
    color: #fff;
    transform: scale(2);
}
#content {
    height: 1000px;
    background-color: lightblue;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>  
    <div class="wrapper">
        <div id="inside">
            <div id="header">
                <h1 id="title">Title</h1>
            </div>
        </div>
    <div id="content"></div>
</body>

推荐答案

如果我们参考 规范我们可以阅读:

If we refer to the specification we can read:

过滤器属性的值不是 none 会导致为绝对定位和固定定位创建一个包含块descendants 除非它适用的元素是文档根当前浏览上下文中的元素.函数列表是按提供的顺序应用.

A value other than none for the filter property results in the creation of a containing block for absolute and fixed positioned descendants unless the element it applies to is a document root element in the current browsing context. The list of functions are applied in the order provided.

这意味着您的 position:fixed 元素将相对于过滤后的容器定位,而不是视口.换句话说,它仍然是固定的,但在它的 new 包含块(过滤的容器)内

This means that your position:fixed element will be positioned relatively to the filtered container and no more the viewport. In other words, it's still fixed but inside its new containing block (the filtered container)

这里有一个简化的版本来说明这个问题:

Here is a simplified version to illustrate the issue:

.container {
  display: inline-block;
  width: 200px;
  height: 200vh;
  border: 1px solid;
}

.container>div {
  position: fixed;
  width: 100px;
  height: 100px;
  background: red;
  color: #fff;
}

<div class="container">
  <div>I am fixed on scroll</div>
</div>

<div class="container" style="filter:grayscale(1);">
  <div>I move with the scroll</div>
</div>

要解决此问题,请尝试将过滤器移动到固定元素而不是其容器:

To fix the issue try to move the filter to the fixed element instead of its container:

.container {
  display: inline-block;
  width: 200px;
  height: 200vh;
  border: 1px solid;
}

.container>div {
  position: fixed;
  width: 100px;
  height: 100px;
  background: red;
  color: #fff;
  filter: grayscale(1);
}

<div class="container">
  <div>I am fixed on scroll</div>
</div>

这是一个非详尽的1属性列表,导致为绝对和固定定位的后代创建包含块

Here is a non-exhaustive1 list of the properties that results in the creation of a containing block for absolute and fixed positioned descendants

  • 过滤器
  • transform 参考
  • backdrop-filter ref
  • perspective ref
  • 包含 ref
  • transform-style 参考
  • 内容可见性 ref
  • will-change 与上述值之一一起使用时
  • filter
  • transform ref
  • backdrop-filter ref
  • perspective ref
  • contain ref
  • transform-style ref
  • content-visibility ref
  • will-change when used with one of the above values

如果属性的任何非初始值会导致元素为绝对定位元素生成包含块,则在 will-change 中指定该属性必须导致元素为绝对定位元素生成包含块.参考

If any non-initial value of a property would cause the element to generate a containing block for absolutely positioned elements, specifying that property in will-change must cause the element to generate a containing block for absolutely positioned elements. ref

1:我会尽量保持这个列表是最新的.

1: I will try to keep this list up to date.

这篇关于为什么在父级上应用 CSS-Filter 会破坏子级定位?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆