父母的CSS过滤器破坏了孩子的位置 [英] CSS-Filter on parent breaks child positioning

查看:52
本文介绍了父母的CSS过滤器破坏了孩子的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在一个网站上工作,遇到了这种奇怪的行为.我不确定这是一个错误还是如何解决,所以我要向你们寻求帮助.

I am currently working on a website and encountered this weird behaviour. I am not sure if it is a bug or how to deal with it so I'm asking you guys for help.

因此,我拥有一个标题屏幕动画",该标题的标题位于全屏页面的中心,当您向下滚动时,标题会变小并保留在页面顶部.这是一个具有预期行为的工作示例,从中我剥离了所有不必要的代码以使其最小化:

So I have this title-screen "animation" that has the title centered in 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 behaviour, 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:

对于filter属性,除none以外的其他值都会导致 创建一个包含绝对位置和固定位置的块 后代,除非它适用的元素是文档根 当前浏览上下文中的元素.功能列表是 按提供的顺序应用.

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 filtred container and no more the viewport. In other words, it's still fixed but inside its new containing block (the filtred 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

  • filter
  • transform 参考
  • backdrop-filter 参考
  • perspective 参考
  • contain 参考
  • transform-style 参考
  • will-change当与上述值之一一起使用时
  • filter
  • transform ref
  • backdrop-filter ref
  • perspective ref
  • contain ref
  • transform-style 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: Will try to keep this list up to date.

这篇关于父母的CSS过滤器破坏了孩子的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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