Pull to refresh

Нюансы употребления плагина jQuery.LocalScroll совместно с CSS-селектором «:target»

Reading time5 min
Views5.8K
На HTML-страницах многих сайтов существуют гиперссылки наподобие <a href="#idName">...</a>, которые ведут не на другую страницу, а к некоторому месту на той же сáмой странице, где и ссылка. Это обычное дело для обширных статей с оглавлением (если каждый пункт оглавления является такой гиперссылкою, которая ведёт к названному в нём заголовку) или с примечаниями (если надстрочный знак примечания служит гиперссылкою и ведёт к примечанию в конце текста, а от примечания стоит гиперссылка в обратном направлении). Таких статей немало в сетевых энциклопедиях (вики, например) или в серьёзных сетевых журналах.

К сожалению, переход по такой внутренней гиперссылке в большинстве современных браузеров Паутины совершается мгновенно, ничуть не заметно для читателя. Это совсем не то, что проматывание страницы вручную, которое происходит плавно и занимает некоторое (заметное взору) время, так что даёт читателю некоторое представление об объёме того текста, мимо которого он пролетает.

Досадно, не правда ли?

К счастью, существует плагин для jQuery, который позволяет невозбранно достичь желаемого, то есть без труда обратить всякий переход по внутренней гиперссылке документа именно в такое проматывание, во всём подобное ручному, но только совершаемое автоматически и за достаточно краткое время (по умолчанию — за секунду), так что читатель как раз успевает осознать происходящее и оценить направление проматывания и пройденное расстояние, но ещё не успевает заскучать.

Этот плагин называется jQuery.LocalScroll, и он, окромя jQuery, потребует для своей работы ещё другой плагин (jQuery.ScrollTo), обёрткою для которого является. Так что достаточно установить jQuery и оба эти плагина — и тогда в дальнейшем вызов функции, включающей автоматическое проматывание для всех внутренних гиперссылок, станет можно записывать как нельзя проще:
$($.localScroll());
Вроде бы всё хорошо. Но проблема в том, что по умолчанию такое проматывание является просто проматыванием: документ прокручивается в окне у читателя, и больше ничего.

А ведь, чтобы полностью воссоздать итог перехода по внутренней гиперссылке, необходимо также добавить строку «#idName» к адресу (в строке адреса, учитываемой браузером). Не то слишком уж далеко возвращала бы читателя кнопка «Назад» в браузере: именно ею выразив желание вернуться назад к оглавлению от подраздела (или же от примечания к поясняемому им тексту), читатель неожиданно вернулся бы к предыдущей странице.

Чтобы имитация перехода по внутренней гиперссылке оставалась совершенною, то есть чтобы добавлять строку «#idName» к адресу страницы, Ariel Flesler (автор плагина jQuery.LocalScroll) предлагает включать параметр «hash»:
$($.localScroll({
    hash: true
}));
После этого #-часть адреса действительно переменяется, и кнопка «Назад» начинает работать нормально.

Но достигает ли желаемого совершенства такая имитация перехода по внутренней гиперссылке?

Увы, нет.

Дальнейшие проблемы начинаются, если в стилях документа используется селектор «:target», появившийся в CSS3. Например, стилевое правило *:target { background-color: red } вроде бы должно подсвечивать ту область документа, к которой произошёл переход по внутренней гиперссылке. И в новых браузерах действительно подсвечивает (как гласит MDC, этот селектор поддерживается в Firefox 1.0, в Opera 9.5, в Safari 1.3, и в более новых). Однако, если задействован вызов $($.localScroll()) или $($.localScroll({hash: true})), то в Файерфоксе прокрутка происходит плавно, но CSS-подсветка вырубается. Напрочь.

Что делать?

Я нипочём не догадался бы о причине этого глюка, когда не взглянул бы в исходники плагина LocalScroll нынешней версии (1.2.7).

Оказывается, Ариэль Флеслер решил радикально упростить себе жизнь: вместо того, чтобы дожидаться конца проматывания (и навесить на него такое событие, которое переменяло бы #-часть адреса именно после того, как проматывание полностью завершилось), плагин ещё до проматывания присваивает #-части адреса страницы желаемое значение. Вот так:
location = link.hash;
Просто, не правда ли?

Но ведь такое присваивание автоматически сразу!) прокрутит документ к указанному месту назначения, и тогда вся идея плавного проматывания пойдёт прахом?

Правильно!

И потому, раз уж Ариэль Флеслер решил радикально упростить себе жизнь, то он идёт в своём намерении до конца: его плагин сперва отбирает атрибут «id="idName"» (или «name="idName"») у места назначения гиперссылки, затем создаёт в поле зрения (чтобы исключить прокручивание) новый пустой элемент именно с таким атрибутом, затем присваивает #-части адреса желаемое значение (прокручивание не происходит), затем убивает этот свежесозданный пустой элемент, а месту назначения внутренней гиперссылки возвращает отобранный атрибут — и только тогда начинает спокойно, медленно к нему проматывать.

Файерфокс, разумеется, при этом селектор «:target» применяет именно к новому пустому элементу (который оказывается убит), а гибель этого элемента и дальнейшее появление аналогичного атрибута у другого элемента — игнорирует хладнокровнейше. Я не решил ещё, можно ли считать такое поведение багом Файерфокса. Я также не проверял, как поведут себя Opera, Safari и Chrome в этой ситуации. Мне достаточно и того, что теперь я знаю, как преодолеть это поведение.

Достаточно вызвать $.localScroll() с нормальным человеческим обработчиком, срабатывающим именно после того, как проматывание завершилося:
$.localScroll({
    onAfter: function(target){
        location = '#' + ( target.id || target.name );
    }
});
Вот и всё.

Просто, не правда ли?

Оно всегда так просто, когда всё ужé ясно.
Tags:
Hubs:
-3
Comments19

Articles

Change theme settings