Pregunta sobre javascript, anchor, html, offset, css – compensar un anclaje html para ajustar el encabezado fijo [duplicado]

944

Esta pregunta ya tiene una respuesta aquí:

El encabezado de página fijo se superpone a los anclajes de página 30 respuestas

Estoy tratando de limpiar la forma en que funcionan mis anclas. Tengo un encabezado que está fijo en la parte superior de la página, por lo que cuando se vincula a un ancla en otra parte de la página, la página salta para que el ancla esté en la parte superior de la página, dejando el contenido detrás del encabezado fijo (espero eso tiene sentido). Necesito una manera de compensar el ancla por 25px desde la altura del encabezado. Preferiría HTML o CSS, pero Javascript también sería aceptable.

La envoltura div se muestra enstackoverflow.com/questions/1431639/… Está bien, creo, no demasiado agresivo. ron
La pregunta que marca este como duplicado no acepta soluciones javascript. Esta pregunta tiene soluciones de script. Debe ser reabierto. Hüseyin Yağlı
Hay un buen artículo sobre este tema:css-tricks.com/hash-tag-links-padding J. Bruni
Re: borrando esta publicación, de SO: esta pregunta no se puede eliminar porque otras preguntas están vinculadas como duplicados de esta. Roy Truelove

Tu respuesta

28   la respuesta
149

Como esta es una preocupación de la presentación, una solución de CSS pura sería ideal. Sin embargo, esta pregunta se planteó en 2012, y aunque se han sugerido soluciones de posicionamiento relativo / margen negativo, estos enfoques parecen bastante complicados, crean posibles problemas de flujo y no pueden responder dinámicamente a los cambios en el DOM / viewport.

Con eso en mente, creo que usar JavaScript estodavía (Febrero 2017) El mejor enfoque. A continuación se muestra una solución de vainilla-JS que responderá tanto a los clics de anclaje como a la resolución del hash de la página en carga.(Ver JSFiddle). Modificar el.getFixedOffset() Método si se requieren cálculos dinámicos. Si estás usando jQuery,Aquí hay una solución modificada con una mejor delegación de eventos y un desplazamiento suave.

(function(document, history, location) {
  var HISTORY_SUPPORT = !!(history && history.pushState);

  var anchorScrolls = {
    ANCHOR_REGEX: /^#[^ ]+$/,
    OFFSET_HEIGHT_PX: 50,

    /**
     * Establish events, and fix initial scroll position if a hash is provided.
     */
    init: function() {
      this.scrollToCurrent();
      window.addEventListener('hashchange', this.scrollToCurrent.bind(this));
      document.body.addEventListener('click', this.delegateAnchors.bind(this));
    },

    /**
     * Return the offset amount to deduct from the normal scroll position.
     * Modify as appropriate to allow for dynamic calculations
     */
    getFixedOffset: function() {
      return this.OFFSET_HEIGHT_PX;
    },

    /**
     * If the provided href is an anchor which resolves to an element on the
     * page, scroll to it.
     * @param  {String} href
     * @return {Boolean} - Was the href an anchor.
     */
    scrollIfAnchor: function(href, pushToHistory) {
      var match, rect, anchorOffset;

      if(!this.ANCHOR_REGEX.test(href)) {
        return false;
      }

      match = document.getElementById(href.slice(1));

      if(match) {
        rect = match.getBoundingClientRect();
        anchorOffset = window.pageYOffset + rect.top - this.getFixedOffset();
        window.scrollTo(window.pageXOffset, anchorOffset);

        // Add the state to history as-per normal anchor links
        if(HISTORY_SUPPORT && pushToHistory) {
          history.pushState({}, document.title, location.pathname + href);
        }
      }

      return !!match;
    },

    /**
     * Attempt to scroll to the current location's hash.
     */
    scrollToCurrent: function() {
      this.scrollIfAnchor(window.location.hash);
    },

    /**
     * If the click event's target was an anchor, fix the scroll position.
     */
    delegateAnchors: function(e) {
      var elem = e.target;

      if(
        elem.nodeName === 'A' &&
        this.scrollIfAnchor(elem.getAttribute('href'), true)
      ) {
        e.preventDefault();
      }
    }
  };

  window.addEventListener(
    'DOMContentLoaded', anchorScrolls.init.bind(anchorScrolls)
  );
})(window.document, window.history, window.location);
Para tu información, alguien puede hackear tu función escribiendo un selector jQuery como el valor href:<a href="#heading1 > .sub-class ul + ul li"> Matthias Dailey
@zipzit - Supongo que él agregó eso antes de que cambiara un poco el enfoque. En ese punto elthis Siempre habría sido el elemento de anclaje el que disparó el evento. Solo está sugiriendo que agregue otra condición para verificar que se trata de un anclaje "estándar", y que no se use una función JS (como un carrusel). Ian Clark
Solucioné el problema donde se hacía clic dos veces en el mismo enlace de anclaje intercambiando la línea interior.delegateAnchors que dicevar elem = e.target; avar elem = e.currentTarget;. No creo que este cambio rompa nada ... Connel
¡Excelente, gracias! También tuve enlaces a otras páginas con anclajes, por ejemplo,/page/#anchor. Este regex cubre esos:/^[\/a-z0-9-]*#[^\s]+$/ tobiv
1025

