es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La propiedad “history.scrollRestoration = manual” no evita que Safari restaure la posición del desplazamiento.

Supongamos que estableces window.history.scrollRestoration = "manual" en una página web.

En Chrome/Firefox

Cada vez que haces clic en un enlace, la página se desplaza a la posición del elemento vinculado, y cada vez que retrocedes/avanzas a través del historial, la posición de desplazamiento permanece igual pero se actualiza la parte de fragmento de la URL (#sectionXYZ).

En Safari

Cada vez que haces clic en un enlace no sucede nada, y cada vez que retrocedes/avanzas a través del historial, la página se desplaza a la posición del elemento vinculado al fragmento de la página actual (#sectionXYZ).

Cuando digo “navegar a través del historial” me refiero a utilizar window.history.back(), window.history.forward() y window.history.go(N) o utilizando los botones de volver/avanzar del navegador.

En el siguiente ejemplo hay 2 botones (azul y rojo) que agregarán 2 estados diferentes al historial cuando se hagan clic.
Intenta hacer clic varias veces y retroceder/avanzar a través del historial para replicar los comportamientos que describí.

¿Por qué Safari restaura la posición de desplazamiento de la página incluso cuando history.scrollRestoration está establecido en manual? ¿Existe alguna manera de evitar este comportamiento como lo hacen Chrome y Firefox?

html,body,div {
    height: 100vh;
    width: 100vw;
    margin: 0;
    overflow-x: hidden;
}    
#nav {
    display:flex;
    justify-content:center;
    position:fixed;
    width: 100%;
    height: 100px;
    background: rgba(0,0,0,0.7);
}
nav > a {
    display:grid;
    justify-content:center;
    align-items:center;
    text-decoration:none;
    color:white;
    width: 30%;
    height: 90%;
    font-size:120%;
    cursor:pointer;
}
#a1, #blue{
    background-color:blue;
}   
#a2, #red {
    background-color:red;
}

<body>
    <nav id = "nav">
        <a id = "a1" href = "#blue">AZUL</a> 
        <a id = "a2" href = "#red">ROJO</a> 
    </nav>
    <div id = "blue"></div>
    <div id = "red"></div>

    <script>
        window.history.scrollRestoration = "manual";
        window.addEventListener("popstate", () => {
            console.log("blue: ", document.getElementById("blue").getBoundingClientRect());
            console.log("red: ",  document.getElementById("red").getBoundingClientRect());
        });
        document.getElementById("a1").addEventListener("click", () => window.history.pushState("blue", "", "#blue"));
        document.getElementById("a2").addEventListener("click", () => window.history.pushState("red",  "", "#red"));
    </script>
</body>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    ¿Por qué Safari restaura la posición de desplazamiento de la página incluso cuando history.scrollRestoration se establece en manual? ¿Hay alguna forma de evitar este comportamiento como lo hacen Chrome y Firefox?

    En Safari, cuando history.scrollRestoration se establece en manual, todavía restaura la posición de desplazamiento de la página al navegar hacia atrás/adelante a través del historial. Esto se debe a que Safari considera que la scrollPosition es parte del estado del historial, por lo que lo almacena y lo restaura junto con el resto del estado.

    Para evitar este comportamiento, se puede utilizar el método history.replaceState() para reemplazar el estado actual por uno nuevo que tenga una posición de desplazamiento null. Esto eliminará efectivamente la posición de desplazamiento del estado de la historia, haciendo que Safari se comporte como Chrome y Firefox.

    Aquí hay un ejemplo de cómo modificar el fragmento de código original para evitar que Safari restaure la posición de desplazamiento:

    <body>
      <nav id="nav">
        <a id="a1" href="#blue">BLUE</a>
        <a id="a2" href="#red">RED</a>
      </nav>
      <div id="blue"></div>
      <div id="red"></div>
    
      <script>
        const setNullScrollState = () => {
          const { state } = window.history;
          state.scrollPosition = { x: 0, y: 0 };
          window.history.replaceState(state, '', '');
        };
    
        /* Llama a la función cada vez que se carga la página */
        setNullScrollState();
    
        window.addEventListener('popstate', () => {
          console.log('azul:', document.getElementById('blue').getBoundingClientRect());
          console.log('rojo:', document.getElementById('red').getBoundingClientRect());
          /* Restablece la posición de desplazamiento a 0 siempre que se navega hacia atrás/adelante */
          setNullScrollState();
        });
    
        document.getElementById('a1').addEventListener('click', () => window.history.pushState('blue', '', '#blue'));
        document.getElementById('a2').addEventListener('click', () => window.history.pushState('red', '', '#red'));
      </script>
    </body>
    

    La función setNullScrollState() crea un nuevo objeto de estado de la historia que es igual al actual, excepto que su propiedad scrollPosition es un objeto con los valores x: 0 e y: 0, y reemplaza el estado actual por este nuevo usando history.replaceState(). Cada vez que el usuario navega hacia atrás/adelante, se llama al controlador de eventos popstate, que registra la posición de los elementos blue y red (con fines de demostración), y luego llama a setNullScrollState() para restablecer la posición de desplazamiento a 0.

Comments are closed.