Haga que el enlace de anclaje vaya algunos píxeles arriba de donde está vinculado

123

No estoy seguro de la mejor manera de hacer / buscar esta pregunta:

Cuando haces clic en un enlace de anclaje, te lleva a esa sección de la página con el área enlazada ahora en la parte SUPERIOR de la página. Me gustaría que el enlace de anclaje me envíe a esa parte de la página, pero me gustaría un poco de espacio en la parte superior. Como en, no quiero que me envíe a la parte vinculada a ella en la parte SUPERIOR, me gustaría tener más o menos 100 píxeles de espacio allí.

¿Esto tiene sentido? es posible?

Editado para mostrar código, es solo una etiqueta de anclaje:

<a href="#anchor">Click me!</a>

<p id="anchor">I should be 100px below where I currently am!</p>
damon
fuente

Respuestas:

156
window.addEventListener("hashchange", function () {
    window.scrollTo(window.scrollX, window.scrollY - 100);
});

Esto permitirá que el navegador haga el trabajo de saltar al ancla para nosotros y luego usaremos esa posición para compensar.

EDITAR 1:

Como señaló @erb, esto solo funciona si está en la página mientras se modifica el hash. Entrar a la página con un #somethingya en la URL no funciona con el código anterior. Aquí hay otra versión para manejar eso:

// The function actually applying the offset
function offsetAnchor() {
    if(location.hash.length !== 0) {
        window.scrollTo(window.scrollX, window.scrollY - 100);
    }
}

// This will capture hash changes while on the page
window.addEventListener("hashchange", offsetAnchor);

// This is here so that when you enter the page with a hash,
// it can provide the offset in that case too. Having a timeout
// seems necessary to allow the browser to jump to the anchor first.
window.setTimeout(offsetAnchor, 1); // The delay of 1 is arbitrary and may not always work right (although it did in my testing).

NOTA: Para usar jQuery, puede reemplazar window.addEventListenercon $(window).onen los ejemplos. Gracias @Neon.

EDITAR 2:

Como señalaron algunos, lo anterior fallará si hace clic en el mismo enlace de anclaje dos o más veces seguidas porque no hay ningún hashchangeevento que fuerce el desplazamiento.

Esta solución es una versión ligeramente modificada de la sugerencia de @Mave y utiliza selectores jQuery para simplificar

// The function actually applying the offset
function offsetAnchor() {
  if (location.hash.length !== 0) {
    window.scrollTo(window.scrollX, window.scrollY - 100);
  }
}

// Captures click events of all <a> elements with href starting with #
$(document).on('click', 'a[href^="#"]', function(event) {
  // Click events are captured before hashchanges. Timeout
  // causes offsetAnchor to be called after the page jump.
  window.setTimeout(function() {
    offsetAnchor();
  }, 0);
});

// Set the offset when entering page with hash present in the url
window.setTimeout(offsetAnchor, 0);

JSFiddle para este ejemplo está aquí

Eric Olson
fuente
1
Esto sólo funciona cuando el usuario ya está en la página, no lo hace, por ejemplo, cuando el usuario visita example.com/#anchorde example.com/about/.
erb
77
Gracias @erb. La pregunta del OP no requería ese caso, pero para ayudar a otros agregué otra versión de la implementación.
Eric Olson
2
Todavía falta un detalle menor. Si hace clic en un ancla, luego desplácese hacia arriba y luego haga clic en el mismo ancla nuevamente, no hay cambio de hash, por lo que no usará el desplazamiento. Ideas?
Teo Maragakis
Podrías ir por $('a[href^="#"]').on('click', function() { offsetAnchor(); });. De esta manera, si la hrefde un aelemento comienza con a #, se llama a la misma función.
Mave
2
No es necesario jQuery - solo reemplace $(window).on("hashchange",conwindow.addEventListener("hashchange",
Neon
89

Al trabajar solo con CSS, puede agregar un relleno al elemento anclado (como en una solución anterior) Para evitar espacios en blanco innecesarios, puede agregar un margen negativo de la misma altura:

#anchor {
    padding-top: 50px;
    margin-top: -50px;
}

No estoy seguro si esta es la mejor solución en cualquier caso, pero funciona bien para mí.

usuario3364768
fuente
3
si hay un enlace dentro de 50px encima, puede estar tapado y no se puede hacer clic, creo
Andrew
@ Andrew Eso no parece ser un problema en IE10 o Chrome.
Sinister Beard
11
puede hacer lo mismo usando la position: relativepropiedad css. Entonces, sería comoposition: relative; top: -50px;
Aleks Dorohovich
@AleksDorohovich: puede publicar eso como una respuesta por separado, ya que es exclusivo de los existentes.
BSMP
Mi página se volvió loca ... * _ *
64

Aún mejor solución:

<p style="position:relative;">
    <a name="anchor" style="position:absolute; top:-100px;"></a>
    I should be 100px below where I currently am!
</p>

Simplemente coloque la <a>etiqueta con posicionamiento absoluto dentro de un objeto relativamente posicionado.

Funciona al ingresar a la página o mediante un cambio hash dentro de la página.

Thomas
fuente
44
Prefiero su solución porque no usa javascript. ¡Gracias!
Rosario Russo
1
No entiendo esta respuesta. ¿Estás haciendo referencia a este enlace al objeto o al objeto mismo?
CZorio
3
Muy útil con barras de
navegación de
1
@CZorio Si lo entendí bien, está (ingeniosamente) creando un elemento de anclaje (podría ser algo más, como "span" en lugar de "a") y posicionándolo relativamente por debajo, de modo que el anclaje href="#anchor"dentro apunte allí, en lugar de apuntar al <p>elemento directamente. Pero una advertencia: usar en idlugar de nameen HTML5, ver: stackoverflow.com/questions/484719/html-anchors-with-name-or-id
flen
1
Verdaderamente una mejor solución :)
Bobby Axe
22

