IT TIP

타겟팅 위치 : 현재 '멈춤'상태에있는 고정 요소

itqueen 2020. 10. 24. 12:11
반응형

타겟팅 위치 : 현재 '멈춤'상태에있는 고정 요소


position : sticky 는 이제 일부 모바일 브라우저에서 작동하므로 페이지와 함께 메뉴 막대를 스크롤 할 수 있지만 사용자가 스크롤 할 때마다 뷰포트 상단에 고정 할 수 있습니다.

그러나 현재 '고정'상태 일 때마다 고정 메뉴 막대의 스타일을 약간 변경하려면 어떻게해야합니까? 예를 들어, 페이지와 함께 스크롤 할 때마다 막대가 둥근 모서리를 갖기를 원할 수 있지만, 뷰포트의 상단에 달라 붙 자마자 상단의 둥근 모서리를 제거하고 그 아래에 약간의 그림자를 추가 할 수 있습니다. 그것.

pseudoselector (예를 들어, 어떤 종류가 있습니까 ::stuck이 대상 요소) position: sticky 현재 숨어있다가? 아니면 브라우저 공급 업체가 파이프 라인에 이와 같은 것이 있습니까? 그렇지 않은 경우 어디에서 요청합니까?

NB. 모바일에서는 일반적으로 scroll사용자가 손가락을 뗄 때 하나의 이벤트 만 수신되므로 자바 스크립트 솔루션은 이에 적합하지 않습니다 . 따라서 JS는 스크롤 임계 값이 전달 된 정확한 순간을 알 수 없습니다.


현재 '고착'된 요소에 대해 제안되는 선택기가 없습니다. Postioned 레이아웃 모듈position: sticky 정의는 하나 그러한 선택을 언급하지 않습니다.

CSS에 대한 기능 요청은 www 스타일 메일 링리스트에 게시 할 수 있습니다 . 나는 :stuck가상 클래스가 ::stuck가상 요소 보다 더 합리적 이라고 생각합니다 . 그 상태에있는 동안 요소 자체를 대상으로하기 때문입니다. 사실, :stuck의사 클래스는 얼마 전에 논의 되었습니다 . 발견 된 주요 문제는 렌더링되거나 계산 된 스타일을 기반으로 일치를 시도하는 제안 된 선택기 (순환 종속성)를 괴롭히는 문제입니다.

a의 경우에는 :stuck의사 클래스, 원형의 간단한 경우는 다음과 같은 CSS 발생할 것입니다 :

:stuck { position: static; /* Or anything other than sticky/fixed */ }
:not(:stuck) { position: sticky; /* Or fixed */ }

그리고 해결하기 어려운 더 많은 엣지 케이스가있을 수 있습니다.

일반적으로 특정 레이아웃 상태를 기반으로 일치하는 선택기를 갖는 것이 좋을 것이라는 데 동의하지만 , 불행히도 이러한 구현을 사소하지 않게 만드는 주요 제한 사항이 있습니다. 조만간이 문제에 대한 순수한 CSS 솔루션을 위해 숨을 참지 않을 것입니다.


IntersectionObserver상황이 적절하게 플러시하는 대신 루트 컨테이너 외부의 픽셀 또는 두 개에 고정 할 수있는 경우 간단한 방법으로 트릭을 수행 할 수 있습니다. 그런 식으로 가장자리 바로 너머에있을 때 관찰자가 발사되고 우리는 도망 가게됩니다.

const observer = new IntersectionObserver( 
  ([e]) => e.target.toggleAttribute('stuck', e.intersectionRatio < 1),
  {threshold: [1]}
);

observer.observe(document.querySelector('nav'));

을 사용하여 컨테이너 외부에 요소를 붙인 top: -2px다음 stuck속성을 통해 대상을 지정 합니다.

nav {
  background: magenta;
  height: 80px;
  position: sticky;
  top: -2px;
}
nav[stuck] {
  box-shadow: 0 0 16px black;
}

예 : https://codepen.io/anon/pen/vqyQEK


스타일링 (예 : getBoudingClientRect, 스크롤 리스닝, 크기 조정 리스닝)에 js 해킹을 사용하는 팬은 아니지만 이것이 현재 문제를 해결하는 방법입니다. 이 솔루션은 최소화 / 최대화 가능한 콘텐츠 (<details>), 중첩 스크롤 또는 실제로 모든 커브 볼이있는 페이지에 문제가 있습니다. 즉, 문제가 단순 할 때도 간단한 해결책입니다.

let lowestKnownOffset: number = -1;
window.addEventListener("resize", () => lowestKnownOffset = -1);

const $Title = document.getElementById("Title");
let requestedFrame: number;
window.addEventListener("scroll", (event) => {
    if (requestedFrame) { return; }
    requestedFrame = requestAnimationFrame(() => {
        // if it's sticky to top, the offset will bottom out at its natural page offset
        if (lowestKnownOffset === -1) { lowestKnownOffset = $Title.offsetTop; }
        lowestKnownOffset = Math.min(lowestKnownOffset, $Title.offsetTop);
        // this condition assumes that $Title is the only sticky element and it sticks at top: 0px
        // if there are multiple elements, this can be updated to choose whichever one it furthest down on the page as the sticky one
        if (window.scrollY >= lowestKnownOffset) {
            $Title.classList.add("--stuck");
        } else {
            $Title.classList.remove("--stuck");
        }
        requestedFrame = undefined;
    });
})

Google Developers 블로그의 누군가IntersectionObserver를 사용하여 수행 가능한 JavaScript 기반 솔루션을 찾았다 고 주장합니다 .

여기에 관련 코드 비트 :

/**
 * Sets up an intersection observer to notify when elements with the class
 * `.sticky_sentinel--top` become visible/invisible at the top of the container.
 * @param {!Element} container
 */
function observeHeaders(container) {
  const observer = new IntersectionObserver((records, observer) => {
    for (const record of records) {
      const targetInfo = record.boundingClientRect;
      const stickyTarget = record.target.parentElement.querySelector('.sticky');
      const rootBoundsInfo = record.rootBounds;

      // Started sticking.
      if (targetInfo.bottom < rootBoundsInfo.top) {
        fireEvent(true, stickyTarget);
      }

      // Stopped sticking.
      if (targetInfo.bottom >= rootBoundsInfo.top &&
          targetInfo.bottom < rootBoundsInfo.bottom) {
       fireEvent(false, stickyTarget);
      }
    }
  }, {threshold: [0], root: container});

  // Add the top sentinels to each section and attach an observer.
  const sentinels = addSentinels(container, 'sticky_sentinel--top');
  sentinels.forEach(el => observer.observe(el));
}

나는 그것을 스스로 복제하지는 않았지만 누군가이 질문에 걸림돌이되는 데 도움이 될 수 있습니다.

참고 URL : https://stackoverflow.com/questions/25308823/targeting-positionsticky-elements-that-are-currently-in-a-stuck-state

반응형