[css] 타겟팅 위치 : 현재 ‘고정’상태에있는 고정 요소

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


답변

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

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


답변

스타일링 (예 : 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;
    });
})


답변

요소 위에 요소가있을 때 간단한 방법입니다 position:sticky. stuckCSS에서 일치시킬 수 있는 속성 을 다음과 같이 설정합니다 header[stuck].

HTML :

<img id="logo" ...>
<div>
  <header style="position: sticky">
    ...
  </header>
  ...
</div>

JS :

if (typeof IntersectionObserver !== 'function') {
  // sorry, IE https://caniuse.com/#feat=intersectionobserver
  return
}

new IntersectionObserver(
  function (entries, observer) {
    for (var _i = 0; _i < entries.length; _i++) {
      var stickyHeader = entries[_i].target.nextSibling
      stickyHeader.toggleAttribute('stuck', !entries[_i].isIntersecting)
    }
  },
  {}
).observe(document.getElementById('logo'))


답변