Aquí está la respuesta 2020 para esto:

#anchor {
  scroll-margin-top: 100px;
}

¡Porque es ampliamente compatible !

usuario127091
fuente
1
Votado negativamente porque aunque esto sería bueno, NO es ampliamente compatible. Ni opera mobile / mini, ni safari browser / ios, ni siquiera el primer Edge lo admite completamente.
Beda Schmid
1
Un poco menos del 90% de todos los navegadores (incluido iOS con scroll-snap-margin-top) debería ser suficiente para optar por una solución de JavaScript, especialmente si el impacto del usuario es solo tener que desplazarse. Pero bueno, vamos a rechazar este enfoque antes de que perjudique a alguien.
user127091
Una respuesta tan simple y funcional. Pronto alcanzará el 100% de soporte (para navegadores modernos).
Leonel Becerra
17

Mejor solución

<span class="anchor" id="section1"></span>
<div class="section"></div>

<span class="anchor" id="section2"></span>
<div class="section"></div>

<span class="anchor" id="section3"></span>
<div class="section"></div>

<style>
.anchor{
  display: block;
  height: 115px; /*same height as header*/
  margin-top: -115px; /*same height as header*/
  visibility: hidden;
}
</style>
Никита Андрейчук
fuente
8
¿Por qué es esta la mejor solución? Además, es mucho más útil si le das algún nivel de explicación / razonamiento con una respuesta.
Phill Healey
Como está agregando HTML para hacer un ancla de todos modos, agregar un lapso no es muy diferente. Luego, simplemente agregando un poco de CSS, logras resolver este problema sin obtener ningún error; como algunas otras soluciones pueden hacer.
Sondre
11

Esto funcionará sin jQuery y en la carga de la página.

(function() {
    if (document.location.hash) {
        setTimeout(function() {
            window.scrollTo(window.scrollX, window.scrollY - 100);
        }, 10);
    }
})();
MK
fuente
1
Funciona para mí y tiene la ventaja sobre el método css de que se aplica a todas las ubicaciones de hash en una página, por lo que no tiene que escribir un estilo con cada hash incluido y recuerde modificar el estilo cuando agregue otro para con Un nuevo hash. También le permite a uno diseñar el objetivo con un color de fondo sin que esto se extienda 100px (o lo que sea) arriba como en la respuesta de @ user3364768, aunque hay una forma de evitarlo.
David
4

Para vincular a un elemento, y luego 'posicionar' ese elemento a una distancia arbitraria de la parte superior de la página, usando CSS puro, tendrías que usarlo padding-top, de esa manera el elemento todavía está posicionado en la parte superior de la ventana, pero parece , visiblemente, estar ubicado a cierta distancia de la parte superior del puerto de visualización, por ejemplo:

<a href="#link1">Link one</a>
<a href="#link2">Link two</a>

<div id="link1">
    The first.
</div>

<div id="link2">
    The second.
</div>

CSS:

div {
    /* just to force height, and window-scrolling to get to the elements.
       Irrelevant to the demo, really */
    margin-top: 1000px;
    height: 1000px;
}

#link2 {
    /* places the contents of the element 100px from the top of the view-port */
    padding-top: 100px;
}