Podrías usar CSS sin ningún javascript.

Dale a tu ancla una clase:

<a class="anchor" id="top"></a>

Luego, puede colocar el anclaje en un desplazamiento más alto o más bajo que donde realmente aparece en la página, al convertirlo en un elemento de bloque y posicionarlo relativamente. -250px posicionará el anclaje hasta 250px

a.anchor {
    display: block;
    position: relative;
    top: -250px;
    visibility: hidden;
}
Estoy triste, pero tengo un voto útil para dar. A +++ volvería a votar de nuevo. MiDri
@harpo: Buena idea, pero no funciona. Probado en cromo 40. Hannobo
Por alguna razón, JS descompone el cerebro y 50 líneas de JS (que es debatably un hack) para evitar algunas líneas de hack no es una buena programación. El desplazamiento suave [et al] no siempre se desea (rendimiento, pérdida de tiempo en la interfaz de usuario crítica). JS no es siempre la respuesta. Marc
Este es un muy buen enfoque parano-script usuarios ekfuhrmann
87

FWIW esto funcionó para mí:

*[id]:before { 
  display: block; 
  content: " "; 
  margin-top: -75px; 
  height: 75px; 
  visibility: hidden; 
}
No trabaje si tiene una imagen de fondo para su elemento por ejemplo ... (porque el tamaño del elemento cambia con este truco) fred727
Y conserva colapso de márgenes, absolutamente hermoso! Paul
Usted podría agregarposition: relative yz-index: -1 Para evitar que se superponga contenido anterior. Al menos eso me funcionó. kylesimmonds
¡Eres el hombre! Gran solucion Ryan Walton
81

Solución css pura inspirada en Alexander Savin:

a[name] {
  padding-top: 40px;
  margin-top: -40px;
  display: inline-block; /* required for webkit browsers */
}

Opcionalmente, puede agregar lo siguiente si el objetivo aún está fuera de la pantalla:

  vertical-align: top;
@Asrail Para mí no funcionó sin él Hameno
FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
Si hay un enlace justo encima del ancla, no se puede hacer clic. Agregue las siguientes dos reglas: posición: relativo; índice z: -1; sbaechler
Un selector [nombre] no debería verse afectado a los enlaces. Ziav
2

Esto se inspiró en la respuesta de Shouvik: el mismo concepto que el suyo, solo que el tamaño del encabezado fijo no está codificado. Siempre que su encabezado fijo esté en el primer nodo del encabezado, esto debería "simplemente funcionar"

/*jslint browser: true, plusplus: true, regexp: true */

function anchorScroll(fragment) {
    "use strict";
    var amount, ttarget;
    amount = $('header').height();
    ttarget = $('#' + fragment);
    $('html,body').animate({ scrollTop: ttarget.offset().top - amount }, 250);
    return false;
}

function outsideToHash() {
    "use strict";
    var fragment;
    if (window.location.hash) {
        fragment = window.location.hash.substring(1);
        anchorScroll(fragment);
    }
}

function insideToHash(nnode) {
    "use strict";
    var fragment;
    fragment = $(nnode).attr('href').substring(1);
    anchorScroll(fragment);
}

$(document).ready(function () {
    "use strict";
    $("a[href^='#']").bind('click',  function () {insideToHash(this); });
    outsideToHash();
});
Oh, también esta solución supone que el atributo id se usa para el ancla, no el atributo de nombre en desuso. Alice Wonder
Me gusta esta solución, muy modular y muy bien hecha. Oh, extraño los días de JQuery y las manipulaciones de DOM :) traumatized
2

