Así que tengo esta "animación" de pantalla de título que tiene el título centrado en una página de pantalla completa y cuando se desplaza hacia abajo se vuelve más pequeño y permanece en la parte superior de la página. Aquí hay un ejemplo de trabajo con el comportamiento esperado, del cual eliminé todo el código innecesario para hacerlo mínimo:
$(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> El siguiente es exactamente el mismo fragmento pero con una adición: apliqué un filtro, que es, en lo que a mí respecta, puramente cosmético: filter: brightness(1.3); .
Como puede ver a continuación, cuando se desplaza a la mitad de la "animación", el título simplemente desaparece. Cuando inspeccionas el elemento, todavía tiene todas sus propiedades, pero de alguna manera se ha ido. Esto es lo mismo en Firefox y Chrome y no tengo idea de por qué. Apreciaría mucho si alguien pudiera publicar un fragmento que funcione con el filtro aplicado y explicar por qué no funcionó antes.
$(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>Si nos remitimos a la especificación podemos leer:
Un valor distinto de ninguno para la propiedad de filtro da como resultado la creación de un bloque contenedor para descendientes absolutos y de posición fija, a menos que el elemento al que se aplica sea un elemento raíz del documento en el contexto de exploración actual. La lista de funciones se aplica en el orden indicado.
Esto significa que su elemento position:fixed se colocará en relación con el contenedor filtrado y no más con la ventana gráfica. En otras palabras, todavía está arreglado pero dentro de su nuevo bloque contenedor (el contenedor filtrado)
Aquí hay una versión simplificada para ilustrar el problema:
.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>Para solucionar el problema, intente mover el filtro al elemento fijo en lugar de su contenedor:
.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>Aquí hay una lista no exhaustiva 1 de las propiedades que dan como resultado la creación de un bloque contenedor para descendientes absolutos y de posición fija
filtertransform referenciabackdrop-filterperspectivecontain referenciatransform-stylecontent-visibilitywill-change cuando se use con uno de los valores anterioresSi cualquier valor no inicial de una propiedad hace que el elemento genere un bloque contenedor para elementos con posiciones absolutas, especificar esa propiedad en will-change debe hacer que el elemento genere un bloque contenedor para elementos con posiciones absolutas. árbitro
1 : Intentaré mantener esta lista actualizada.
Para evitar un mantenimiento intensivo y una implementación diferente para cada navegador, puede utilizar una función de recorrido de árbol recursivo que marca los nodos de posición 'fijos' y luego aplica el filtro necesario correctamente sin destruir las posiciones.
Utilicé este código para aplicar la propiedad 'filter invert' globalmente, sin codificarlo en elementos principales específicos.
Puedes hacer que suceda usando before . en lugar de asignar el filter: brightness(1.3); al elemento secundario directamente. asigne color y filtro al before de este elemento secundario. entonces tu código debería ser así:
#inside:before{ filter: brightness(1.3); content: ""; background-color: lightcoral; top: 0; left: 0; width: 100%; height: 100%; position: absolute; }Esto arreglará el problema.
También debe editar parte de su código para que esto funcione completamente:
#inside{ position: relative; } Haga que la posición principal sea relativa para asegurarse de que before se ajuste dentro de su principal.
Esta solución también funciona con otros filtros como backdrop-filter .
Si desea desenfocar o escalar en gris toda la página, excepto un elemento, simplemente use backdrop-filter lugar del filter . Al momento de escribir, Firefox solo necesita enviarlo de manera predeterminada.
No funciona:
<!DOCTYPE html><html><head> <style> .overlay { position:fixed; right:10%; top:10%; bottom:10%; left:10%; background-color:red; z-index:2; } .overlay ~ * { filter: grayscale(50%) blur(5px); } </style> </head> <body> <div class="overlay">I am not blurred</div> <!-- position test --> <div style="margin-top:100px;float:right;"> <div style="background-color:red;position:fixed;top:0;right:0;width:100px;height:100px;"></div> </div> </body> </html>Trabajando:
<!DOCTYPE html><html><head> <style> .overlay { position:fixed; right:10%; top:10%; bottom:10%; left:10%; background-color:red; z-index:2; } body:after { content:""; position:fixed; z-index: 1; top:0; left:0; width:100%; height:100%; backdrop-filter: grayscale(50%) blur(5px); } </style> </head> <body> <div class="overlay">I am not blurred</div> <!-- position test --> <div style="margin-top:100px;float:right;"> <div style="background-color:red;position:fixed;top:0;right:0;width:100px;height:100px;"></div> </div> </body> </html>