“位置:粘性;” 无法正常工作的CSS和HTML


177

滚动到导航栏后,我想使其停留在顶部,但是它不起作用,我也不知道为什么。如果可以的话请帮我,这是我的HTML和CSS代码:

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato",sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover{
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav style="position: sticky; position: -webkit-sticky;">
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>


10
位置:黏性需要协调才能传送到哪里黏着
G-Cyrillus

36
您还必须注意父元素。position: sticky除非小心否则它可能会停止工作,除非它在flexbox内,否则会失败,如果在它之间滚动overflow: hiddenoverflow: auto在滚动条内部滚动(主体根或有溢出的最近祖先:滚动)也将失败
user56reinstatemonica8 '18

2
@ user56reinstatemonica8 OMG thankkkkyou这么多告诉我关于overflow: hiddenoverflow: auto!几天来,我一直在
ing

Answers:


206

粘性定位是相对定位和固定定位的混合。将该元素视为相对位置,直到它超过指定的阈值为止,此时将其视为固定位置。
...
您必须指定的至少一个阈值toprightbottom,或者left为粘稠定位像预期的那样。否则,将无法与相对位置区分开。[资料来源:MDN ]

因此,在您的示例中,您必须使用top属性来定义最终应粘贴的位置。

html, body {
  height: 200%;
}

nav {
  position: sticky;
  position: -webkit-sticky;
  top: 0; /* required */
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>


124
总的来说,这个答案不足以使他们坚持工作,父母也应该没有溢出属性。
ViliusL '18

感谢您的评论。我同意您的意见,对于除OP之外的其他示例,我的回答可能还不够。其他答案指出了这一点:)
Marvin

我认为诀窍是,位置粘滞只能应用于具有已知高度的可滚动父级的子级(flexbox中的直接子级具有从其他flex-item计算出的已知高度)
code4j

@ViliusL谢谢您的评论!那就是我在职位上遇到的问题:粘性,我不会知道是否不适合您,因为我在任何地方都找不到此信息。
Piotr Szlagura

粘性位置不应该具有带有溢出属性的父项,某些Web浏览器也不支持粘性
Rohan Shenoy

331

检查祖先元素是否设置了溢出(例如 overflow:hidden);尝试切换。您可能必须将DOM树提高到比您期望的高=)。

这可能会影响您position:sticky的后代元素。


36
希望我能多次投票支持您!这比我不愿承认的更经常咬我。
亚历山大·瓦维克

2
这是正确的答案。但是,可能很难找到哪个父元素引起了问题。我编写了一个jquery脚本,以帮助在标识出问题的父级上标识溢出属性(只需在您的控制台中运行)。因为脚本只有几行,所以我添加了一个包含以下脚本的答案。
danday74 '18年

5
我错过了您的“父元素”中
che-azeh

