it-swarm.com.ru

Позиция таргетинга: липкие элементы, которые в данный момент находятся в "застрявшем" состоянии

position: sticky теперь работает в некоторых мобильных браузерах, так что вы можете сделать прокрутку строки меню со страницей, но затем придерживаться верхней части области просмотра всякий раз, когда пользователь прокручивает ее.

Но что, если вы хотите немного изменить стиль своей липкой строки меню, когда она в данный момент «залипает»? например, вы можете захотеть, чтобы полоса имела закругленные углы при прокрутке страницы, но затем, как только она прилипнет к вершине области просмотра, вы захотите избавиться от верхних закругленных углов и добавить небольшую тень под ним. Это.

Есть ли какой-либо псевдоселектор (например, ::stuck) для целевых элементов, которые имеют position: stickyи, которые в настоящее время придерживаются? Или у производителей браузеров есть что-то подобное в процессе разработки? Если нет, то где бы я его попросил?

NB. Решения javascript не годятся для этого, потому что на мобильном устройстве вы обычно получаете только одно событие scroll, когда пользователь отпускает палец, поэтому JS не может знать точный момент, когда был пройден порог прокрутки.

58
callum

В настоящее время не существует селектора, который предлагается для элементов, которые в данный момент «застряли». Модуль Postioned Layout , где position: sticky определен, также не упоминает ни один такой селектор.

Запросы функций для CSS можно публиковать в список рассылки в стиле www . Я полагаю, что псевдо-класс :stuck имеет больше смысла, чем псевдоэлемент ::stuck, поскольку вы пытаетесь настроить таргетинг на сами элементы, пока они находятся в этом состоянии. Фактически, псевдокласс :stuck обсуждался некоторое время назад ; было обнаружено, что основным осложнением является то, что оно касается практически любого предлагаемого селектора, который пытается сопоставить на основе визуализированного или вычисляемого стиля: циклические зависимости.

В случае псевдокласса :stuck самый простой случай округлости произошел бы со следующим CSS:

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

И может быть еще много случаев Edge, которые будет трудно рассмотреть.

Хотя в целом принято считать, что наличие селекторов, совпадающих на основе определенных состояний макета, будет Nice, к сожалению, существуют серьезные ограничения, которые делают их нетривиальными для реализации. Я бы не стал задерживаться на чистом CSS-решении этой проблемы в ближайшее время.

64
BoltClock

На самом деле не фанат использования js-хаков для стилевого оформления (например, getBoudingClientRect, прослушивание с прокруткой, прослушивание с изменением размера), но именно так я сейчас решаю проблему. Это решение будет иметь проблемы со страницами, которые имеют минимизируемый/максимизируемый контент (<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;
    });
})
2
Seph Reed

Кто-то в блоге разработчиков Google утверждает, что нашел эффективное решение на основе JavaScript с IntersectionObserver .

Соответствующий бит кода здесь:

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

Я не повторил это сам, но, может быть, это поможет кому-то наткнуться на этот вопрос.

0
neo post modern