your programing

고정 헤더에 맞게 조정하기 위해 html 앵커 오프셋

lovepro 2020. 9. 27. 13:36
반응형

고정 헤더에 맞게 조정하기 위해 html 앵커 오프셋 [중복]


이 질문에 이미 답변이 있습니다.

앵커가 작동하는 방식을 정리하려고합니다. 페이지 상단에 고정 된 헤더가 있으므로 페이지의 다른 위치에 앵커에 연결하면 페이지가 점프하여 앵커가 페이지 상단에 있고 콘텐츠는 고정 헤더 뒤에 남습니다. 의미가 있습니다). 헤더 높이에서 25px만큼 앵커를 오프셋하는 방법이 필요합니다. HTML이나 CSS를 선호하지만 Javascript도 허용됩니다.


자바 스크립트없이 CSS 만 사용할 수 있습니다.

앵커에게 수업을 제공하십시오.

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

그런 다음 앵커를 블록 요소로 만들고 상대적으로 배치하여 앵커를 페이지에 실제로 표시되는 위치보다 높거나 낮은 오프셋으로 배치 할 수 있습니다. -250px는 앵커를 250px 위로 배치합니다.

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

이 해결책을 찾았습니다.

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

이것은 콘텐츠에 어떤 간격도 만들지 않으며 앵커 링크는 정말 훌륭하게 작동합니다.


이것은 표현의 문제이므로 순수한 CSS 솔루션이 이상적입니다. 그러나이 질문은 2012 년에 제기되었으며 상대적 위치 / 음의 마진 솔루션이 제안되었지만 이러한 접근 방식은 다소 불안정 해 보이고 잠재적 인 흐름 문제를 일으키며 DOM / 뷰포트의 변경에 동적으로 응답 할 수 없습니다.

이를 염두에두고 JavaScript를 사용하는 것이 여전히 (2017 년 2 월) 최선의 방법 이라고 생각합니다 . 다음은 앵커 클릭에 응답하고로드시 페이지 해시를 해결하는 vanilla-JS 솔루션입니다 (JSFiddle 참조) . .getFixedOffset()동적 계산이 필요한 경우 방법을 수정하십시오 . jQuery를 사용하는 경우 더 나은 이벤트 위임과 부드러운 스크롤 기능을 갖춘 수정 된 솔루션이 있습니다.

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

나는 이것에 대한 해결책을 찾고 있었다. 제 경우에는 꽤 쉬웠습니다.

모든 링크가있는 목록 메뉴가 있습니다.

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

그리고 그 아래에는 그것이 가야 할 제목이 있습니다.

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

이제 내 페이지 상단에 고정 메뉴가 있기 때문에 메뉴 뒤에 있기 때문에 태그로 이동할 수 없습니다.

대신 적절한 ID로 내 태그 안에 스팬 태그를 넣었습니다.

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

이제 2 줄의 CSS를 사용하여 적절하게 배치합니다.

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

고정 헤더의 높이 (또는 그 이상)와 일치하도록 상단 값을 변경합니다. 이제 나는 이것이 다른 요소에서도 작동한다고 가정합니다.


FWIW 이것은 나를 위해 일했습니다.

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

Alexander Savin에서 영감을 얻은 순수한 CSS 솔루션 :

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

선택적으로 대상이 화면 밖에있는 경우 다음을 추가 할 수 있습니다.

  vertical-align: top;

이것은 이전 답변에서 많은 요소를 취하고 작은 (194 바이트 축소) 익명 jQuery 함수로 결합됩니다. 메뉴 또는 차단 요소의 높이에 대해 fixedElementHeight조정 하십시오.

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

애니메이션이 마음에 들지 않으면

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

와:

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

Uglified 버전 :

 !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);

내 솔루션은 CMS에 대한 대상 및 이전 선택기를 결합합니다. 다른 기술은 앵커의 텍스트를 고려하지 않습니다. 높이와 음수 여백을 필요한 오프셋으로 조정하십시오.

:target::before {
    content: '';
    display: block;
    height:      180px;
    margin-top: -180px;
}