5
我也错过了“ s” :(,这就是问题所在。在很多地方,人们写道您应该只检查父母而不是所有父母。我通过检查$(stickyElement).parents().css("overflow", "visible")在Web控制台中调用是否有帮助找到了我的问题,然后找到遥远的父母overflow:hidden造成了这个问题,我希望我能更仔细地阅读这个答案
Mariusz Pawelski '18

2
如果需要检查overflow:hidden,则可以在浏览器控制台中运行此脚本,以检查给定元素的所有父母/祖先: gist.github.com/brandonjp/478cf6e32d90ab9cb2cd8cbb0799c7a7
brandonjp

100

我有同样的问题,我在这里找到了答案。

如果您的元素不符合预期,则首先要检查的规则是应用于容器的规则。

具体来说,寻找在父级上设置的任何溢出属性。不能使用overflow: hiddenoverflow: scrolloverflow: auto在的父position: sticky元素。


这也是正确的答案,但也请参阅我的答案,这有助于轻松识别引起问题的父母。
danday74 '18年

9
您应该检查不但最靠近父容器,但所有的父元素小号
Mariusz Pawelski

是的,请参阅我的回答以做到这一点,并非常迅速地检查所有父母
danday74 '18

1
链接也对我有帮助。我的问题通过“ ...如果您不使用溢出但仍然有问题,则值得检查是否在父级上设置了高度...”解决了
xenetics

救生员,对问题的描述非常简单,但是对此有好奇吗?
Rahul Singh,

32

我碰到的几件事:

当您的粘性元素是组件(角度等)时

  • 如果“ sticky”元素本身是带有自定义元素选择器的组件,例如名为的角度组件<app-menu-bar>,则需要在组件的css中添加以下内容:

    :host { display: block; }   

    要么

    app-menu-bar  { display: block; }   // (in the containing component's css)

    尤其是iOS上的Safari似乎display:block甚至需要在app-root角度应用程序的根元素上使用,否则它不会卡住。

  • 如果要创建一个组件,定义组件内部的CSS(影子DOM /封装样式),确保position: sticky被应用到“外”选择(例如,app-menu-bar在devtools应显示粘的位置),而不是一个顶级div 组件。使用Angular,可以通过:host组件的CSS中的选择器来实现。

    :host
    {
        position: sticky;
        display: block;   // this is the same as shown above
        top: 0;
        background: red;    
    }

其他

  • 如果粘滞元素后面的元素具有固定背景,则必须添加以下内容以阻止其在下面滑动:

    .sticky-element { z-index: 100; }
    .parent-of-sticky-element { position: relative; }
  • 如果使用top,您的粘滞元素必须位于第一个位置(在内容之前),如果使用则必须在其之后bottom

  • overflow: hidden包装元素上使用会带来一些麻烦,通常会杀死里面的粘性元素。更好地解释了这个问题

  • 当屏幕键盘可见时,移动浏览器可能会禁用粘性/固定位置的项目。我不确定确切的规则(任何人都知道),但是当键盘可见时,您正在查看进入窗口的某种“窗口”,并且您将无法轻易将东西固定在窗口上屏幕的实际可见顶部。

  • 确保您具有:

    position: sticky;

    并不是

    display: sticky;

其他可用性问题

  • 如果您的设计要求将东西粘在移动设备的屏幕底部,请务必谨慎。例如,在iPhone X上,它们显示一条细线以指示滑动区域(以返回首页)-并且该区域内的元素不可单击。因此,如果您粘贴某些东西,请务必在iPhone X上测试用户可以激活它。如果人们无法点击“立即购买”按钮,那就不好了!
  • 如果您要在Facebook上做广告,则该网页将显示在Facebook的移动应用程序的“网络视图”控件中。特别是在显示视频时(您的内容仅在屏幕的下半部分开始)-它们通常将页面放在可滚动的视口中,从而完全弄乱了粘性元素,实际上使粘性元素从页面顶部消失了。确保在实际广告的环境中进行测试,而不仅仅是在手机的浏览器甚至Facebook的浏览器中进行测试,因为两者的行为可能会有所不同。

@Sergey我不是很清楚Safari会触发哪个错误display: blockposition: relative触发正确的行为-似乎只需要这样做display: block吗?当然,同时指定它们可能不会有什么坏处
Simon_Weaver

2
只是display: block足够
谢尔盖

27

这是MarsAndBack和Miftah Mizwar的答案的延续。

他们的答案是正确的。但是,很难确定问题祖先。

要使其变得非常简单,只需在浏览器控制台中运行此jQuery脚本,它将告诉您每个祖先上的overflow属性的值。

$('.your-sticky-element').parents().filter(function() {
    console.log($(this));
    console.log($(this).css('overflow'));
    return $(this).css('overflow') === 'hidden';
});

祖先没有overflow: visible更改其CSS的地方!

另外,如其他地方所述,请确保您的粘滞元素在CSS中具有以下内容:

.your-sticky-element {
    position: sticky;
    top: 0;
}

2
那很有帮助。我能够快速确定值为的父元素overflow: invisible
David Brower

4
如果页面上没有jQuery,则可以在控制台中运行此小片段以添加它: (async function() { let response = await fetch('https://code.jquery.com/jquery-3.3.1.min.js'); let script = await response.text(); eval(script); })();
magikMaker

8
您还可以运行不需要JQuery查找非“可见”溢出父级的代码段:开发人员工具中最后选择的元素var p = $0.parentElement; while(p != null) { var ov = getComputedStyle(p).overflow; if(ov !== 'visible') console.warn(ov, p); else console.log(ov, p); p = p.parentElement; }哪里。$0
Mariusz Pawelski,

12

我必须使用以下CSS使其起作用:

.parent {
    display: flex;
    justify-content: space-around;
    align-items: flex-start;
    overflow: visible;
}

.sticky {
    position: sticky;
    position: -webkit-sticky;
    top: 0;
}

如果以上都不起作用,那么...

遍历所有祖先并确保这些要素都没有overflow: hidden。您必须将其更改为overflow: visible


1
显示:flex做事情
MaciejLisCK,

6

如果遇到这种情况而粘滞不起作用-尝试将父项设置为:

display: unset

为我工作


这是一个。
mm-93

哦! 对于父元素具有有限高度的情况(例如导航栏容器或其他东西,而不是整个容器或页面容器),这似乎是一种变通方法-似乎stickies不喜欢滚动到其外部父母(这太荒谬了!)现在,每个人都需要如此幸运,以便能够将父母定为display: unset,这可能并不总是立即可行的
Ben Philipp

似乎还可以与contentsinitial(?)和inline
Ben Philipp

5

有趣的时刻对我来说并不明显:position: sticky如果您使用DevTools进行设置,至少在Chrome 70 中不会应用。


您是否有此资源或有关如何解决此问题的其他信息?
AJMansfield '18

5

似乎要粘贴的导航栏不应位于具有其他内容的任何div或部分中。在我将导航栏从与另一个topbar共享的div中取出时,所有解决方案都无法为我工作。


谢谢,这就是我想要的!对我来说,没有父母溢出,也没有任何身高问题。也很高兴在接受的答案中看到此信息。
saglamcem

我只是通过实验发现,即时贴不会滚动到其父元素之外。它有多少个同级兄弟并不重要,但是它的父级显然不能成为导航栏容器,而必须是页面/内容容器中的某个级别:(这很荒谬
Ben Philipp

但是,罗!如果可以,如果将限制父级设置为display: unset,则取消此限制!参见stackoverflow.com/a/60560997/2902367 也似乎可以与contentsinitial(?)和inline
Ben Philipp

4

从我的评论:

position:sticky 需要协调才能联系到哪里

nav {
  position: sticky;
  top: 0;
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}

body {
  height: 200vh;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

除FF和Chrome浏览器外,还有用于其他浏览器的polyfill。这是一个实验性规则,可以通过浏览器随时执行或不执行。Chrome在几年前添加了它,然后又放下了它,似乎又回来了……但是要持续多久?

最接近的将是position:relative + coordonates,滚动时一旦到达粘滞点,就会更新,如果您想将其转换为javascript脚本


4

我知道这似乎已经得到了回答,但是我遇到了一个具体情况,我觉得大多数答案都没说清楚。

overflow:hidden回答覆盖90%的病例。这或多或少是“粘性导航”的场景。

但是最好在容器的高度内使用粘性行为。考虑一下您网站右栏中的新闻通讯表单,该表单随页面向下滚动。如果您的粘性元素是容器的唯一子元素,则容器的大小完全相同,并且没有滚动空间。

您的容器必须是您希望元素在其中滚动的高度。在我的“右列”方案中,哪一个是左列的高度。实现此目的的最佳方法是display:table-cell在列上使用。如果不能,并且float:right像我以前那样受困,则必须猜测使用Javascript计算它的左列高度。


2
“如果您的粘性元素是容器的唯一子元素,则该容器的大小完全相同,并且没有滚动空间。” 金!!!谢谢!
马克·杰克逊

是! 花了我一段时间来解决这个问题。我最初发现这是一个荒谬的限制,但我认为至少应该有这样做的选择。无论如何sticky-limit: parent,我还是更喜欢像... sticky-limit: bodysticky-limit: nth-parent(3)... 这样的东西:如果可以,可以通过将限制父级设置为来解除此限制display: unset,如stackoverflow.com/a/60560997/2902367中所述。似乎还可以与contentsinitial(?)和inline
Ben Philipp

3

我知道这是旧帖子。但是,如果有像我这样的人最近才开始摆弄位置:粘性,这可能会很有用。

就我而言,我使用的是位置:粘性作为网格项目。它不起作用,问题是溢出-x:隐藏在html元素上。我删除该属性后,它就可以正常工作。在body元素上隐藏overflow-x:似乎行得通,还不知道为什么。


1

这里有两个答案:

  1. overflowbody标签中删除属性

  2. 设置height: 100%body解决问题overflow-y: auto

min-height: 100% 不起作用而不是 height: 100%


1

我相信这篇文章讲了很多关于如何sticky运作的内容

CSS Position Sticky如何真正发挥作用!CSS位置粘性有两个主要部分,粘性项目和粘性容器

粘性项目  -是我们使用以下位置定义的元素:粘性样式。当视口位置与位置定义匹配时,该元素将浮动,例如:top: 0px

粘性容器 —是包装粘性项目的HTML元素。这是粘性项目可以漂浮的最大区域。

当您定义具有位置:粘性的元素时,您会自动将父元素定义为粘性容器!


1

粘性元素的实际行为是:

  • 首先它是相对的
  • 然后固定一会儿
  • 最终,它从视野中消失了

粘滞放置的元素被视为相对放置,直到其包含的块在其流根(或在其中滚动的容器)内超过指定的阈值(例如,将顶部设置为auto以外的值),此时将其视为“卡住” ”,直到遇到其包含块的相对边缘。

根据文档的正常流程放置元素,然后根据top,right,bottom的值相对于其最近的滚动祖先和包含表相关元素的包含块(最近的块级祖先)偏移。走了。该偏移量不会影响任何其他元素的位置。

此值始终创建一个新的堆栈上下文。请注意,粘性元素“粘贴”到其最接近的祖先,该祖先具有“​​滚动机制”(在隐藏,滚动,自动或覆盖溢出时创建),即使该祖先不是最近的实际滚动祖先。

该示例将帮助您理解:

code https://codepen.io/darylljann/pen/PpjwPM


0

如果danday74的修复不起作用,请检查父元素是否具有高度。

就我而言,我有两个孩子,一个漂浮在左边,另一个漂浮在右边。我希望右浮动对象变得粘稠,但必须<div style="clear: both;"></div>在父级末尾添加一个,以增加高度。


不确定为什么有人会对此否决,但这完全是我的情况:我添加float:left到父元素(不包含float的高度为0)并position:sticky工作。
aexl

0

我使用了JS解决方案。它适用于Firefox和Chrome。有任何问题,请通知我。

html

<body>
  <header id="header">
    <h1>Extra-Long Page Heading That Wraps</h1>
    <nav id="nav">
      <ul>
        <li><a href="" title="">Home</a></li>
        <li><a href="" title="">Page 2</a></li>
        <li><a href="" title="">Page 3</a></li>
      </ul>
    </nav>
  </header>
  <main>
    <p><!-- ridiculously long content --></p>
  </main>
  <footer>
    <p>FOOTER CONTENT</p>
  </footer>
  <script src="navbar.js" type="text/javascript"></script>
</body>

的CSS

nav a {
    background: #aaa;
    font-size: 1.2rem;
    text-decoration: none;
    padding: 10px;
}

nav a:hover {
    background: #bbb;
}

nav li {
    background: #aaa;
    padding: 10px 0;

}

nav ul  {
    background: #aaa;
    list-style-type: none;
    margin: 0;
    padding: 0;

}

@media (min-width: 768px) {

    nav ul {
        display: flex;
    }
}

js

function applyNavbarSticky() {
    let header = document.querySelector('body > header:first-child')
    let navbar = document.querySelector('nav')
    header.style.position = 'sticky'

    function setTop() {
        let headerHeight = header.clientHeight
        let navbarHeight = navbar.clientHeight
        let styleTop = navbarHeight - headerHeight

        header.style.top = `${styleTop}px`
    }

    setTop()

    window.onresize = function () {
        setTop()
    }
}

0

z-index也很重要 有时它会起作用,但您只会看不到它。请确保将其设置为很高的数字。另外,不要总是放,top: 0但要尝试更高的东西以防隐藏在某个地方(在工具栏下)。


0

这就是让我绊倒的原因...我的粘性div位于另一个div内,以便父div在粘性div之后需要一些其他内容,以使父div足够“高”,以使粘性div可以“滑过”其他内容,例如您向下滚动。

因此,就我而言,在粘性div之后,我必须添加:

    %div{style:"height:600px;"} 
      &nbsp;

(我的应用程序有两个并排的div,左侧有一个“高”图像,右侧有一个简短的数据输入表单,我希望当您向下滚动时,数据输入表单会浮在图像旁边,因此表单始终显示在屏幕上。直到我添加了上述“额外内容”后,表单才起作用,因此粘性div可以“滑移”


-1

这是真实的,overflow需要被拆除或设置为initial使position: sticky子元素的作品。我在Angular应用程序中使用了Material Design,发现某些 Material组件更改了该overflow值。我的情况的解决方法是

mat-sidenav-container, mat-sidenav-content {
  overflow: initial;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.