Demostración de JS Fiddle .

Para usar un enfoque simple de JavaScript:

function addMargin() {
    window.scrollTo(0, window.pageYOffset - 100);
}

window.addEventListener('hashchange', addMargin);

Demostración de JS Fiddle .

David dice reinstalar a Mónica
fuente
1
El único problema con esto es que ahora empuja ese div real más abajo en la página. Idealmente, el enlace de anclaje bajaría 100px menos de lo normal. Estoy dispuesto a usar JS o jQuery si es necesario para lograr esto.
damon
3
Esto no resuelve el problema, simplemente agrega espacios en blanco antes del elemento.
XCS
user1925805: vea la respuesta actualizada para una solución de JavaScript. @Cristy: Lo , expliqué explícitamente que en la respuesta misma: el elemento todavía está posicionado en la parte superior de la ventana, pero parece que está visiblemente a cierta distancia de la parte superior .
David dice que reinstale a Mónica el
La mejor solución limpia con su JS. ¡Gracias, me funciona muy bien!
DanielaB67
Esto solo funciona los cambios de hash ocurridos dentro de la página. Pero el uso se redirigió con ID, entonces esto no funciona
Rohan Khude
4

Esto debería funcionar:

    $(document).ready(function () {
    $('a').on('click', function (e) {
        // e.preventDefault();

        var target = this.hash,
            $target = $(target);

       $('html, body').stop().animate({
        'scrollTop': $target.offset().top-49
    }, 900, 'swing', function () {
    });

        console.log(window.location);

        return false;
    });
});

Simplemente cambie el .top-49 a lo que encaje con su enlace de anclaje.

dMehta
fuente
3

Si usa nombres de ancla explícitos como,

<a name="sectionLink"></a>
<h1>Section<h1>

entonces en CSS puedes simplemente configurar

A[name] {
    padding-top:100px;
}

Esto funcionará siempre que sus etiquetas de anclaje HREF no especifiquen un atributo NAME

Mespr
fuente
Gracias. Esta es la única solución de esta lista que funcionó para mí.
MikeyBunny
3

La respuesta de Eric es genial, pero realmente no necesitas ese tiempo de espera. Si está utilizando jQuery, puede esperar a que se cargue la página. Entonces sugiero cambiar el código a:

// The function actually applying the offset
function offsetAnchor() {
    if (location.hash.length !== 0) {
        window.scrollTo(window.scrollX, window.scrollY - 100);
    }
}

// This will capture hash changes while on the page
$(window).on("hashchange", function () {
    offsetAnchor();
});

// Let the page finish loading.
$(document).ready(function() {
    offsetAnchor();
});

Esto también nos libera de ese factor arbitrario.

rppc
fuente
3

pruebe este código, ya tiene una animación suave cuando hace clic en el enlace.

$(document).on('click', 'a[href^="#"]', function (event) {
    event.preventDefault();

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top - 100
    }, 500);
});
Maricar Onggon
fuente
1

La solución más fácil:

CSS

#link {
    top:-120px; /* -(some pixels above) */
    position:relative;
    z-index:5;
}

HTML

<body>
    <a href="#link">Link</a>
    <div>
        <div id="link"></div> /*this div should placed inside a target div in the page*/
        text
        text
        text
    <div>
</body>
Edalat Mojaveri
fuente
1

Una variante de la solución de Thomas: los elementos CSS > selectores de elementos pueden ser útiles aquí:

CSS

.paddedAnchor{
  position: relative;
}
.paddedAnchor > a{
  position: absolute;
  top: -100px;
}

HTML

<a href="#myAnchor">Click Me!</a>

<span class="paddedAnchor"><a name="myAnchor"></a></span>

Un clic en el enlace moverá la posición de desplazamiento a 100 px arriba donde sea que se encuentre el elemento con una clase de paddedAnchor.

Compatible con navegadores que no son IE, y en IE desde la versión 9. Para compatibilidad con IE 7 y 8, <!DOCTYPE>debe declararse a.

HondaGuy
fuente
1

Acabo de encontrar una solución fácil para mí. Tenía un margen superior de 15 px

HTML

<h2 id="Anchor">Anchor</h2>

CSS

h2{margin-top:-60px; padding-top:75px;}
Gero
fuente
1

Usar solo css y no tener problemas con el contenido cubierto y no cliqueable antes (el punto es los eventos de puntero: ninguno):

CSS

.anchored::before {
    content: '';
    display: block;
    position: relative;
    width: 0;
    height: 100px;
    margin-top: -100px;
}

HTML

