Проблема: дропдаун не меняет положения при ресайзе или изменении положения родителя. Касается также тултипов, поповеров и попапов.
- Чистые стили, только
reset.css
. - Позиционирование независимо от
overflow: hidden
.
- Кусок кода уезжает со своего места, порождая пачку проблем:
- Если там инпуты, они отрываются от формы, нужно следить за их заполнением и дублировать в hidden-поля.
- Если там подэлементы компонента, ломается поиск по JS-классам, ломается делегирование и слушание событий, нужно вводить специальные обёртки и кэшировать ссылки на них для каждого компонента, попавшего в дропдаун.
- Даже при отсутствии подэлементов ломается обычная событийная работа, потому что события всплывают прямо в
body
, минуя всех родителей. - Невозможно поместить дропдаун в элемент с
overflow: hidden
с обрезанием, если это всё же понадобится. Пример: дропдаун в попапе.
- Дропдаун никак не связан со свитчером, что порождает ещё одну пачку проблем:
- При изменении размеров окна свитчер может переехать, нужно обновлять его по событию
resize
(сделано). - При изменении положения свитчера (перед ним открылся ToggleBlock) нужно передвигать дропдаун, а это можно отследить только таймером.
- При изменении видимости любого из родительских элементов свитчера дропдаун нужно скрыть или показать, тоже отслеживается только таймером.
- Перемещение на JS по определению отстаёт и лагает, где-то больше, где-то меньше.
- (?) Перекрытие друг друга дропдаунами, тултипами, поповерами и попапами, которые произвольно насыпались в конец
body
. Перекрытие одного другим можно разрулить только черезz-index
, но дропдаун может открыться на странице под попапом и в самом попапе, в одном случае он должен быть под паранжой, в другом над паранжой.
- Переезжает сам вместе со свитчером, пока тот неподвижен относительно своего offsetParent'a. Если обернуть свитчер в элемент с
position: relative
, дропдаун будет переезжать вместе с ним при любом сдвиге и ресайзе нативно и без лагов. - Скрывается и показывается вместе с элементом при изменении видимости родителей.
- Элементы остаются на месте, находятся по дереву, события всплывают куда надо. Не требуется вмешательство в другие компоненты.
- Наследуются стили родителя, нужен сброс со стороны блока или специальная обёртка со стороны клиента. Вариант решения: g-reset.
- Если свитчер внутри элемента с
overflow: hidden
, дропдаун будет обрезаться. Вариант решения: в редких случаях помещения дропдауна с компонентами внутри вoverflow: hidden
по параметру осознанно переводить его в режим добавления вbody
и рефакторить попавшие в него компоненты.
Twitter, Google, Github кладут рядом. Яндекс кладёт в body и не следит за положением свитчера, можно подвинуть его стилями или поместив что-то перед ним, дропдаун остаётся на месте. При ресайзе на главной Яндекса дропдаун перерисовывается, а в картах нет.
См. скриншоты.
ХЗ. Проблемы те же, но выставить блок поверх всех остальных из любого места DOM не так-то просто.
Я написал в начале, что проблема касается любых поповеров. То, что сейчас дропдаун закрывается при клике куда-либо и это нельзя отключить — очень конкретное (и странное) поведение, на которое нельзя завязываться. У тултипа, к примеру, для этого есть настройка.
Думай так: есть ли что-то необычное в том, чтобы оставить дропдаун открытым при клике на документе? Ничего необычного нет, и на Яндексе и других сайтах часто так бывает, значит и наш дропдаун может не закрыться. Ещё ToggleBlock может закрыться скриптом, и т.п., от того что ты переложишь заботу обо всём этом на разработчика, использующего дропдаун, им станет только сложнее пользоваться.
Если хочешь, чтобы он умел только примитивные базовые вещи, надо оставить только ручное открытие/закрытие и дополнить его какими-то менеджерами, которые будут следить за видимостью, положением, ресайзом, кликами, и делать всё что нужно для нормальной работы компонента. В этом тоже есть смысл: модуль дропдаун + тонкая управляющая обёртка, модуль можно использовать в других компонентах.
Это уже тонкости реализации, главное чтобы компонент работал из коробки и не создавал никаких проблем разработчику.