En lugar de tener una barra de navegación de posición fija que esté superpuesta por el resto del contenido de la página (con todo el cuerpo de la página desplazable), considere tener un cuerpo no desplazable con una barra de navegación estática y luego tener el contenido de la página en una posicionamiento absoluto div desplazable por debajo.

Es decir, tener HTML como este ...

<div class="static-navbar">NAVBAR</div>
<div class="scrollable-content">
  <p>Bla bla bla</p>
  <p>Yadda yadda yadda</p>
  <p>Mary had a little lamb</p>
  <h2 id="stuff-i-want-to-link-to">Stuff</h2>
  <p>More nonsense</p>
</div>

... y CSS como este:

.static-navbar {
  height: 100px;
}
.scrollable-content {
  position: absolute;
  top: 100px;
  bottom: 0;
  overflow-y: scroll;
  width: 100%;
}

Esto logra el resultado deseado de una manera directa y no intrincada. La única diferencia de comportamiento entre este y algunos de los hacks inteligentes de CSS sugeridos anteriormente es que la barra de desplazamiento (en los navegadores que representan uno) se adjuntará a la división de contenido en lugar de a la altura total de la página. Usted puede o no puede considerar esto deseable.

Aquí hay un JSFiddle que demuestra esto en acción.

Esta es ABSOLUTAMENTE la mejor solución. No requiere hacks o pseudo-clases. También lo encuentro 100% semántico. Esencialmente, hay una parte de la página en la que desea que se desplace, y la establece explícitamente. Además, resuelve completamente el problema de cómo hacer que los encabezados desaparezcan detrás de las navs sin fondo. abalter
La mejor respuesta para mi. Lo estoy usando ahora. Todas las respuestas aquí son hacky. Agregar un pseudo elemento "antes" a todo no es aceptable para mí y potencialmente puede interferir con muchos otros elementos CSS que ya usan el pseudo elemento "antes". Esta es la forma correcta y limpia de proceder. David
No hacky, pero: (1) completamente inútil fuera de este ejemplo, (2) engorroso de adoptar y mantener, (3) anti-semántico y / o abusivo de css, (4) no intuitivo. Tomaré ellimpiar a:before {...} ¡Solución sobre esto cualquier día! Ярослав Рахматуллин
133

Yo también estaba buscando una solución para esto. En mi caso fue bastante fácil.

Tengo un menú de lista con todos los enlaces:

<ul>
<li><a href="#one">one</a></li>
<li><a href="#two">two</a></li>
<li><a href="#three">three</a></li>
<li><a href="#four">four</a></li>
</ul>

Y debajo de eso los encabezados a donde debe ir.

<h3>one</h3>
<p>text here</p>

<h3>two</h3>
<p>text here</p>

<h3>three</h3>
<p>text here</p>

<h3>four</h3>
<p>text here</p>

Ahora porque tengo un menú fijo en la parte superior de mi página, no puedo hacer que vaya a mi etiqueta porque estaría detrás del menú.

En su lugar, puse una etiqueta de span dentro de mi etiqueta con la identificación adecuada.

<h3><span id="one"></span>one</h3>

Ahora usa 2 líneas de css para posicionarlos correctamente.

h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}

Cambie el valor superior para que coincida con la altura de su encabezado fijo (o más). Ahora asumo que esto también funcionaría con otros elementos.

Realmente me gusta la simplicidad de esta solución. Funciona muy bien. ¡Gracias! Dognoir
Esto funciona muy bien y evita algunos de los problemas con los que me topé con otras técnicas, como cuando utilizo una etiqueta h2 que establece un top de relleno. Jonathan
Utilizo esto, así como un evento JS que escucha los eventos de clic en los anclajes para un desplazamiento suave si JS está disponible. Daniel Dewhurst
Me gusta esta solucion Johan Hoeksma
33

Esto toma muchos elementos de respuestas anteriores y se combina en una pequeña función anónima jQuery (194 bytes minificada). AjustarfijoElementoHeight Para la altura de su menú o elemento de bloqueo.

    (function($, window) {
        var adjustAnchor = function() {

            var $anchor = $(':target'),
                    fixedElementHeight = 100;

            if ($anchor.length > 0) {

                $('html, body')
                    .stop()
                    .animate({
                        scrollTop: $anchor.offset().top - fixedElementHeight
                    }, 200);

            }

        };

        $(window).on('hashchange load', function() {
            adjustAnchor();
        });

    })(jQuery, window);

