0

HTML elements affixed to the top of the page using CSS position property set to either fixed or sticky can often work just fine on desktops, but mobile web browsers behave vastly differently due to the resizing nature of the address bar UI.

Setup

This issue happens when the element fixed to the top is nested within an HTML hierarchy, but not when it's placed directly within the body of the document. There are of course some additional assumptions (i.e. styling of the html and body elements), so I'm providing a minimum POC to reproduce the behaviour.

Example

When the website is first loaded, the element with a position fixed to the top of the screen will display below an initially expanded address bar. When the user scrolls the page down, the address bar will shrink to a more compact version, causing viewport to change size. Simultaneously, the element fixed to the top will also change its position and get occluded by the address bar in the process. When the user then scrolls back up, the address bar will expand and consequently, unveil the fixed element. Interestingly, this behaviour isn't "1:1" and subsequently scrolling up and down just enough to occlude and unveil the element results in a net scroll down (on scroll-up, the element is unveiled at a higher rate while on scroll-down the element gets occluded proportionally to the scroll speed).

enter image description here

Reproducing the issue:

<html> <head> <style> html { min-height: 100%; background: lightblue; } body { margin: 0; min-height: 100%; } .navbar { background: lightcoral; height: 5rem; position: fixed; top: 0; width: 100%; } p { font-size: 1.5rem; } </style> </head> <body> <div> <div class="navbar"> <p>navbar</p> </div> </div> <div class="content"> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <!-- Add more to fill up the viewport if needed --> </div> </body> </html> 

Partial fix

Moving the element to be a direct child of the body solves this issue.

enter image description here

Code for the partial fix

<html> <body> <!-- <div> --> <div class="navbar"> <p>navbar</p> </div> <!-- </div> --> <div class="content"> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <!-- Add more to fill up the viewport if needed --> </div> </body> </html> 
2
  • Why is the solution titled partial fix? Is it not working as expected? Just curious. Commented Oct 24 at 10:25
  • @natashap It's only a partial fix, because moving elements around within the DOM hierarchy is not always possible. This is particularly the case when using layouts that structure the main page elements (such as header or footer) but additional elements need to be pinned to the top from their children. For example, imagine you have a layout that defines header, footer and main page content. A specific page using that layout may want to pin additional header to the top, but at that point, its contents are always going to be within the layout's main content. Commented Oct 25 at 9:35

1 Answer 1

0

This issue can be fixed without modifying the HTML hierarchy, by instead setting the unicode-bidi property to isolate on the element whose position is fixed or sticky, i.e.:

.navbar { /* ... */ unicode-bidi: isolate; } 

In the case of the above example:

<html> <head> <style> html { min-height: 100%; background: lightblue; } body { margin: 0; min-height: 100%; } .navbar { background: lightcoral; height: 5rem; position: fixed; top: 0; width: 100%; unicode-bidi: isolate; /* <-- HERE */ } p { font-size: 1.5rem; } </style> </head> <body> <div> <div class="navbar"> <p>navbar</p> </div> </div> <div class="content"> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <!-- Add more to fill up the viewport if needed --> </div> </body> </html>

Sign up to request clarification or add additional context in comments.

2 Comments

I turned your answer into a minimal reproducible example and it doesn't work. What's the point of the unicode-bidi property here?
@imhvost, thanks for turning the snippet to a runnable code. This helped me realise that there was a typo in the class attribute I forgot to change from className (in testing I was using React which uses className). After updating the code to use class correctly, the code works. As for the unicode-bidi, frankly I'm stumped myself! I plan on updating the answer once I understand why and how this works to begin with, since MDN's documentation only states that it determines how bidirectional text is handled.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.