불행히도 위의 모든 솔루션을 구현 한 후 비슷한 문제에 직면 해 있었고 다음과 같은 결론에 도달했습니다.

  1. 내 내부 요소는 깨지기 쉬운 CSS 구조를 가지고 있고 위치 상대 / 절대 플레이를 구현하여 페이지 디자인을 완전히 깨뜨 렸습니다.
  2. CSS는 저의 강점이 아닙니다.

이 간단한 스크롤 js를 작성하여 헤더로 인한 오프셋을 설명하고 div를 약 125 픽셀 아래로 재배치했습니다. 적합하다고 생각되는대로 사용하십시오.

HTML

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

자바 스크립트

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

여기 에서 라이브 구현을 참조 하십시오 .


최신 브라우저의 경우 페이지에 CSS3 : target 선택기를 추가하기 만하면됩니다. 이는 모든 앵커에 자동으로 적용됩니다.

:target {
    display: block;    
    position: relative;     
    top: -100px;
    visibility: hidden;
}

js없이 html을 변경하지 않고도 할 수 있습니다. CSS 전용입니다.

a[id]::before {
    content: '';
    display: block;
    height: 50px;
    margin: -30px 0 0;
}

그러면 ID가있는 모든 a- 태그 앞에 의사 요소가 추가됩니다. 머리글 높이와 일치하도록 값을 조정합니다.


@moeffju가 제안했듯이 이것은 CSS달성 할 수 있습니다 . 내가 만났던 문제 (내가 논의하지 않은 것에 놀랐습니다)는 패딩으로 이전 요소를 겹치는 트릭이거나 투명한 테두리가 해당 섹션의 맨 아래에서 마우스 오버 및 클릭 동작을 방지하는 것입니다. z 순서.

내가 찾은 가장 좋은 해결책은 다음 위치에 섹션 콘텐츠를 배치하는 div것입니다 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;
}

위치 속성을 변경하는 솔루션이 항상 가능한 것은 아니므로 (레이아웃을 파괴 할 수 있음) 다음을 제안합니다.

HTML :

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

CSS :

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

이것을 사용하십시오 :

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

겹침을 최소화하고 글꼴 크기를 1px로 설정합니다. 빈 앵커는 일부 브라우저에서 작동하지 않습니다.


같은 문제에 대해 저는 쉬운 해결책을 사용했습니다. 각 앵커에 40px의 패딩 상단을 두는 것입니다.


이 링크에 제공된 답변에서 일부 코드를 빌리면 (작성자가 지정되지 않음) 앵커에 멋진 부드러운 스크롤 효과를 포함 할 수 있으며 고정 된 부트 스트랩 탐색 아래에 잘 맞도록 앵커 위 -60px에서 멈출 수 있습니다. bar (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(){
     });
});

이 같은 문제가 발생하여 다음과 같이 클릭 이벤트를 수동으로 처리했습니다.

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

물론 스크롤 애니메이션은 선택 사항입니다.


위의 방법은 앵커가 표 요소이거나 표 (행 또는 셀) 내에있는 경우 잘 작동하지 않습니다.

이 문제를 해결하기 위해 자바 스크립트를 사용하고 창 hashchange이벤트에 바인딩해야 했습니다 ( 데모 ).

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

* 참고 : 일부 브라우저에서는 hashchange 이벤트를 사용할 수 없습니다.


이것은 Shouvik의 대답에서 영감을 얻었습니다. 그의 개념과 동일한 개념이며 고정 헤더의 크기 만 하드 코딩되지 않았습니다. 고정 헤더가 첫 번째 헤더 노드에있는 한 "그냥 작동"합니다.

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

페이지의 나머지 콘텐츠 (전체 페이지 본문이 스크롤 가능)에 의해 아래에있는 고정 위치 탐색 모음을 사용하는 대신 정적 탐색 모음이있는 스크롤 할 수없는 본문을 사용하고 페이지 콘텐츠를 아래의 절대 위치 스크롤 가능 div.

즉, 다음과 같은 HTML이 있습니다.

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

... 그리고 CSS는 다음과 같습니다.

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

