Проблемы с position: sticky CSS и способ их решить

Проблемы с position: sticky CSS и способ их решить

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

Липкие элементы или фиксированные панели часто используются в программах — особенно в приложениях на основе строк / столбцов, таких как Microsoft Excel. CSS position: sticky также широко используется в мобильных (нативных) приложениях и в веб-дизайне. Такие элементы помогают пользователям сохранять чувство перспективы при сортировке длинных списков или отслеживании деталей своих заказов при совершении покупок в Интернете.

Старый способ

Указать элементу, чтобы он вел себя липко и статично в окне браузера, было довольно сложно. До того, как (современные) браузеры представили нативное решение, нам приходилось прибегать к имитации поведения с помощью привязки (например, для заголовков, боковых панелей и т. д.) через javascript и position: fixed;. Javascript прослушивает события прокрутки и положение элемента в документе, и как только добавляется математика, вы вводите класс, скажем, «sticky», который назначает элементу position: fixed;, что приводит к тому, что элемент прилипание в соответствии с вашими инструкциями.

Довольно сложная техника для чего-то (что должно быть) достаточно простого. Этот метод имеет несколько (отчасти) очевидных ошибок:

элемент не расположен в потоке документа, что вызывает скачок, когда он становится в статическую позицию, и

потенциальное снижение производительности в результате непрерывных перерисовок и обратных вызовов из-за события прокрутки (вы могли бы справиться с проблемами производительности, используя такие методы, как дросселирование, отскок или даже Intersection Observer.

Способ sticky

Удобство этого метода заключается в том, что браузер делает всю тяжелую работу за вас. Элемент беспрепятственно участвует в потоке документа, а также фиксируется в окне, когда вы прокручиваете страницу, не вызывая внезапного скачка.

Вы можете сделать это с помощью четырех строк кода:

.element { position: sticky; top: 0;
}

Просто! Однако могут возникнуть трудности — особенно если мы введем переполнения.

Проблемы с переполнением

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

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

Проблема с переполнением заключается в том… что липкий элемент «прилипает» к своему прямому родительскому элементу, который имеет «механизм прокрутки» (создаваемый, когда для overflow задано hidden, scroll, auto или overlay), даже если этот предок не является фактически прокручиваемым элементом. Это подавляет любое «липкое» поведение. (Из MDN Web Docs)

Такое поведение воспроизведено в этом коде от Валттери Лайтинен:

Это именно то, что нам нужно, но заголовки не прилипают, когда мы вертикально прокручиваем таблицу. Если родительский контейнер имеет свойство overflow, у нас возникают проблемы. Как только вы удалите overflow, заголовки встанут, как нужно (попробуйте установить флажок). Так как мы можем справиться с этим?

Добавить фиксированную высоту

Покопавшись в Интернете, я нашел полезное предложение: указать высоту в нашем контейнере с переполняющим размеры содержимым. В этой упрощенной версии мы установили фиксированную высоту для контейнера:

Несмотря на то, что заголовки остаются, это работает только при прокрутке внутри контейнера, а не в окне документа. К сожалению, это не то, что нам нужно.

Предлагаемое решение

Прежде всего, давайте отделим заголовки от таблицы. Мы сделаем, чтобы заголовки содержались в собственном div («headers»), чтобы мы могли работать с ними отдельно. Давайте назначим для этого div position: sticky; , и давайте добавим внутри него еще один div «scroller», чтобы контент мог прокручиваться горизонтально.

<!-- HTML -->
<div class="wrap"> <div class="headers"> <div class="scroller"> <div class="track"> <div class="heading">Heading 1</div> </div> ... </div> </div> <!-- headers -->
...
/* Styles */
.headers { position: sticky; top: 0; z-index: 1;
}
.scroller { overflow: auto;
}

Теперь заголовки прилипают, когда мы прокручиваем окно документа. Но все еще немного не так. Обратите внимание, что теперь мы можем прокручивать заголовки и таблицу по отдельности; при горизонтальной прокрутке заголовки не перемещаются вдоль столбцов таблицы.

Чтобы исправить это, нам нужно ввести крошечный скрипт (946 байтов), чтобы можно было синхронизировать прокрутку двух контейнеров. Добавив класс .syncscroll с атрибутом name, мы можем добиться синхронного режима прокрутки двух элементов div.

Чтобы предотвратить вывод полосы прокрутки в контейнере заголовков, нам также нужно добавить:

.scroller { overflow-x: hidden;
}

Это дает нам нужный результат:

А вот реальный пример:

Мне не удалось найти решение на чистом CSS для синхронизации прокручиваемых контейнеров.

Примечание о поддержке браузерами

Помимо некоторых небольших проблем с thead в таблицах, поддержка браузерами position: sticky; довольно неплоха. Однако наш старый друг Internet Explorer не распознает его, поэтому, если вы хотите, чтобы «липкий» элемент работал в старых браузерах, рассмотрите возможность использования полифилла, такого как stickyfill.

Также помните, что Safari нужен префикс (position: -webkit-sticky).

Автор: Dannie Vinther

Источник: https://uxdesign.cc/

Редакция: Команда webformyself.