Есть ли способ позиционирования содержимого страницы под или на верхней части полосы прокрутки?
Я пытаюсь эмулировать функциональность CTRL+F из Chrome, которая выделяет совпадения на странице на полосе прокрутки, но для определенных полей в форме. Используя смещения страниц и проценты, у меня есть цветные блоки, которые соответствуют относительным местоположениям этих полей на странице.
В моем прототипе цветные блоки располагаются слева от полосы прокрутки. В идеале, они должны находиться под полосой прокрутки, и дорожка полосы прокрутки будет прозрачной, так что похоже, что они являются частью дорожки полосы прокрутки.
Можно ли установить полосу прокрутки по умолчанию, чтобы содержимое переполнения отображалось под ней (или позволяло содержимому страницы проходить поверх него)? Я знаю, что этого можно достичь, если я просто сверну свой собственный свиток, но я бы хотел использовать стандартные, предоставляемые браузером, если это вообще возможно.
Ясно, если вы просто посмотрите на этот прототип.
CSS:
::-webkit-scrollbar {
width: 14px;
height: 18px;
background-color:transparent;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-track-piece {
background:none;
}
::-webkit-scrollbar-thumb {
height: 6px;
border: 4px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
-webkit-border-radius: 7px;
background-color: #333
}
::-webkit-scrollbar-button {
width: 0;
height: 0;
display: none;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}
1 ответ
Я думал о рендеринге совпадений на трекбаре так же, как это делали браузеры сегодня. Идея проста с помощью linear-gradient
фон для ::-webkit-scrollbar-track
, Однако я не пытался реализовать это. Сразу после прочтения вашего вопроса я попробовал его и похоже, что это не так просто.
Вы можете использовать linear-gradient
фон в порядке, но если вы попытаетесь отрисовать более 1 совпадения (строки), иногда это невозможно отрисовать (особенно при изменении размера окна), а линия не отображается ровно. Например, это нормально:
//render 2 lines, one is at 50px and the other is at 100px
background: linear-gradient(transparent 50px, red 50px, red 51px, transparent 51px,
transparent 100px, red 100px, red 101px, transparent 101px);
но он не стабилен, как я уже сказал, когда вы пытаетесь изменить размер окна, при некотором размере некоторая строка не будет отображаться (по крайней мере, я пытался в Opera). Когда высота окна велика, линия становится размытой (не резкой) и толще. Я не очень понимаю это, потому что цветовые остановки установлены жестко (по px
не %
). Эта проблема еще хуже, когда количество строк больше. У тебя есть linear-gradient
со многими соответствующими цветными остановками. Это, кажется, хороший способ решить проблему. Только из-за нежелательной проблемы мы не можем использовать этот подход.
Новый подход: поэтому я попытался использовать функцию мульти-фонов. Каждый фон просто отображает 1 строку, background-size
одинаково для всего фона примерно 2px
высота и background-position
должно быть по-другому. Вот эквивалентный код (приведенный выше чистый код) с использованием этого подхода:
background: linear-gradient(red, red), linear-gradient(red, red);
background-repeat: no-repeat;
background-size: 100% 2px;
background-position: 0 50px, 0 100px;
Новый подход, конечно, требует, чтобы браузер поддерживал мульти-фоновые функции (похоже, просто IE8- не поддерживает эту классную функцию).
Так что это почти то, что вам нужно, чтобы решить эту проблему. Теперь нам нужно найти, как применить этот стиль, используя скрипт. Мы не можем выбрать псевдоэлемент (или что-то подобное) через скрипт. Мы можем просто использовать window.getComputedStyle()
метод, чтобы получить стиль только для чтения псевдоэлемента. Однако у нас всегда есть способ изменить CSS напрямую. Это с помощью чистого JS с помощью document.styleSheets
а также cssRules
, Они позволяют нам вставить / удалить / изменить правило.
Это выглядит великолепно. Но есть еще одна проблема. При изменении стиля с использованием этого метода, стиль не применяется правильно (по крайней мере, это происходит с ::-webkit-scrollbar-track
, это может не произойти с другими элементами). Только когда вы наводите указатель мыши на полосу прокрутки, применяется новый стиль. Я только что нашел простой способ аннулировать эту полосу прокрутки, установив overflow
из document.documentElement
(html
) чтобы hidden
и установите его обратно auto
, Это работает почти хорошо.
Вот код:
var requiredTb = $(".required input");
var invalids = requiredTb;
var offsets = [];
//init offsets to highlight on the trackbar later
requiredTb.each(function() {
offsets.push(($(this).offset().top)/document.body.scrollHeight * 100);
});
//find the rule styling the -webkit-scrollbar-track
//we added in the CSS stylesheet, this is done just 1 time
var sheets = document.styleSheets;
var trackRule;
for(var i = 0; i < sheets.length; i++){
var rules = sheets[i].cssRules || sheets[i].rules;
for(var j = 0; j < rules.length; j++){
var rule = rules[j];
if(rule.selectorText == "::-webkit-scrollbar-track:vertical"){
trackRule = rule; break;
}
}
}
//define an invalidate() method, we need to use this method
//to refresh the scrollbars, otherwise the newly applied style is not affected
window.invalidate = function(){
$(document.documentElement).css('overflow','hidden');
setTimeout(function(e){
$(document.documentElement).css('overflow','auto');
},1);
};
//this is the main function to set style for the scrollbar track.
function setTrackHighlights(positions, color){
positions.sort();//ensure that the input array should be ascendingly sorted.
trackRule.style.cssText = "";
var gradient = "background: ", backPos = "background-position: ";
var winHeight = $(window).height();
$.each(positions, function(i,pos){
gradient += "linear-gradient(" + color + ", " + color + "),";
backPos += "0 " + pos + "%,"
});
gradient = gradient.substr(0,gradient.length-1) + ";";
backPos = backPos.substr(0,backPos.length -1) + ";";
trackRule.style.cssText += gradient + backPos + "background-repeat:no-repeat; background-size:100% 2px";
invalidate();
}
//initially set the highlights on the trackbar
setTrackHighlights(offsets,'red');
//handle the oninput event to update the highlights accordingly
requiredTb.on('input', function(e){
var required = $(this).closest('.required');
var refreshHighlights = false;
if(this.value && !required.is('.ok')) {
required.addClass('ok');
refreshHighlights = true;
invalids = invalids.not(this);
}
if(!this.value && required.is('.ok')) {
required.removeClass('ok');
refreshHighlights = true;
invalids = invalids.add(this);
}
if(refreshHighlights){
offsets.splice(0);
invalids.each(function() {
offsets.push(($(this).offset().top)/document.body.scrollHeight * 100);
});
setTrackHighlights(offsets,'red');
}
});
Вы должны добавить пустой ::-webkit-scrollbar-track:vertical
Правило (нам нужно иметь дело только с вертикальной полосой прокрутки) в коде CSS, оно должно быть добавлено в конце, чтобы переопределить любое подобное правило раньше. Мы можем на самом деле использовать insertRule()
метод (из CSSRuleList, который может быть доступен через cssRules
свойство), чтобы добавить новое правило вместо циклического styleSheets
и через cssRules
(каждого листа), чтобы найти пустое правило ::-webkit-scrollbar-track:vertical
,
Код, который я разместил здесь, может быть улучшен, например, вы можете добавить другой метод setTrackHighlights
чтобы разрешить добавлять больше строк (вместо рендеринга всех строк каждый раз, когда нам нужно добавить / удалить только одну строку)...
Обратите внимание, что используя термин line, я имею в виду представление соответствия на трекбар.