CSS - 在悬停固定子项时在父项内滚动

lae*_*aef 5 html css css-position

我有一个内部可滚动元素。在它里面,有可以滚动的内容,还有一个position: fixed;形成侧边栏的孩子。

如果我将鼠标悬停在父级内部的任何位置并滚动,则父级的内容会按预期滚动。但是,如果我将鼠标悬停在仍位于父级边界框内的固定子级内并滚动,则不会:

<style>
  body,
  html {
    margin: 0;
  }
  
  #container {
    position: relative;
    width: 100%;
    height: 100vh;
    overflow-y: auto;
  }
  
  #sidebar {
    position: fixed;
    right: 10px;
    width: 100px;
    top: 10px;
    height: calc(100% - 20px);
    background-color: red;
  }
</style>

<div id='container'>

  <div id='sidebar'>
    <a href='https://google.com/'>Link to click</a>
    When hovering here, scroll does NOT work.
  </div>

  <p>Lorem ipsum.</p>
  <p>Lorem ipsum.</p>
  <p>Lorem ipsum.</p>
  ... and so on. When hovering here, scroll works.

</div>
Run Code Online (Sandbox Code Playgroud)

我了解此功能的使用,但我有兴趣使滚动事件仍然从position:fixed;子级向上传播到overflow:auto;其父级,从而允许用户滚动父元素,即使在悬停子级时也是如此。这可能吗?

我已经尝试使用 JavaScript 来监视子级上的滚动事件,然后将它们传递给父级,但是没有捕获到此类滚动事件(我想是因为元素本身没有任何可在内部滚动的内容)。我还尝试了父元素(position:relative;, position:absolute;, position:fixed;)的各种配置,都无济于事。该问题仅在孩子被修复时发生,但将其设置为绝对不是一个选项。

最好,我想在没有 JavaScript 的情况下完成此操作,因此对可能的解决方案(仅 HTML、HTML 和 CSS 以及仅 JavaScript)进行细分可能会很有用。


我知道这个问题,但是那里的第一个答案不起作用,因为在悬停固定子项时滚动不会触发滚动事件(对于子项或父项)。第二个答案也不可行,因为它将孩子移到父母之外,这在我的情况下不是一个选择。


编辑: Harsh Karanpuria 建议我添加pointer-events: none;到侧边栏。这确实实现了预期的结果,但它也会使侧边栏中的元素无法点击,我宁愿不这样做!在他们回答之后,我还尝试再次制作侧边栏的 子元素pointer-events: all;,但发现虽然这恢复了我单击它们的能力,但在悬停该孙子时再次删除了可滚动特性。

nok*_*kko 3

position: fixed;不是为此设计的;使用position: sticky;

\n

我将在这里采取规定性立场:您不需要浪费时间传播或类似的东西来实现您正在寻找的效果。过去可能就是这种情况,但 CSS 拥有比position: fixed;.

\n

看一下 CSS3 定位布局模块,以下是他们对固定定位的看法:

\n
\n

固定定位,[\xe2\x80\xa6] 绝对定位框并将其粘贴到视口或页框上,使其始终可见。

\n
\n

这与你的解释不一致,强调我的:

\n
\n

但是,如果我将鼠标悬停在固定子项内(该子项仍在父项的边界框内), [\xe2\x80\xa6]

\n
\n

从视觉上看,是的,固定子项位于其父项\xe2\x80\xa6 内,但只需向父项添加边距即可将其移开:

\n

\r\n
\r\n
<style>\n  body,\n  html {\n    margin: 0;\n  }\n  \n  #container {\n    /* <Changes> */\n    background-color: skyblue;\n    margin-top: 10vh;\n    /* </Changes> */\n    position: relative;\n    width: 100%;\n    height: 100vh;\n    overflow-y: auto;\n  }\n  \n  #sidebar {\n    position: fixed;\n    right: 10px;\n    width: 100px;\n    top: 10px;\n    height: calc(100% - 20px);\n    background-color: red;\n  }\n</style>\n\n<div id=\'container\'>\n\n  <div id=\'sidebar\'>\n    <a href=\'https://google.com/\'>Link to click</a>\n    When hovering here, scroll does NOT work.\n  </div>\n\n  <p>Lorem ipsum.</p>\n  <p>Lorem ipsum.</p>\n  <p>Lorem ipsum.</p>\n  ... and so on. When hovering here, scroll works.\n\n</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

