调整浏览器窗口大小时,请保留内容中的位置
Keep place in content when resizing the browser window
当窗口大小发生变化时,是否有方法阻止内容滚动?
我正在开发一个具有长格式内容的响应式网站。当调整浏览器窗口的大小时,阅读器在内容中的位置会发生移动。这导致了糟糕的用户体验,因为他们必须再次在内容中找到自己的位置。
bootstrap文档站点就是一个很好的例子。试着在文档集底部附近调整窗口大小,调整大小后你会看到完全不同的东西。http://getbootstrap.com/components/#panels
Mozilla漏洞来自1999年处理我面临的一个问题#retrobughttps://bugzilla.mozilla.org/show_bug.cgi?id=19261
element.scrollIntoView()
。
您可以使用以下功能检测哪个元素最接近顶部:
function closestToTop() {
const top = window.scrollY;
return [].reduce.call(
document.querySelectorAll('h1, h2, h3'),
(closest, el) => Math.abs(offsetTop(el) - top) <= Math.abs(offsetTop(closest) - top)
? el
: closest,
document.body
);
}
在哪里您可以使用获得offsetTop
function offsetTop(el, offset = 0) {
if (el === document.body) {
return 0;
}
return offset + el.offsetTop + offsetTop(el.offsetParent);
}
我们将自身限制为<h1>
、<h2>
和<h3>
元素,以使计算更容易。
你想做的是在调整大小开始时弄清楚什么元素在顶部,并且只有在滚动结束时它在屏幕外时才滚动到它。因此,我们需要应用某种油门:
{
let throttling = false;
function throttledResize() {
if (throttling) {
return;
}
throttling = true;
window.dispatchEvent(new CustomEvent('resizeStart'));
requestAnimationFrame(() => {
window.dispatchEvent(new CustomEvent('resizeEnd'));
throttling = false;
});
};
window.addEventListener('resize', throttledResize);
}
现在我们有了'resizeStart'
和'resizeEnd'
事件。请注意,我们将其放在ECMAScript2015块作用域中,这样我们就不会用throttling
和throttleResize
变量污染全局作用域。现在,我们可以关闭开始调整大小时位于顶部的任何元素(再次使用块范围(。
{
let wasAtTop = null;
window.addEventListener('resizeEnd', () => {
if (!wasAtTop) {
return;
}
wasAtTop.scrollIntoView();
wasAtTop = null;
});
window.addEventListener('resizeStart', () => {
wasAtTop = closestToTop();
});
}
注意:这是高度未优化的。我们可以对此进行各种改进。类似于在下一个动画帧之前节流更长的时间,并且除非元素实际上在视图window.scrollY < offsetTop(el) && offsetTop(el) < window.scrollY + window.height
之外,否则永远不要滚动。
很难将顶部保持在像素级,精确到窗口调整大小之前的位置(例如,在div的中间(。但作为一种变通方法,您可以使用一些div(例如小节标题(作为"锚点":每当用户滚动时,检测并跟踪当前视图中的锚点div,并在调整大小后将页面固定回锚点。
更具体地说,以您提供的链接为例:http://getbootstrap.com/components/#panels
假设您希望所有<h1>
标记都作为锚点(您可以使用h2,也可以使用h1+h2,这取决于您想要的详细控制(:var anchorDivs = document.getElementsByTagName("h1");
作为一个开始(不测试每个角落的场景(,我将这个函数组合在一起,以检测当前视图中的第一个锚点div:
function getAnchorDiv(anchorDivs) {
var viewTop = document.body.scrollTop || document.documentElement.scrollTop; // IE
var viewBottom = viewTop + window.innerHeight;
var anchorDiv;
for (var i = 0; i < anchorDivs.length; i++) {
var anchorDiv = anchorDivs[i];
// gets the cumulative offset top of current div
var anchorDivTop = anchorDiv.offsetTop;
var tempDiv = anchorDiv.offsetParent;
while (tempDiv) {
anchorDivTop += tempDiv.offsetTop
tempDiv= tempDiv.offsetParent;
}
if (anchorDivTop >= viewTop && anchorDivTop < viewBottom) {
// this div is the first one in view
break;
} else if (anchorDivTop >= viewBottom) {
// page view doesn't contain any anchor div, so give the one that's just scrolled over (previous anchor div in the array)
anchorDiv = anchorDivs[(i-1) >= 0 ? (i-1) : 0];
break;
}
}
return anchorDiv;
}
当用户滚动时,更新锚点div:
var anchorDiv = anchorDivs[0];
document.onscroll = function() {
anchorDiv = getAnchorDiv(anchorDivs);
}
最后,在调整大小时,滚动到@Rúnar Berg建议的锚点div:
window.onresize = function() {
anchorDiv.scrollIntoView();
};
如果只是停留在url中的散列位置,您可以在调整大小后重置window.location.href:
window.onresize = function() {
window.location.href = "http://getbootstrap.com/components/#panels";
};
为了在调整大小时保持窗口中的内容,我们首先需要知道我们通过百分比向下滚动了页面的距离。
var percent;
window.addEventListener("scroll", getScrollPercent);
function getScrollPercent() {
percent = window.pageYOffset / document.body.scrollHeight;
}
首先,我将percent
设为全局变量,因为我们将在另一个函数中暂时使用该值。
其次,这个函数不是给我们滚动页面的百分比,而是从正文顶部到窗口顶部的百分比(你永远不会得到100%(。这对我们有利,因为我们的下一个函数将调用window.scrollTo()
,它根据页面顶部的偏移量滚动一定的量。
window.addEventListener("resize", function(){
var Ypos = document.body.scrollHeight * percent;
window.scrollTo(0, Ypos);
});
我们使用之前计算的"百分比"来确定页面大小调整后滚动条的位置,然后将所述值插入Y的window.scrollTo()
中,使X值为0。
希望这对每个人都有效,如果我的措辞令人困惑,我提前道歉。
- 将所有元素保留在同一位置
- 保留选项后的滚动位置(单击时)
- 更新数据后保留D3图的位置
- EXT-JS 4.2.1 保留表单 - 面板滚动条的当前位置
- 在全屏退出时保留页面位置
- 基于鼠标位置的滚动将点击事件保留在前台
- 在 DOM 中添加新元素后,保留元素屏幕位置
- 在 CKEditor 中重新加载页面后保留光标位置
- 执行列排序后,dgrid 无法保留滚动位置
- 如何在fabricjs中保留图像的位置
- 缩放时保留元素大小和位置
- Meteor:当页面刷新或其他页面位置时,如何保留dom操作
- 即使在使用javascript重新加载后,也要保留滚动条的位置
- 使用jquery保留滚动条位置
- Angular JS在重新加载后保留滚动位置
- 如何替换位置哈希并只保留最后一个历史记录条目
- 在fabricjs中放大图像后无法保留圆的位置
- 重新定义window.console函数时,请保留原始路径位置
- HTML数字字段setSelectionRange保留光标位置不起作用
- 过滤字符串末尾的空间,同时在相同位置保留特殊字符