이것은 간단하고 해킹이 아닌 방식으로 원하는 결과를 얻습니다. 이것과 위에서 제안 된 일부 영리한 CSS 해킹 사이의 동작의 유일한 차이점은 스크롤바 (하나를 렌더링하는 브라우저에서)가 페이지의 전체 높이가 아닌 콘텐츠 div에 첨부된다는 것입니다. 이것이 바람직하다고 생각할 수도 있고 생각하지 않을 수도 있습니다.

다음은이를 실제로 보여주는 JSFiddle입니다.


모든 "콘텐츠 요소"가 다음과 같이 래핑 된 TYPO3 웹 사이트에서이 문제에 직면하고 있습니다.

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

다음과 같이 렌더링되도록 렌더링을 변경했습니다.

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

그리고이 CSS :

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

고정 상단 막대는 40px 높이이므로 이제 앵커가 다시 작동하고 상단 막대 아래에서 10px 시작됩니다.

이 기술의 유일한 단점은 더 이상 사용할 수 없다는 것 :target입니다.


a[name]:not([href])css 선택기를 사용하여 ID없이이를 수행 할 수 있습니다 . 이것은 단순히 이름이 있고 href가없는 링크를 찾습니다.<a name="anc1"></a>

예제 규칙은 다음과 같습니다.

a[name]:not([href]){
    display: block;    
    position: relative;     
    top: -100px;
    visibility: hidden;
}

Ziav의 답변 (Alexander Savin 덕분에) 에 추가 <a name="...">...</a>하여 <div id="...">...</div>코드에서 다른 목적 으로 사용하고 있으므로 구식을 사용해야 합니다. 나는 몇 가지 디스플레이 문제가 있었다. display: inline-block모든 <p>요소 의 첫 번째 줄은 약간 오른쪽 들여 쓰기로 판명되었다 (웹킷과 파이어 폭스 브라우저 모두에서). 나는 결국 다른 display가치관 을 시도하고 display: table-caption나를 위해 완벽하게 작동합니다.

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

.vspaceh1요소 앞에 앵커를 들고있는 40px 높이의 요소를 추가했습니다 .

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

CSS에서 :

.vspace { height: 40px;}

훌륭하게 작동하고 공간이 꽉 막히지 않습니다.


navbar의 높이를 제공하는 링크 가능한 ID가있는 숨겨진 스팬 태그는 어떻습니까?

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


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

여기 바이올린 : http://jsfiddle.net/N6f2f/7


다음 속성을 사용하여 앵커를 추가 할 수도 있습니다.

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

부모 컨테이너에 상대적 위치를 제공하십시오.

나를 위해 완벽하게 작동합니다.


@Jan의 탁월한 답변에 대한 추가 트위스트는 jQuery (또는 MooTools)를 사용하는 #uberbar 고정 헤더에이를 통합하는 것입니다. ( http://davidwalsh.name/persistent-header-opacity )

콘텐츠의 상단이 항상 고정 헤더 아래가 아닌 아래에 있도록 코드를 수정했으며 앵커가 항상 고정 헤더 아래에 위치하도록 @Jan의 앵커를 다시 추가했습니다.

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

jQuery (#uberbar 및 앵커 접근 방식에 대한 조정 포함 :

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

그리고 마지막으로 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>

아마도 이것은 #uberbar 페이딩 딕스 헤더를 좋아하는 사람에게 유용 할 것입니다!


@AlexanderSavin의 솔루션은 WebKit브라우저에서 잘 작동 합니다.

추가로 선택한 앵커에 스타일을 적용하여 패딩을 조정 하는 : target pseudo-class FF, Opera& IE9:

a:target {
  padding-top: 40px
}

이 스타일은 Chrome/ Safari용이 아니므로 css-hacks, 조건부 주석 등을 사용해야합니다.

또한 Alexander의 솔루션은 타겟 요소가 inline. 링크를 원하지 않으면 간단히 display속성을 변경할 수 있습니다.

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

우리 사이트에서 사용하는 솔루션은 다음과 같습니다. headerHeight헤더 높이가 무엇이든 변수를 조정하십시오 . js-scroll클릭시 스크롤해야하는 앵커에 클래스를 추가합니다 .

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

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

참고 URL : https://stackoverflow.com/questions/10732690/offsetting-an-html-anchor-to-adjust-for-fixed-header

반응형