【问题标题】:Scrolling into view an element hidden beneath a persistent header滚动查看隐藏在持久标题下的元素
【发布时间】:2012-10-07 19:41:45
【问题描述】:

我目前在一些严格的限制下工作,以限制我可以使用 JavaScript 做什么(例如,没有像 jQuery 这样的框架,并且在 Firefox 2.0 之后没有任何东西)。

这是我的问题;我在页面顶部浮动了一个持久标题。我的输入元素分散在各处(我们正在精确复制纸质表格,包括背景图像)。页面底部附近有一个字段被标记出来(使用键盘选项卡按钮)并将焦点放在页面顶部的字段上。 Firefox 将自动滚动“进入视图”字段。然而,虽然浏览器认为该字段在视图中,但它实际上隐藏在持久标头之下。

http://imageshack.us/a/img546/5561/scrollintoviewproblem.png

通过从页面上的另一个位置点击“标签”来访问上面的蓝色字段。浏览器认为该字段已滚动到视图中,但实际上它隐藏在浮动持久标头之下。

我正在寻找关于如何检测该字段位于此标题下方并相应地滚动整个页面的想法。

我尝试了一些边距和填充的变体(请参阅http://code.stephenmorley.org/javascript/detachable-navigation/#considerations 的其他注意事项),但没有运气。每次我们关注一个字段时,我也尝试调用 JavaScript 函数“scrollIntoView(element)”,但考虑到表单上的字段数量(以及我们正在对齐它们以匹配论文的背景图像的事实准确的形式),这会导致一些非常严重的“跳跃”行为,当在彼此靠近但高度略有不同的字段中切换时。

我可以更改持久标头的完成方式,只要它不需要太多努力。不幸的是,框架是不可能的,因为我们需要与持久标题中的页面内容进行交互。

理想情况下,解决方案是 CSS,但如果 JavaScript 能解决我的问题,我愿意接受。

另外注意,我们要求输入元素具有背景颜色,这意味着向它们添加填充会使背景颜色拉伸,从而隐藏部分背景图像。但是,输入元素在一个 div 中,所以我们可以利用它来发挥我们的优势。

【问题讨论】:

  • 我好像你可能需要为标题设置一个偏移量。这里有一些建议如何使用scollIntoView 函数进行偏移:forums.devshed.com/javascript-development-115/…
  • this demo 是否很好地代表了您的问题?
  • @Kraz:那个演示实际上正好显示了我的问题。 @Axel:我会给那些 scrollIntoView 偏移建议一个机会,然后回复你。
  • onfocus 事件与 scrollTo 相结合(我无法让 scrollBy 工作:/)似乎是 work nicely (code)。
  • 另一种解决方案可能是在页面顶部附近有一个无用的隐藏输入,您将专注于该输入,然后将焦点重定向到您的第一个表单元素。

标签: javascript css header persistent


【解决方案1】:

因此,在进行了更多搜索之后(感谢 @Kraz 通过 scrollTo() 建议引领这条路线),我找到了适合我的解决方案。

我为每个元素动态添加了 onFocus 调用,因此它们总是调用 scrollScreenArea(element) 函数,该函数确定它们是否隐藏在顶部页眉下方或太靠近页脚区域(这完全解决了另一个问题,使用相同的解决方案)。

/* This function finds an element's position relative to the top of the viewable area */
function findPosFromTop(node) { 
    var curtop = 0;
    var curtopscroll = 0;
    if (node.offsetParent) {
        do {
            curtop += node.offsetTop;
            curtopscroll = window.scrollY;
        } while (node = node.offsetParent);


    }
    return (curtop - curtopscroll);
}

/* This function scrolls the page to ensure that elements are
   always in the viewable area */
function scrollScreenArea(el) 
{ 

    var topOffset       = 200; //reserved space (in px) for header
    var bottomOffset    = 30;  //amount of space to leave at bottom
    var position        = findPosFromTop(el);
    //if hidden beneath header, scroll into view
    if (position < topOffset)
    {
        // to scroll up use a negative number
        scrollTo(el.offsetLeft,position-topOffset);
    }
    //if too close to bottom of view screen, scroll into view
    else if ((position + bottomOffset) > window.innerHeight)
    {
        scrollTo(0,window.scrollY+bottomOffset);
    }
}

如果您有任何问题,请告诉我。感谢@Kraz 让我了解这个解决方案。

同样,我想引用Can I detect the user viewable area on the browser?,因为我从那里获取了一些代码,并且部分描述了我的问题(带有一个简洁的图表)。

【讨论】:

    【解决方案2】:

    最简单的方法是监听每个元素的焦点事件,然后查看它是否在页面上。在纯 JS 中,它是这样的:

    var input = Array.prototype.slice.call(document.getElementsByTagName('input'));
    for ( var i in input )
        input[i].addEventListener( 'focus', function (e) {
            var diff = 150 /* Header height */ - e.target.getBoundingClientRect().top;
            if ( diff > 0 ) {
                document.body.scrollTop += diff;
                document.documentElement && document.documentElement.scrollTop += diff;
            }
        }, false );
    

    我没有包含 IE addEvent 方法,但鉴于此基础,您自己应该很容易做到这一点。

    【讨论】:

    • 除了上面的建议,我也在试一试。无论哪个有效(并且更易于维护),我都会选择。另外,由于我们只处理 Firefox,我不会费心研究 IE 方法。
    • 虽然我认为这个解决方案可行,但我们被困在 Firefox 2.0 上的事实(我无法控制,很遗憾......)意味着我们实际上无法访问 getBoundingClientRect()功能。对于获得该价值的替代方法有什么想法吗?
    • Firefox 2.0 在一周内迎来了它的 6 岁生日,所以我不知道你为什么需要支持它。但是 polyfill 相当容易,特别是因为您知道唯一不支持它的情况。只需使用 offsetParent + offsetTop,将其相加直到到达正文,然后减去文档的 scrollTop。
    • 一些非常特殊的要求意味着我们只支持 Firefox 2.0。至少对于这个版本的代码,所以在我可以改变它之前,一切都是关于一些非常讨厌的解决方法。我之前找到了一个修复程序,我会尽快发布。我会记住您的建议,以防我们遇到不适用于我当前修复的类似问题,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    • 2014-11-28
    • 2012-05-23
    • 1970-01-01
    • 2021-10-24
    相关资源
    最近更新 更多