javascript html css anchor offset

javascript - anchor offset html



compensar un anclaje html para ajustar el encabezado fijo (28)

Esta pregunta ya tiene una respuesta aquí:

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.


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.


¿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ín: http://jsfiddle.net/N6f2f/7


Agregando a la respuesta de Ziav (gracias a Alexander Savin), necesito usar el <a name="...">...</a> la vieja escuela, ya que estamos usando <div id="...">...</div> para otro propósito en nuestro código. Tuve algunos problemas de visualización al usar display: inline-block : la primera línea de cada elemento <p> resultó estar ligeramente sangrada (en los navegadores Webkit y Firefox) Terminé probando otros valores de display y display: table-caption funciona perfectamente para mí.

.anchor { padding-top: 60px; margin-top: -60px; display: table-caption; }


Agregué 40px-height .vspace element sosteniendo el ancla antes de cada uno de mis elementos h1 .

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


Al tomar prestado parte del código de una respuesta dada en 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, ajustándose muy bien por debajo de la navegación bootstrap fija barra (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(){ }); });


Aquí está la solución que utilizamos en nuestro sitio. Ajusta la variable headerHeight a la altura de tu cabecera. Agregue la clase js-scroll 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; });


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.

Teniendo esto en cuenta, creo que el uso de JavaScript sigue siendo (febrero de 2017) el mejor enfoque. A continuación se muestra una solución de vanilla-JS que responderá tanto a los clics de anclaje como a la resolución del hash de la página en carga (consulte JSFiddle) . Modifique el método .getFixedOffset() si se requieren cálculos dinámicos. Si está utilizando 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);


Como sugiere @moeffju, esto se puede lograr 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 un div que se encuentra en z-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; }


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 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. Puede o no puede considerar esto deseable.

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


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.


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

  1. 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.
  2. CSS no es mi fuerte.

Escribí este js de desplazamiento simple, que explica el desplazamiento causado por el encabezado y reubicó el div a 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; } } });

Vea una implementación en vivo aquí .


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(); });


Esto toma muchos elementos de las respuestas anteriores y se combina en una pequeña función anónima jQuery (194 bytes minificada). Ajuste fixedElementHeight 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);


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 funcionan de nuevo 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 .


FWIW esto funcionó para mí:

*[id]:before { display: block; content: " "; margin-top: -75px; height: 75px; visibility: hidden; }


La solución @ AlexanderSavin funciona muy bien en los navegadores WebKit para mí.

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

a:target { padding-top: 40px }

Tenga en cuenta que este estilo no es para Chrome / Safari por lo que probablemente tendrá 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 está en inline . Si no quieres un enlace, simplemente puedes cambiar la propiedad de display :

<div id="myanchor" style="display: inline"> <h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1> </div>


Las soluciones con propiedades de posición cambiantes no siempre son posibles (puede destruir el diseño), por lo que 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.


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 con el evento de hashchange ventana para hashchange esto ( demo ):

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: el evento hashchange no está disponible en todos los navegadores.


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 animación opcional, por supuesto.


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: inline-block; height: 180px; margin: -180px 0 0; }


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


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; }


Puede lograr esto sin una ID utilizando el selector css a a[name]:not([href]) . 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; }


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;


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.


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 (incluyendo 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!


Usted podría simplemente 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, convirtiéndolo en un elemento de bloque y posicionándolo relativamente. -250px posicionará el anclaje hasta 250px

a.anchor { display: block; position: relative; top: -250px; visibility: hidden; }


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.