提问人:marsielko 提问时间:9/12/2023 更新时间:9/12/2023 访问量:50
当任何祖先处于位置时,3D 变换会闪烁:固定
The 3D transforms flickering when any ancestor is position: fixed
问:
我已经实现了基于 3d 变换的自定义滚动条:https://developer.chrome.com/blog/custom-scrollbar/,但是我注意到滚动条拖动器在滚动过程中的闪烁行为。
此行为仅发生在 Mozzila 浏览器中 - 测试于:“Mozilla/5.0 (X11;Ubuntu的;Linux x86_64;rv:109.0) Gecko/20100101 Firefox/117.0”。为了使滚动条拖动器动画流畅,我必须删除“position: fixed”,这是我在当前用例中根本无法完成的步骤。
检查下面的代码片段(或打开此 codepen 项目:https://codepen.io/marsielko/pen/OJrmoWq)并在 html/body 元素中切换“position: fixed”,并上下滚动鼠标滚轮。
// Taken from: https://github.com/GoogleChromeLabs/ui-element-samples/blob/gh-pages/custom-scrollbar/scrollbar.js
(function(scope) {
var dragging = false;
var lastY = 0;
function dragStart(event) {
dragging = true;
this.style.pointerEvents = 'none';
this.style.userSelect = 'none';
lastY = (event.clientY || event.clientY === 0) ? event.clientY : event.touches[0].clientY;
}
function dragMove(event) {
if (!dragging) return;
var clientY = (event.clientY || event.clientY === 0) ? event.clientY : event.touches[0].clientY;
this.scrollTop += (clientY - lastY)/this.thumb.scaling;
lastY = clientY;
event.preventDefault();
}
function dragEnd(event) {
dragging = false;
this.style.pointerEvents = 'initial';
this.style.userSelect = 'initial';
}
// The point of this function is to update the thumb's geometry to reflect
// the amount of overflow.
function updateSize(scrollable) {
scrollable.style.width = '';
scrollable.style.width = `calc(${getComputedStyle(scrollable).width} + 200px)`;
var thumb = scrollable.thumb;
var viewport = scrollable.getBoundingClientRect();
var scrollHeight = scrollable.scrollHeight;
var maxScrollTop = scrollHeight - viewport.height;
var thumbHeight = Math.pow(viewport.height, 2)/scrollHeight;
var maxTopOffset = viewport.height - thumbHeight;
thumb.scaling = maxTopOffset / maxScrollTop;
thumb.style.height = `${thumbHeight}px`;
if(scrollable.isIOS) {
thumb.nextElementSibling.style.marginTop = `-${thumbHeight}px`;
var z = 1 - 1/(1+thumb.scaling);
thumb.style.transform = `
translateZ(${z}px)
scale(${1-z})
translateX(-200px)
`;
} else {
thumb.style.transform = `
scale(${1/thumb.scaling})
matrix3d(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, -1
)
translateZ(${-2 + 1 - 1/thumb.scaling}px)
translateX(-200px)
`;
}
}
function makeCustomScrollbar(scrollable) {
// Edge requires a transform on the document body and a fixed position element
// in order for it to properly render the parallax effect as you scroll.
// See https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/5084491/
if (getComputedStyle(document.body).transform == 'none')
document.body.style.transform = 'translateZ(0)';
var fixedPos = document.createElement('div');
fixedPos.style.position = 'fixed';
fixedPos.style.top = '0';
fixedPos.style.width = '1px';
fixedPos.style.height = '1px';
fixedPos.style.zIndex = 1;
document.body.insertBefore(fixedPos, document.body.firstChild);
scrollable.style.perspectiveOrigin = 'top right';
scrollable.style.transformStyle = 'preserve-3d';
scrollable.style.perspective = '1px';
var perspectiveCtr = document.createElement('div');
perspectiveCtr.style.perspectiveOrigin = 'top right';
perspectiveCtr.style.transformStyle = 'preserve-3d';
perspectiveCtr.style.width = '100%';
perspectiveCtr.style.position = 'absolute';
perspectiveCtr.style.pointerEvents = 'none';
perspectiveCtr.classList.add('perspective-ctr')
while(scrollable.firstChild) perspectiveCtr.appendChild(scrollable.firstChild);
scrollable.insertBefore(perspectiveCtr, scrollable.firstChild);
var thumb = document.createElement('div');
thumb.classList.add('thumb');
thumb.style.pointerEvents = 'initial';
thumb.style.position = 'absolute';
thumb.style.transformOrigin = 'top right';
thumb.style.top = '0';
thumb.style.right = '0';
perspectiveCtr.insertBefore(thumb, perspectiveCtr.firstChild);
scrollable.thumb = thumb;
scrollable.perspectiveCtr = perspectiveCtr;
// We are on Safari, where we need to use the sticky trick!
if (getComputedStyle(scrollable).webkitOverflowScrolling) {
scrollable.isIOS = true;
thumb.style.right = '';
thumb.style.left = '100%';
thumb.style.position = '-webkit-sticky';
perspectiveCtr.style.perspective = '1px';
perspectiveCtr.style.height = '';
perspectiveCtr.style.width = '';
perspectiveCtr.style.position = '';
Array.from(scrollable.children)
.filter(function (e) {return e !== perspectiveCtr;})
.forEach(function (e) {perspectiveCtr.appendChild(e);});
}
scrollable.thumb.addEventListener('mousedown', dragStart.bind(scrollable), {passive: true});
window.addEventListener('mousemove', dragMove.bind(scrollable));
window.addEventListener('mouseup', dragEnd.bind(scrollable), {passive: true});
scrollable.thumb.addEventListener('touchstart', dragStart.bind(scrollable), {passive: true});
window.addEventListener('touchmove', dragMove.bind(scrollable));
window.addEventListener('touchend', dragEnd.bind(scrollable), {passive: true});
var f = function () {
updateSize(scrollable);
};
requestAnimationFrame(f);
window.addEventListener('resize', f);
return f;
}
window.addEventListener('load', function () {
Array.from(document.querySelectorAll('.overflow')).forEach(scrollable => {
makeCustomScrollbar(scrollable);
updateSize(scrollable);
});
});
})(self);
/* Taken from: https://github.com/GoogleChromeLabs/ui-element-samples/blob/gh-pages/custom-scrollbar/index.html */
::-webkit-scrollbar {
width: 0px;
height: 0px;
}
html, body {
margin: 0;
border: 0;
padding:0 ;
height: 100%;
overflow: hidden;
top: 0;
bottom: 0;
left: 0;
right: 0;
position: fixed;
}
.overflow {
overflow-x: hidden;
overflow-y: scroll;
background: #EDEDED;
width: 100%;
height: 100%;
position: relative;
-webkit-overflow-scrolling: touch;
}
.thumb {
width: 68px;
/* background-image: url('cat.gif'), linear-gradient(90deg, transparent, magenta, red, yellow, limegreen, turquoise, blue, magenta, transparent); */
/* background-position: center bottom, center -40px; */
/* background-repeat: no-repeat, no-repeat; */
/* background-size: contain, contain; */
background-color: red;
}
.fakecontent {
padding: 25vh 0;
border: 1px solid transparent;
}
<!-- Taken from: https://github.com/GoogleChromeLabs/ui-element-samples/blob/gh-pages/custom-scrollbar/index.html -->
<body>
<main class="glider-scrollable overflow">
<div class="fakecontent">Lorem</div>
<div class="fakecontent">ipsum</div>
<div class="fakecontent">dolor</div>
<div class="fakecontent">sit</div>
<div class="fakecontent">amet,</div>
<div class="fakecontent">consectetur</div>
<div class="fakecontent">adipiscing</div>
<div class="fakecontent">elit</div>
</main>
<body>
我的问题是,有没有办法像在 Chrome 中那样使拖拽器的动画流畅,或者这是一个错误,需要报告?
答: 暂无答案
评论