Si no te gusta la animación, reemplaza

$('html, body')
     .stop()
     .animate({
         scrollTop: $anchor.offset().top - fixedElementHeight
     }, 200);

con:

window.scrollTo(0, $anchor.offset().top - fixedElementHeight);

Versión mejorada:

 !function(o,n){var t=function(){var n=o(":target"),t=100;n.length>0&&o("html, body").stop().animate({scrollTop:n.offset().top-t},200)};o(n).on("hashchange load",function(){t()})}(jQuery,window);
@DavidPrieto cuidado para comprobar que tiene un ancla válida. Funciona con identificaciones bien formadas, no nombres. Por ejemplo, tanto en IE11 como en Edge obtengo longitud = 1 en esta URL:stackoverflow.com/questions/10732690/… Lance
@ Crono1985 ¿Es tu documento HTML 4 o 5? En 4, las ID tenían una lista de caracteres más estricta, por lo que es posible que no se registren como objetivos válidos. A continuación, ¿estás utilizando ID o nombre? En HTML5, ID es un anclaje válido para todas las etiquetas, pero el nombre solo se puede usar en las etiquetas de enlace. Lance
Es el $ (': target'), IE11 devuelve "length": 0, por lo tanto, el código animado no funciona. David Prieto
Realmente no entiendo por qué no funciona en IE11. Es puro HTML5 y nombre de atributo en las etiquetas de enlace. David Prieto
-1

La solución de @ AlexanderSavin funciona muy bien enWebKit navegadores para mi

También tuve que usar:objetivo pseudo-clase que aplica estilo al ancla seleccionada para ajustar el relleno enFF, Opera & IE9:

a:target {
  padding-top: 40px
}

Tenga en cuenta que este estilo no es paraChrome / Safari así que probablemente tendrás que usar css-hacks, comentarios condicionales, etc.

También me gustaría notar que la solución de Alexander funciona debido a que el elemento apuntado esinline. Si no quieres un link simplemente puedes cambiardisplay propiedad:

<div id="myanchor" style="display: inline">
   <h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</div>
@ the0ther me refería a elemento de envoltura no encabezados. También experimentando dificultades para imaginar su marca basada en sus palabras. jibiel
Mis elementos de navegación se vinculan con elementos h2, que son todos de visualización: bloque. Estoy usando Chrome, y no necesité configurar los h2 a inline o inline-block. the0ther
FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
301

Encontré esta solución:

<a name="myanchor">
    <h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</a>

Esto no crea ningún vacío en el contenido y los enlaces de anclaje funcionan realmente bien.

Esa es una gran solución, buen trabajo hermano. Moaz Ateeq
FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
@Mathijs: Tuve el mismo problema. Simplemente lo reemplacé con<a name="myanchor" style="padding-top: 40px; margin-top: -40px;"></a>My anchor y funciona muy bien, sin jQuery (destino de ancla invisible y 0px) xav
El voto negativo como anclajes con el atributo de nombre ya no es compatible con HTML 5, por lo que debe vincularse a la identificación del objeto Stephen Keable
10

Como sugiere @moeffju, esto puede serlogrado con CSS. El problema que encontré (lo que me sorprende que no haya visto) es el truco de superponer elementos anteriores con un relleno o un borde transparente que evita que las acciones se muevan y hagan clic en la parte inferior de esas secciones porque la siguiente aparece más arriba en la orden Z.

La mejor solución que encontré fue colocar el contenido de la sección en undiv eso es enz-index: 1:

// Apply to elements that serve as anchors
.offset-anchor {
  border-top: 75px solid transparent;
  margin: -75px 0 0;
  -webkit-background-clip: padding-box;
  -moz-background-clip: padding;
  background-clip: padding-box;
}

// Because offset-anchor causes sections to overlap the bottom of previous ones,
// we need to put content higher so links aren't blocked by the transparent border.
.container {
  position: relative;
  z-index: 1;
}
29

Me había enfrentado a un problema similar, desafortunadamente después de implementar todas las soluciones anteriores, llegué a la siguiente conclusión.

Mis elementos internos tenían una estructura CSS frágil y la implementación de una posición relativa / juego absoluto, fue romper completamente el diseño de la página.CSS no es mi fuerte.

