body { overflow-x: hidden; } breaks position: sticky
Asked Answered
U

11

63

I have an element that I am making sticky with position sticky:

#header {
    position: sticky;
    width: 100vw;
    top: 0;
}
<app-header id="header"></app-header>

And that works fine, but I realised that if I use:

body {
  overflow-x: hidden;
}

That breaks sticky, and I need to set body overflow-x to hidden, how can I fix that, with only CSS solution, no JS solutions?

Undertaking answered 3/11, 2017 at 12:16 Comment(3)
Note that sticky, by specification, will not work inside element with overflow: hidden or auto. Also, position: sticky is an experimental API and should not be used in production, just a heads up (in case you aren't already aware of that) see: developer.mozilla.org/en-US/docs/Web/CSS/position#stickyMohammed
Yes, wasn't aware of that, thank you for pointing this outUndertaking
The only way I was able to fix this was to unset that overflow-x with something like overflow-x: initial;. A year later and position: sticky is no longer experimental and works cross browser (minus good ol' IE) :)Historied
A
60

Setting the overflow-x property to value clip helped me achieve position sticky and prevent scrolling.

Here is more explanation in this article

Argueta answered 25/2, 2022 at 16:40 Comment(4)
omfg i've been struggling with this for hours now, and your simple solution did the trick for me! ThanksNaples
it doesn't work in SafariAforetime
Only works in Safari 16+ Anyone with an older version will still be affected.Periotic
How did I not find out about that sooner? Works great! And browser support is good as well now caniuse.com/mdn-css_properties_overflow_clipAmok
H
25

UPDATE:

This has been successfully tested on Safari v12.0.2, Firefox v64.0, and Chrome v71.0.3578.98

Added position: -webkit-sticky; for Safari.


Unfortunately the spec is not too clear about the implications of overflow-x: hidden; on position sticky, but there is a way to fix this. Thankfully there is an issue to hopefully fix this: https://github.com/w3c/csswg-drafts/issues/865.

The simple solution is to remove or unset overflow-x: hidden; from every ancestor of the element you want to have position: sticky;. Then you can have overflow-x: hidden; on the body and it will work!

Also double check that you don't have overflow set on both the body and html tags which I posted about more in depth here: https://mcmap.net/q/323085/-position-sticky-not-working-with-body-overflow-x-hidden-duplicate

Here is a pen if you want to play around with it: https://codepen.io/RyanGarant/pen/REYPaJ

/* 
  Try commenting out overflow on body style and uncommenting
  overflow on .overflow-x-hidden class and you will see 
  position sticky stop working!  
*/

body {
  overflow-x: hidden;
}

.overflow-x-hidden {
/*   overflow-x: hidden; */
  border: 1px solid blue;
}

h1 {
  background: palevioletred;
  color: #fff;
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}

.tall {
  background: linear-gradient(to bottom, paleturquoise, white);
  height: 300vh;
  width: 100%;
}
<div class="overflow-x-hidden">
  <h1>I want to be sticky!</h1>
  
  <div class="tall"></div>
</div>
Historied answered 9/1, 2019 at 18:55 Comment(6)
Currently (Firefox 78, Chrome 84) this doesn't seem to work any more. Verified by toggling the overflow-x:hidden property on the body element.Impede
"The simple solution is to remove or unset overflow-x: hidden; from every ancestor of the element you want to have position: sticky;" Isn't the body tag an ancestor of every element anyway?Snell
Your "both the body and html tags" url links to itself. Is there any more info somewhere becasue I need to have it on both html and body because of stackoverflow.com/questions/3047337Microbicide
Did you see this link I added @FINDarkside? https://mcmap.net/q/323085/-position-sticky-not-working-with-body-overflow-x-hidden-duplicateHistoried
This does now work. Note that Safari's html {overflow-x:hidden; } behavior seems to be different inside an <iframe> (like Codepen is using) than when you view the same page in full window (un-framed)Periotic
OH MY STARS this freakin fixed so many projects > Also double check that you don't have overflow set on both the body and html tagsBoat
R
9
body, html { overflow-x: clip; } 

This works well with position: sticky

Im using transform: translateX(-100px) for load animations and overflow-x:clip prevents expanding the viewport and showing horizontal scrollbar..

Russellrusset answered 20/7, 2022 at 11:42 Comment(1)
Yes: for Android it is necessary to declare the two selectors (html + body).Stratification
R
6

I think you have to fix :

body {
  overflow-x: clip;
}

I hope this works .

Rajiv answered 26/7, 2022 at 7:11 Comment(1)
It works, but only in Safari 16+ All older Safaris are still affected.Periotic
B
5

The sticky doesn't work inside element with overflow: hidden or auto. Refer to this https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky

A workaround can be working with this library

Bourbon answered 3/11, 2017 at 12:28 Comment(3)
Hmmm, the link you advise the OP to refer to doesn't mention anything about how position: sticky will not work inside elements with overflow: hidden/auto - the MDN document does, but not at the section you've anchored to. Also, when you repeat what has already been established in the comments it looks like you are just trying to reputation farm.Predilection
Your are right it does but in the upper definition I just corrected, thanksBourbon
Same problem facing how to run both body {overflow-x: hidden} and child is position: stickyJury
H
2

My solution is to replace overflow: hidden with this:

display: flow-root;
overflow: clip;
Histoplasmosis answered 28/3, 2023 at 19:50 Comment(0)
S
1

Not sure if this helps, but I struggled with this for mobile (where the page would "overflow" and scroll past the boundaries) for so long and finally fixed it.

I tried the body {overflow: hidden;} solution, but it would disable my sticky elements. So I then created a <div class="container"> that contained all of my other divs of the page inside the <body>, and that seemed to do it!

Sihunn answered 30/1, 2021 at 23:3 Comment(0)
M
1

I just want to add this here if anyone runs into a similar issue. position:sticky was not working for me because we are applying overflow-y:scroll on tablet/mobile screen resolutions. overflow: and position:sticky do not work together. This article explains the 2 workarounds to fix it. I went with setting a fixed height on the table and then hiding the vertical scroll bar with

::-webkit-scrollbar {
  width: 0;  
  background: transparent;  
}::-webkit-scrollbar {
  width: 0;  
  background: transparent;  /* 
}
Meyers answered 31/7, 2021 at 18:42 Comment(0)
I
1

This is how I make it work for me:
Create a parent wrapper/container element that should contains all your other page elements, and give it a fixed height (mostly height: 100vh) with overflow-y: auto and overflow-x: hidden as it's described in the code/snippet below ..
and make the body overflow: hidden to avoid any extra scroll bars ..

This solution may comes with some consequences/restrictions, for example:
if you're used to use the CSS scroll-behavior property in the html element you will need then to move it to the #page_wrapper element instead ..

body {
  margin: 0;
  overflow: hidden;
}

.page-wrapper {
  height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
}

.sticky {
  position: sticky;
  left: 0;
  padding: 4px;
  text-align: center;
  background-color: forestgreen;
}

.sticky-header {
  top: 0;
}
.sticky-footer {
  bottom: 0;
}

.long-content {
  padding: 2rem;
  min-height: 100vh;
}

.break-overflow-x {
  min-width: 200vw;
  padding: 2rem;
  background-color: red;
}
<body>
  <div class="page-wrapper">
    <div class="sticky sticky-header"><button>Sticky Header</button></div>
    <div class="long-content">Long vertical content</div>
    <div class="break-overflow-x">Long horizontal content</div>
    <div class="long-content">Long vertical content</div>
    <div class="sticky sticky-footer"><button>Sticky Footer</button></div>
  </div>
</body>
Iatry answered 10/12, 2021 at 15:26 Comment(0)
M
-1

can you try with the following...

#one { position: sticky; top: 10px; }* {
  box-sizing: border-box;
}
body{overflow-x: hidden;}
dl > div {
  background: #FFF;
  padding: 24px 0 0 0;
}

dt {
  background: #B8C1C8;
  border-bottom: 1px solid #989EA4;
  border-top: 1px solid #717D85;
  color: #FFF;
  font: bold 18px/21px Helvetica, Arial, sans-serif;
  margin: 0;
  padding: 2px 0 0 12px;
  position: -webkit-sticky;
  position: sticky;
  top: -1px;
}

dd {
  font: bold 20px/45px Helvetica, Arial, sans-serif;
  margin: 0;
  padding: 0 0 0 12px;
  white-space: nowrap;
}

dd + dd {
  border-top: 1px solid #CCC;
}
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/position -->

<dl>
  <div>
    <dt>A</dt>
    <dd>Andrew W.K.</dd>
    <dd>Apparat</dd>
    <dd>Arcade Fire</dd>
    <dd>At The Drive-In</dd>
    <dd>Aziz Ansari</dd>
  </div>
  <div>
    <dt>C</dt>
    <dd>Chromeo</dd>
    <dd>Common</dd>
    <dd>Converge</dd>
    <dd>Crystal Castles</dd>
    <dd>Cursive</dd>
  </div>
  <div>
    <dt>E</dt>
    <dd>Explosions In The Sky</dd>
  </div>
  <div>
    <dt>T</dt>
    <dd>Ted Leo &amp; The Pharmacists</dd>
    <dd>T-Pain</dd>
    <dd>Thrice</dd>
    <dd>TV On The Radio</dd>
    <dd>Two Gallants</dd>
  </div>
</dl>
  
Metathesize answered 9/7, 2018 at 12:14 Comment(0)
A
-2

For those who have the same issue. I added overflow: hidden to the div below the header holding all the contents.

 <div class="header" style="position: sticky;">
        //navs
 </div>
 <div class="content-div" style="overflow: hidden;">
       //contents 
 </div>
Accessary answered 16/8, 2021 at 1:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.