Потяните, чтобы показать

"Потяните, чтобы увидеть" – это шаблон пользовательского интерфейса, в котором контент (например, строка поиска или элемент управления обновлением) скрыт над верхней частью прокручиваемой области при начальной загрузке, и пользователь может потянуть вниз (прокрутить вверх), чтобы увидеть его. Этот шаблон обычно используется в мобильных и веб-приложениях для строк поиска, фильтров и других дополнительных элементов управления, которые должны быть доступны, но не сразу видны.

Свойство CSS scroll-initial-target предлагает декларативный способ реализации этого шаблона только на CSS. Если задать scroll-initial-target: nearest для элемента основного контента, контейнер прокрутки будет отображаться со скрытым контентом, прокрученным за пределы видимости. Раньше для этого разработчики использовали JavaScript (Element.scrollIntoView()) или идентификаторы фрагментов URL (#content-id). Однако оба этих способа имеют ограничения и сложны в реализации.

Как реализовать

Чтобы реализовать шаблон "Потяните, чтобы увидеть":

  1. Убедитесь, что контейнер прокрутки существует. Целевой элемент должен находиться внутри контейнера прокрутки (элемента с переполнением, который позволяет прокручивать, например overflow: auto). Это может быть любой элемент-предок, включая корневой элемент <html>.
  2. Определите скрытый элемент. Поместите контент, который хотите скрыть (например, строку поиска), в качестве первого дочернего элемента внутри контейнера прокрутки. При первоначальной загрузке этот элемент будет прокручен за пределы видимой области.
  3. Определите основной контент. Разместите элемент основного контента сразу после скрытого элемента. Это элемент, который пользователь должен увидеть в первую очередь.
  4. Таргетинг на основной контент. Примените scroll-initial-target: nearest к основному элементу контента, чтобы контейнер прокрутки отображался вместе с ним, скрывая элемент над ним.
  5. Добавьте привязку прокрутки. Чтобы скрытый элемент всегда был либо полностью виден, либо полностью скрыт (и не оставался в частично прокрученном состоянии), добавьте scroll-snap-type: y mandatory в контейнер прокрутки и scroll-snap-align: start как в скрытый элемент, так и в элемент основного контента.
/**
 * ANCESTOR: Define the scroll container.
 * Scroll snapping ensures the search bar is always
 * either fully visible or fully hidden.
 */
.scroll-container {
  height: 100vh;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}

/**
 * HIDDEN ELEMENT: The search bar hidden above the fold on load.
 * It has scroll-snap-align so it snaps into place when pulled down.
 */
.search-bar {
  height: 60px;
  scroll-snap-align: start;
}

/**
 * MAIN CONTENT + TARGET: The element the user sees first.
 * scroll-snap-align makes it a valid snap point.
 * scroll-initial-target tells the browser to scroll here on
 * initial render, hiding the search bar above it.
 */
.main-content {
  scroll-snap-align: start;
  scroll-initial-target: nearest;
}

Стратегическое внедрение и рекомендации

  • РЕКОМЕНДУЕТСЯ использовать scroll-initial-target: nearest, если вы хотите привлечь внимание пользователя к определенной части прокручиваемой области при загрузке и намеренно скрыть периферийные элементы интерфейса, например строку поиска в самом верху.
  • НЕ путайте его с фокусом специальных возможностей. Это свойство перемещает только визуальную область просмотра, но не фокус клавиатуры. Если целевой элемент должен быть начальной точкой для пользователей клавиатуры, вам нужно вручную управлять element.focus().
  • НЕ используйте это свойство, если вам нужна плавная анимация прокрутки при загрузке. Оно является дискретным и мгновенно задает позицию на этапе макета.
  • НЕ устанавливайте scroll-initial-target для нескольких элементов в одном прокручиваемом контейнере. Если атрибут scroll-initial-target: nearest указан для нескольких элементов, браузер выберет тот, который находится выше в дереве DOM.
  • УЧИТЫВАЙТЕ иерархию приоритетов. Фрагмент URL (например, example.com/#top) и свойство scroll-start на уровне контейнера имеют приоритет над scroll-initial-target.

Резервная стратегия

Для браузеров, которые пока не поддерживают API, используйте резервный вариант JavaScript. Обратите внимание, что для раскрытия контента при перетаскивании основной контент должен быть привязан к start (верхней части) контейнера.

/**
 * Progressive Enhancement Fallback
 */
document.addEventListener("DOMContentLoaded", () => {
  // Check for native CSS support
  if (!CSS.supports("scroll-initial-target", "nearest")) {
    const targetContent = document.querySelector('.main-content.target');
    if (targetContent) {
      // Use behavior: "instant" to mimic the native CSS behavior
      // 'block: start' should match your CSS 'scroll-snap-align' (or expected top position)
      targetContent.scrollIntoView({ behavior: 'instant', block: 'start' });
    }
  }
});