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

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

问题描述

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

$(window).scroll(() => {严格使用";让 windowH = $(window).height();让 windowS = $(window).scrollTop();让 header = $("#header").height();如果(windowS  (windowH-header)/2 ? "fixed" :"static");});

.fixed {位置:固定!重要;}.包装{宽度:100%;文本对齐:居中;}.wrapper:before {显示:表;内容: " ";}.wrapper:在{之后清楚:两者;}#里面 {宽度:100%;高度:100vh;背景色:浅珊瑚色;显示:弹性;对齐项目:居中;对齐内容:居中;}#header {高度:90px;顶部:0;位置:粘性;显示:弹性;对齐项目:居中;对齐内容:居中;过渡:全0.5s;}#标题 {宽度:100%;颜色:#fff;变换:比例(2);}#内容 {高度:1000px;背景颜色:浅蓝色;}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><身体><div class="wrapper"><div id="里面"><div id="标题"><h1 id="title">标题</h1>

<div id="内容"></div>

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

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

$(window).scroll(() => {严格使用";让 windowH = $(window).height();让 windowS = $(window).scrollTop();让 header = $("#header").height();如果(windowS  (windowH-header)/2 ? "fixed" :"static");});

.fixed {位置:固定!重要;}.包装{宽度:100%;文本对齐:居中;}.wrapper:before {显示:表;内容: " ";}.wrapper:在{之后清楚:两者;}#里面 {宽度:100%;高度:100vh;背景色:浅珊瑚色;过滤器:亮度(1.3);/*<<<<<<<<<<<<<<<<*/显示:弹性;对齐项目:居中;对齐内容:居中;}#header {高度:90px;顶部:0;位置:粘性;显示:弹性;对齐项目:居中;对齐内容:居中;过渡:全0.5s;}#标题 {宽度:100%;颜色:#fff;变换:比例(2);}#内容 {高度:1000px;背景颜色:浅蓝色;}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><身体><div class="wrapper"><div id="里面"><div id="标题"><h1 id="title">标题</h1>

<div id="内容"></div>

解决方案

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

<块引用>

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

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

这是一个简化版本来说明问题:

.container {显示:内联块;宽度:200px;高度:200vh;边框:1px 实心;}.container>div {位置:固定;宽度:100px;高度:100px;背景:红色;颜色:#fff;}

<div>我固定在滚动</div>

<div class="container" style="filter:grayscale(1);"><div>我随着滚动而移动</div>

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

.container {显示:内联块;宽度:200px;高度:200vh;边框:1px 实心;}.container>div {位置:固定;宽度:100px;高度:100px;背景:红色;颜色:#fff;过滤器:灰度(1);}

<div>我固定在滚动</div>


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

<块引用>

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

1:会尽量更新这个列表.

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>

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);.

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:

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.

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>


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

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: Will try to keep this list up to date.

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

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