Escribí este simple js de desplazamiento, que explica el desplazamiento causado por el encabezado y reubicó la división unos 125 píxeles a continuación. Por favor utilízalo como mejor te parezca.

El HTML

<div id="#anchor"></div> <!-- #anchor here is the anchor tag which is on your URL -->

El JavaScript

 $(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') 
&& location.hostname == this.hostname) {

      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top - 125 //offsets for fixed header
        }, 1000);
        return false;
      }
    }
  });
  //Executed on page load with URL containing an anchor tag.
  if($(location.href.split("#")[1])) {
      var target = $('#'+location.href.split("#")[1]);
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top - 125 //offset height of header here too.
        }, 1000);
        return false;
      }
    }
});

Ver unimplementación en vivo aquí.

Incluso después de casi 3 años, esto es perfecto. ¡Gracias, esto ayudó mucho! Jan D
hmmm, no debería ser un problema. La idea es que queremos llamar a esta función después de cargar la ventana en lugar de que la página esté lista. Esto se hace para tomar las imágenes cargadas en perspectiva para desplazarse por la página. Probablemente debería verificar la referencia de jquery, es decir, si el archivo jquery está cargado. Utilizar el$ en lugar deJQuery. Si recibe un error, es probable que no se haya cargado el jQuery. Shouvik
¡Esto funciona perfectamente! Gracias por el codigo user2596635
@Shouvik Cambié 125 a 165 para coincidir con mi sitio ya, pero todavía no se compensa. Tengo el código js en un archivo llamado site.js cuando el archivo se carga en el pie de página, ¿podría ser el problema? ¿Esto tiene que cargar en la sección de la cabeza? También copié su código directamente en mi archivo site.js. El cambio total que hice fue cambiar el $ a jQuery. Robbiegod
9

Para el mismo problema, utilicé una solución fácil: coloque un top de relleno de 40px en cada anclaje.

FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
Gracias, esto fue básicamente lo que terminé haciendo, pero me preguntaba si hay una solución para situaciones en las que agregar un relleno adicional podría ser incómodo. Ben
0

¿qué hay de las etiquetas de span ocultas con ID vinculables que proporcionan la altura de la barra de navegación:

#head1 {
  padding-top: 60px;
  height: 0px;
  visibility: hidden;
}


<span class="head1">somecontent</span>
<h5 id="headline1">This Headline is not obscured</h5>

Heres el violínhttp://jsfiddle.net/N6f2f/7

FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
27

Para los navegadores modernos, simplemente agregue el selector de destino CSS3: a la página. Esto se aplicará a todos los anclajes automáticamente.

:target {
    display: block;    
    position: relative;     
    top: -100px;
    visibility: hidden;
}
agregar este código a la hoja de estilo no hace nada por mí al usar Chrome 60.0.3112.78 en el sitio web en el que estoy trabajando actualmente, aunque eso podría deberse a efectos de interacción ... ¿Podría publicar un bolígrafo? Julix
Incluso podrías hacer:target:before para crear un pseudo-elemento oculto en lugar de ocultar todo el objetivo. Tavian Barnes
Supongo que podría argumentar que IE no es un navegador moderno. De cualquier manera, al usar una clase CSS en lugar del selector de destino, también funciona bien en IE. cdonner
El selector de destino se supone que es compatible desde IE9, pero el desplazamiento solo funciona con FF y Chrome y Safari en mi sitio, no con IE 11. cdonner
8

Tomando prestado parte del código de una respuesta dadaen este enlace (no se especifica ningún autor), puede incluir un buen efecto de desplazamiento suave en el ancla, mientras que se detiene a -60px por encima del ancla, encajando bien debajo de la barra de navegación de arranque (requiere jQuery):

$(".dropdown-menu a[href^='#']").on('click', function(e) {
   // prevent default anchor click behavior
   e.preventDefault();

   // animate
   $('html, body').animate({
       scrollTop: $(this.hash).offset().top - 60
     }, 300, function(){
     });
});
@AdamFriedman incluso encontró una solución para ese escenario específico. Utilizo una biblioteca de smoothanchor a la que puedo agregar un desplazamiento, pero que tampoco funciona en las cargas de página con urls. url # target Todilo
Gracias, esa es la solución para los usuarios de Twitter Bootstrap. Sebastian Viereck
FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
Una solución completa también debe incluir el escenario en el que un usuario carga una nueva página con el ancla ya en la barra de direcciones. Intenté adaptar este código para activarlo en el evento $ (document) .ready, pero aún se está desplazando al lugar equivocado en el documento. ¿Algunas ideas? Adam Friedman
1