我找不到position:fixedW3C 规范中子级事件不会像往常一样传播到父级的原因,但情况仍然是scroll事件传播到视口,而不是像往常一样冒泡到父级元素。

\n

来自 W3C CSS 定位布局模块级别 3 \xc2\xa7 2:

\n
\n

[ position: fixed:] 与绝对相同,只是框的位置和大小是相对于固定定位包含块(通常是连续媒体中的视口,或分页媒体中的页面区域)。box\xe2\x80\x99s 的位置相对于该参考矩形是固定的:当附加到视口时,当文档滚动时,它不会移动;当附加到页面区域时,当文档分页时,它会在每个页面上复制。这种定位方案称为固定定位,被认为是绝对定位的子集。

\n
\n

position: fixed元素应该固定到视口,而不是其父元素。解决您的问题的自然方法是使用position:sticky.

\n

使用position:stickydisplay: flex

\n

\r\n
\r\n
<style>\n  body,\n  html {\n    margin: 0;\n  }\n  \n  #container {\n    /* <Changes> */\n    background-color: skyblue;\n    display: flex;\n    max-height: 40vh; /* Just to force scrolling in the demo. */\n    /* </Changes> */\n    position: relative;\n    width: 100%;\n    height: 100vh;\n    overflow-y: auto;\n  }\n  \n  #sidebar {\n    position: sticky;\n    right: 0px;\n    top: 0px;\n    min-width: 100px;\n    background-color: red;\n  }\n</style>\n\n<div id=\'container\'>\n  <!-- Changes -->\n  <div id="content">\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    ... and so on. When hovering here, scroll works. Note this really long line is not overlapped by the sidebar.\n  </div>\n  <!-- /Changes -->\n  <div id=\'sidebar\'>\n    <a href=\'https://google.com/\'>Link to click</a>\n    When hovering here, scroll ALSO works.\n  </div>\n</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

我稍微更改了 HTML,将<p>标签放入包含中div#content并重新排列内容和侧边栏的顺序。您可以更改flex-direction并放弃重新排列。推力是相同的:容器元素、内部内容、内部侧边栏。

\n

此布局的效果与问题中呈现的效果不同:侧边栏不能与此布局中的内容重叠。如果这不理想,您可以使用display:grid.

\n

使用position:stickydisplay: grid

\n

我们可以为侧边栏创建一个网格区域,如下所示:

\n

\r\n
\r\n
<style>\n  body,\n  html {\n    margin: 0;\n  }\n  \n  #container {\n    /* <Changes> */\n    background-color: skyblue;\n    display: grid;\n    grid-template-columns: 1fr min-content;\n    \n    max-height: 40vh; /* Just to force scrolling in the demo. */\n    /* </Changes> */\n    position: relative;\n    width: 100%;\n    height: 100vh;\n    overflow-y: auto;\n  }\n  \n  #content {\n    grid-row: 1 / span 2;\n    grid-column: 1 / span 2;\n  }\n  \n  #sidebar {\n    grid-row: 1;\n    grid-column: 2;\n    position: sticky;\n    right: 0px;\n    top: 0px;\n    min-width: 100px;\n    min-height: 110px;\n    background-color: red;\n  }\n  \n</style>\n\n<div id=\'container\'>\n  <!-- Changes -->\n  <div id="content">\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    <p>Lorem ipsum.</p>\n    ... and so on. When hovering here, scroll works. Note this really long line is overlapped by the sidebar.\n  </div>\n  <!-- /Changes -->\n  <div id=\'sidebar\'>\n    <a href=\'https://google.com/\'>Link to click</a>\n    When hovering here, scroll ALSO works.\n  </div>\n</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

请注意,为了使重叠起作用,我们需要手动设置grid-column和元素。grid-row#sidebar#content

\n

也可以看看:

\n\n