<a href="#anchor">Click me!</a>
<div style="pointer-events:none;">
<p id="anchor" class="anchored">I should be 100px below where I currently am!</p>
</div>
dantefff
fuente
1

Pon esto en estilo:

.hash_link_tag{margin-top: -50px; position: absolute;}

y use esta clase en una divetiqueta separada antes de los enlaces, por ejemplo:

<div class="hash_link_tag" id="link1"></div> 
<a href="#link1">Link1</a>

o use este código php para la etiqueta de enlace de eco:

function HashLinkTag($id)
{
    echo "<div id='$id' class='hash_link_tag'></div>";
}
MohsenB
fuente
0

Sé que esto es un poco tarde, pero encontré algo muy importante para poner en su código si está utilizando Bootstrap's Scrollspy. ( http://getbootstrap.com/javascript/#scrollspy )

Esto me estaba volviendo loco por horas.

El desplazamiento para el espía de desplazamiento DEBE coincidir con el window.scrollY o de lo contrario correrá el riesgo de:

  1. Obteniendo un extraño efecto de parpadeo al desplazarse
  2. Encontrarás que cuando hagas clic en las anclas, aterrizarás en esa sección, pero el espía de desplazamiento asumirá que estás en una sección sobre ella.

 var body = $('body');
    body.scrollspy({
        'target': '#nav',
        'offset': 100 //this must match the window.scrollY below or you'll have a bad time mmkay
});

$(window).on("hashchange", function () {
        window.scrollTo(window.scrollX, window.scrollY - 100);
});

beefsupreme
fuente
Sólo js en el fragmento? No funcionará sin importar qué
0

Basado en la solución @Eric Olson , solo modifique un poco para incluir el elemento de anclaje que quiero ir específicamente

// Function that actually set offset
function offsetAnchor(e) {
    // location.hash.length different to 0 to ignore empty anchor (domain.me/page#)
    if (location.hash.length !== 0) {
        // Get the Y position of the element you want to go and place an offset
        window.scrollTo(0, $(e.target.hash).position().top - 150);
    }
}

// Catch the event with a time out to perform the offset function properly
$(document).on('click', 'a[href^="#"]', function (e) {
    window.setTimeout(function () {
        // Send event to get the target id later
        offsetAnchor(e);
    }, 10);
});
Carlos A. Ortiz
fuente
0

Solo tengo el mismo problema. Tengo una navegación colocada pixelada y quiero que el angkor comience debajo de la navegación. La solución window.addEventListener...no funciona para mí porque configuré mi página para scroll-behavior:smoothque establezca el desplazamiento en lugar de desplazarme al angkor. el setTimeout()trabajo si el tiempo es suficiente para desplazarse hasta el final pero aún no se ve bien. entonces mi solución fue agregar un div absoluto posicionado en el angkor, con height:[the height of the nav]y bottom:100%. en este caso, este div terminó en la parte superior del elemento angkor, y comienza en la posición donde se desplaza el angkor. ahora todo lo que hago es establecer el enlace de angkor a este div absoluto y el trabajo hecho :)

html,body{
    margin:0;
    padding:0;
    scroll-behavior:smooth;
}

nav {
    height:30px;
    width:100%;
    font-size:20pt;
    text-align:center;
    color:white;
    background-color:black;
    position:relative;
}

#my_nav{
    position:fixed;
    z-index:3;
}
#fixer_nav{
    position:static;
}

#angkor{
    position:absolute;
    bottom:100%;
    height:30px;
}
<nav id="my_nav"><a href="#angkor">fixed position nav<a/></nav>
<nav id="fixer_nav"></nav>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.
</p>

<nav><div id="angkor"></div>The angkor</nav>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.

</p>

Yosef Tukachinsky
fuente
0

Estaba enfrentando un problema similar y lo resolví usando el siguiente código

$(document).on('click', 'a.page-scroll', function(event) {
        var $anchor = $(this);
        var desiredHeight = $(window).height() - 577;
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top - desiredHeight
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
Umair Mehmood
fuente
-1
<a href="#anchor">Click me!</a>

<div style="margin-top: -100px; padding-top: 100px;" id="anchor"></div>
<p>I should be 100px below where I currently am!</p>
Sportcanon
fuente
44
Esa es esencialmente la misma respuesta que esta . Si publica respuestas a una pregunta anterior, intente agregar algo nuevo. Por ejemplo, podría describir por qué eso funciona.
Artjom B.
1
Yo diría que cualquier respuesta debería tener algún tipo de descripción de por qué funciona. ;-)
Phill Healey