Estoy enfrentando este problema en un sitio web de TYPO3, donde todos los "Elementos de contenido" están envueltos con algo como:

<div id="c1234" class="contentElement">...</div>

y cambié la representación para que se muestre así:

<div id="c1234" class="anchor"></div>
<div class="contentElement">...</div>

Y este CSS:

.anchor{
    position: relative;
    top: -50px;
}

La barra superior fija tiene una altura de 40 px, ahora los anclajes vuelven a funcionar y comienzan 10 píxeles por debajo de la barra superior.

El único inconveniente de esta técnica es que ya no se puede usar.:target.

En realidad puedes usar: target como tal:.anchor:target+div lipsumar
0

Puede lograr esto sin una identificación utilizando ela[name]:not([href]) selector css. Esto simplemente busca enlaces con un nombre y sin href, por ejemplo.<a name="anc1"></a>

Una regla de ejemplo podría ser:

a[name]:not([href]){
    display: block;    
    position: relative;     
    top: -100px;
    visibility: hidden;
}
Tenga en cuenta que en HTML5, ela elemento no tienename atributo, por lo que esto no funcionará. Geoff
26
Puedes hacerlo sin js y sin alterar html. Es sólo para CSS.
a[id]:before {
    content:"";
    display:block;
    height:50px;
    margin:-30px 0 0;
}

Eso agregará un pseudo-elemento antes de cada etiqueta-a con un id. Ajuste los valores para que coincida con la altura de su encabezado.

modifiqué esto para seleccionar:target[id]:before ya que los ID a los que estoy anclado-enlace son a veces h1-h6. KFunk
Si alguna vez se ha preguntado por qué no funciona para usted, verifique si el elemento padre no tienefrontera orelleno. byashimov
La altura y el margen negativo deben coincidir, ¿verdad? Facundo Colombier
a [id]: antes se puede cambiar a otra cosa como div [nombre]: antes cannin
Una idea interesante, pero tenga en cuenta que esto arruina la pantalla si tiene vínculos visibles conid's. harpo
9

Las soluciones con propiedades de posición cambiantes no siempre son posibles (puede destruir el diseño), por lo tanto, sugiero esto:

HTML:

<a id="top">Anchor</a>

CSS:

#top {
    margin-top: -250px;
    padding-top: 250px;
}

Utilizar esta:

<a id="top">&nbsp;</a>

para minimizar la superposición, y establecer el tamaño de fuente en 1px. El anclaje vacío no funcionará en algunos navegadores.

0

He añadido 40px-altura.vspace elemento que sostiene el ancla antes de cada uno de mish1 elementos.

<div class="vspace" id="gherkin"></div>
<div class="page-header">
  <h1>Gherkin</h1>
</div>

En el CSS:

.vspace { height: 40px;}

Está funcionando muy bien y el espacio no está repleto.

FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
21

Mi solución combina los selectores de destino y anteriores para nuestro CMS. Otras técnicas no tienen en cuenta el texto en el ancla. Ajuste la altura y el margen negativo al desplazamiento que necesita ...

:target:before {
    content: "";
    display: block;
    height: 180px;
    margin: -180px 0 0;
}
[Resuelto] Esta solución funciona y usé esta solución condisplay: block;. Sin una clase especial, etiqueta vacía o javascript. AmirMehdi KhademAstaneh
Estas dos soluciones CSS no funcionaron a primera vista, pero finalmente lo descubrí.podría no ser compatible con otras propiedades de CSS. Añadió una envoltura y eso solucionó el problema. Combinación de: objetivo: antes con pantalla: el bloque funciona mejor para mí. John
2

Los métodos anteriores no funcionan muy bien si su ancla es un elemento de tabla o dentro de una tabla (fila o celda).

Tuve que usar javascript y enlazar a la ventana.hashchange evento para evitar esto (manifestación):

function moveUnderNav() {
    var $el, h = window.location.hash;
    if (h) {
        $el = $(h);
        if ($el.length && $el.closest('table').length) {
            $('body').scrollTop( $el.closest('table, tr').position().top - 26 );
        }
    }
}

$(window)
    .load(function () {
        moveUnderNav();
    })
    .on('hashchange', function () {
        moveUnderNav();
    });

* Nota lahashchange El evento no está disponible en todos los navegadores.

0

También puede agregar un ancla con seguimiento attr:

(text-indent:-99999px;)
visibility: hidden;
position:absolute;
top:-80px;    

y darle al contenedor padre una posición relativa.

Funciona perfecto para mi.

FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
4

Me encontré con este mismo problema y terminé manejando los eventos de clic manualmente, como:

$('#mynav a').click(() ->
  $('html, body').animate({
      scrollTop: $($(this).attr('href')).offset().top - 40
  }, 200
  return false
)

Desplazamiento de la animación opcional, por supuesto.

FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
Este javascript ni siquiera es válido, entiendo el mensaje que intentas transmitir. Pero por lo menos debe tener llaves y sintaxis válidos para ser una respuesta legítima. gzimmers
0

Agregando a la respuesta de Ziav (gracias a Alexander Savin), necesito usar la vieja escuela<a name="...">...</a> como estamos usando<div id="...">...</div> para otro propósito en nuestro código. Tuve algunos problemas de visualización usandodisplay: inline-block - la primera línea de cada<p> El elemento se estaba volviendo ligeramente sangrado a la derecha (en los navegadores Webkit y Firefox). Terminé probando otrodisplay valores ydisplay: table-caption funciona perfectamente para mi

.anchor {
  padding-top: 60px;
  margin-top: -60px;
  display: table-caption;
}
FYI: fusionado destackoverflow.com/questions/9047703/… Shog9
0

Un giro adicional a la excelente respuesta de @Jan es incorporar esto en el encabezado fijo #uberbar, que usa jQuery (o MooTools). (http://davidwalsh.name/persistent-header-opacity)

He ajustado el código para que la parte superior del contenido esté siempre debajo, no debajo del encabezado fijo y también agregué los anclajes de @Jan, asegurándome de que los anclajes estén siempre ubicados debajo del encabezado fijo.

El CSS:

#uberbar { 
    border-bottom:1px solid #0000cc; 
    position:fixed; 
    top:0; 
    left:0; 
    z-index:2000; 
    width:100%;
}

a.anchor {
    display: block;
    position: relative;
    visibility: hidden;
}

El jQuery (incluidos los ajustes tanto para el #uberbar como para el ancla se acerca:

<script type="text/javascript">
$(document).ready(function() {
    (function() {
        //settings
        var fadeSpeed = 200, fadeTo = 0.85, topDistance = 30;
        var topbarME = function() { $('#uberbar').fadeTo(fadeSpeed,1); }, topbarML = function() { $('#uberbar').fadeTo(fadeSpeed,fadeTo); };
        var inside = false;
        //do
        $(window).scroll(function() {
            position = $(window).scrollTop();
            if(position > topDistance && !inside) {
                //add events
                topbarML();
                $('#uberbar').bind('mouseenter',topbarME);
                $('#uberbar').bind('mouseleave',topbarML);
                inside = true;
            }
            else if (position < topDistance){
                topbarME();
                $('#uberbar').unbind('mouseenter',topbarME);
                $('#uberbar').unbind('mouseleave',topbarML);
                inside = false;
            }
        });
        $('#content').css({'margin-top': $('#uberbar').outerHeight(true)});
        $('a.anchor').css({'top': - $('#uberbar').outerHeight(true)});
    })();
});
</script>

Y finalmente el HTML:

<div id="uberbar">
    <!--CONTENT OF FIXED HEADER-->
</div>
....
<div id="content">
    <!--MAIN CONTENT-->
    ....
    <a class="anchor" id="anchor1"></a>
    ....
    <a class="anchor" id="anchor2"></a>
    ....
</div>

¡Tal vez esto sea útil para alguien a quien le guste el encabezado dixed #uberbar fading!

-1

Aquí está la solución que utilizamos en nuestro sitio. Ajustar elheaderHeight variable a cualquiera que sea su altura de cabecera. Añade eljs-scroll Clase al ancla que debe desplazarse al hacer clic.

// SCROLL ON CLICK
// --------------------------------------------------------------------------
$('.js-scroll').click(function(){
    var headerHeight = 60;

    $('html, body').animate({
        scrollTop: $( $.attr(this, 'href') ).offset().top - headerHeight
    }, 500);
    return false;
});

Preguntas relacionadas