I'm trying to use scroll snapping via the CSS scroll-snap-type and scroll-snap-align properties, but no matter what I do I end up making non-snapping elements unreachable.
In the example below, for example. the paragraphs (<p>) are all reachable and even snapping just fine, but the header (<h1>) becomes unreachable because when I try to scroll up to view it, I just get snapped back down to the first paragraph beneath it.
html {
scroll-snap-type: y mandatory;
height: 100vh;
overflow: scroll;
}
p {
background: pink;
padding: 3rem 4rem;
scroll-snap-align: start;
}
<h1>THIS IS UNREACHABLE</h1>
<p>1.1</p>
<p>1.2</p>
<p>1.3</p>
<p>1.4</p>
<p>1.5</p>
<p>1.6</p>
<p>2.1</p>
<p>2.2</p>
<p>2.3</p>
<p>2.4</p>
<p>2.5</p>
<p>2.6</p>
<p>3.1</p>
<p>3.2</p>
<p>3.3</p>
<p>3.4</p>
<p>3.5</p>
<p>3.6</p>
My question: Is there a way to achieve CSS scroll snapping without making non-snapping elements unreachable?
further notes:
You'll probably notice that I'm using scroll-snap-type on the <html> tag rather than using a container, which is apparently more typical. That's because using a container makes things even worse, introducing multiple scrollbars and confusion over whether the container or the <body> is being scrolled. Also, for the scroll-snapping design I'm trying to achieve to function, I would need to force the container itself to snap to the top of the viewport, which just brings us back to using <body>, or, since that simply doesn't work (don't know why), <html>.
It's not really possible. Because the scroll snapping API wasn't meant to be used with mixed non-snapping elements. I ran into the same issue myself, hence why I ended up on your entry. One thing that helps a little is to use proximity instead of mandatory on the html element.
Obviously that yields a different scroll feel that you might be going for. And it has its own shares of issues; such as when you refresh the page it might still scroll down to the first <p> element because it happens to be close enough for the proximity value to trigger. To kind of avoid this you can unset snapping on the first and last child with pseudo selectors.
In the demo below it looks like it might work, but this is where things go from bad to really bad. Let's say you want to have some content below the <p>'s that also doesn't snap. If you resize the window, while at the very bottom you'll notice that the window jumps back up to the last registered snap point. Same thing will happen to any layout shifts such as opening and closing an accordion, or browsing on a mobile device with a shifting url bar. Not ideal.
So in terms of viability; mixing snap enabled together with non-snapping elements is a rabbit hole of despair, dont do it.
html {
scroll-snap-type: y proximity;
height: 100vh;
overflow: scroll;
}
p:first-of-type {
scroll-snap-align: unset;
}
p {
background: pink;
padding: 3rem 4rem;
scroll-snap-align: start;
}
h2 { height: 150vh; }
<h1>THIS IS UNREACHABLE</h1>
<p>1.1</p>
<p>1.2</p>
<p>1.3</p>
<p>1.4</p>
<p>1.5</p>
<p>1.6</p>
<p>2.1</p>
<p>2.2</p>
<p>2.3</p>
<p>2.4</p>
<p>2.5</p>
<p>2.6</p>
<p>3.1</p>
<p>3.2</p>
<p>3.3</p>
<p>3.4</p>
<p>3.5</p>
<p>3.6</p>
<h2>content below</h2>
I have an interesting CSS / rendering issue with Microsoft Edge and scrollable content in divs that I'm trying to find a workaround for.
If the Edge browser window starts small enough that the div scrollbar is needed immediately, then most(!) of the time the scrollbar will be rendered correctly as below:
However if the browser window is resized or the content within the div changes so that a scrollbar is required, rendering of the scrollbar and parent div is performed incorrectly as shown below:
I've only observed this issue in Edge so far so believe it's an Edge only peculiarity.
Here's the url if you'd like to try it out: https://www.topomap.co.nz/#ShareMap
The CSS for the div is:
.sidebar-scrollable-area {
position: absolute;
width: 235px;
top: 38px;
bottom: 0px;
overflow: auto;
padding-right: 15px;
padding-top: 15px;
}
Setting overflow to either auto or scroll results in the same issue manifesting.
Does anyone have any ideas that I can try as a fix / workaround?
I believe this is an Edge specific rendering bug. I'm currently porting the site from Google Maps to Leaflet which gave me a chance to observe that the rendering issue seems to capture a static snapshot of whatever content is under the div when the issue occurs.
As a result I've lodged an error report with Microsoft:
https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/17459668/
The screenshot below demonstrates the rendering issue:
I have this interface concept and I just don't know if it's possible. It's kinda hard to explain so I sketched it out.
I think I know how to accomplish some behaviour:
<header> position: fixed;
<nav> position: sticky (with a polyfill)
<section class="content box"> --- no idea really
I was hoping there would be some kind of way to add a clip-path to the content box that I could position: fixed. So that when the user scrolls the content box would peep trhough the area which was defined by the clip-path.
Looked into quite some options and thought I'd found a solution in webkit-mask-attachment but that property was nuked.
Any help is welcome. I prefer a pure CSS solution which has to work responsively.
Cheers,
Bart!
PS. I have thought of a javascript solution where I monitor the scroll offset and change the class of <header> in which I set a height and overflow: hidden. But I really would prefer it if there was a CSS solution.
UPDATE 1
I'm on to something. Working in Firefox only since I'm using position: sticky and haven't bothered polyfilling it. It works when you scroll.... but if you scroll down and wait a couple of seconds somehow stuff gets repositioned or redrawn and the red header is shown fully again.
Any idea why this happens?
Try out this pen on Firefox: http://codepen.io/anon/pen/GJBxYw
Ah, found it! Strange behaviour. In order to hide the svg object I set the css properties for svg to:
svg { display: none; }
Now somehow when scrolling this doesn't matter. But when you scroll the css rule kicks in. So in order to hide the svg object I changed the rule to:
svg {
position: fixed;
z-index: -1;
top: 0;
height: 0;
width: 0;
}
And that seems to work. Don't know if there are better ways to go about hiding the svg object?
Try out this updated pen on Firefox: http://codepen.io/anon/pen/GJBxYw
Haven't done any serious FED since XHTML so I'm quite proud of myself, go easy on me :)
When scrolling on a website I've built, using the CSS property position: fixed works as expected to keep a navigation bar at the very top of the page.
In Chrome, however, if you use the links in the navigation bar it sometimes disappears. Usually, the item you've clicked on is still visible, but not always. Sometimes the entire thing disappears. Moving the mouse around brings back part of the element, and scrolling with the scroll wheel or arrow keys just one click brings the element back. You can see it happening (intermittently) on https://nikeplusphp.charanj.it - you might have to click on a few of the navigation the links a few times to see it happen.
I've also tried playing with the z-index and the visibility/display type but with no luck.
I came across this question but the fix didn't work for me at all. Seems to be a webkit issue as IE and Firefox work just fine.
Is this a known issue or is there a fix to keep fixed elements visible?
Update:
Only effects elements that have top: 0;, I tried bottom: 0; and that works as expected.
Add -webkit-transform: translateZ(0) to the position: fixed element. This forces Chrome to use hardware acceleration to continuously paint the fixed element and avoid this bizarre behavior.
I created a Chrome bug for this https://bugs.chromium.org/p/chromium/issues/detail?id=288747. Please star it so this can get some attention.
This fixes it for me:
html, body {height:100%;overflow:auto}
I was having the same issue with Chrome, it seems to be a bug that occurs when there is too much going on inside the page, I was able to fix it by adding the following transform code to the fixed position element, (transform: translateZ(0);-webkit-transform: translateZ(0);) that forces the browser to use hardware acceleration to access the device’s graphical processing unit (GPU) to make pixels fly. Web applications, on the other hand, run in the context of the browser, which lets the software do most (if not all) of the rendering, resulting in less horsepower for transitions. But the Web has been catching up, and most browser vendors now provide graphical hardware acceleration by means of particular CSS rules.
Using -webkit-transform: translate3d(0,0,0); will kick the GPU into action for the CSS transitions, making them smoother (higher FPS).
Note: translate3d(0,0,0) does nothing in terms of what you see. it moves the object by 0px in x,y and z axis. It's only a technique to force the hardware acceleration.
#element {
position: fixed;
background: white;
border-bottom: 2px solid #eaeaea;
width: 100%;
left: 0;
top: 0;
z-index: 9994;
height: 80px;
/* MAGIC HAPPENS HERE */
transform: translateZ(0);
-webkit-transform: translateZ(0);
}
The options above were not working for me until I mixed two of the solutions provided.
By adding the following to the fixed element, it worked. Basically z-index was also needed for me:
-webkit-transform: translateZ(0);
z-index: 1000;
This is a webkit issue that has yet to be resolved, oddly making the jump with JavaScript, rather than using the # url value, doesn't cause the problem. To overcome the issue, I supplied a JavaScript version that takes the anchor value and finds the absolute position of the element with that ID and jump to that:
var elements = document.getElementsByTagName('a');
for(var i = 1; i < elements.length; i++) {
elements[i].onclick = function() {
var hash = this.hash.substr(1),
elementTop = document.getElementById(hash).offsetTop;
window.scrollTo(0, elementTop + 125);
window.location.hash = '';
return false;
}
}
I could refine this further and make it is that only it only looks for links beginning with a #, rather than ever a tag it finds.
If it don't work after adding
-webkit-transform: translateZ(0)
than also add
user-scalable=no
on viewport meta
source here
it worked for me
I encountered the same issue in a different case. It was because of usage of same id in multiple place. For example i used #full 2 divs.
It seems that mozilla and I.E. supports usage of same id in multiple cases. But chrome doesnot. It reacted with fixed element disappering in my case.
Just removing the id's solved the problem.
None of them worked for me except calling the modal via javascript
Click me to open MyModal
<script>
function show_modal()
{
MyModal.style.display = 'block';
}
</script>
other than this, none of the solutions above solved my problem.
This Worked for me . Add Overflow property to your top most container which can be Div or Form etc.
div, form
{
overflow:visible;
}
The same issue happened to me. For the main page of the website. I made a fixed header and Used an image for the front poster. Everything worked fine. But the moment I changed the opacity of the poster image my header with position: fixed; got disappeared. It was present there in the chrome developer tools. But was totally transparent on the website.
I tried every solution from StackOverflow, W3shools, Geeke4geeks. But if one thing was fixed another thing got messed up.
So I just opened photoshop and edited the image manually. And then posted it on my website.
It worked.
But still, it won't be effective for divs under the fixed elements.
If none of the answers above worked for you, make sure you aren't a dummy like me and have overflow: hidden; set on the fixed element :(
What if none of above worked at all? simple case of sticky header + mobile side menu pushing content.
I try to find a way to avoid fixed element (sticky header) being translated but in this case nothing is a good alternative.
So as there is no workaround on scope so far there is a JS alternative that I opted for to recalculate absolute position of fixed element. See here: https://stackoverflow.com/a/21487975/2012407
In my case, I just added min-height: 100vh; to fixed element, may be that will be useful for somebody
I've just noticed that Firefox 12 and 13 won't show horizontal bar when the page gets x overflow. I tried to make CSS declaration:
html {
overflow-x: scroll !important;
}
but it doesn't help.
Any ideas? Thanks
The line in the jquery-ui style sheet that causes this is:
.ui-helper-hidden-accessible { .position: absolute; left: -99999999px; }
If you change it to the following you should see your scrollbars again:
.ui-helper-hidden-accessible { /*.position: absolute; */ left: -99999999px; }
Although I have no clue what so ever what other effects this change might have. I don't know what that element is used for.
Make sure you have not made a mistake elsewhere, try it in another browser first to make sure then strip all the CSS and just replace it with html {
overflow-x: scroll !important;
} and see if it works, if you did anything with changing the width of the page it would change the effect on the page.
I assume, that there is actually some overflow to display?
Same issue. Page looks fine in chrome, IE and FF11. I can make it go away by disabling http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.3/themes/base/jquery-ui.css (via WebDeveloper toolbar). Can't find a root cause yet though.
I don't think you want to do this...
.ui-helper-hidden-accessible { /*.position: absolute; */ left: -99999999px; }
this will cause these elements to show on screen, when they are supposed to be positioned off to the left. As these elements probably don't always exist you'll be putting a "bug in the bank" for later on, one day you'll get a load of elements showing up on your site that should be invisible. Which will be really hard to debug!
This issue looks like it might be related to this https://bugzilla.mozilla.org/show_bug.cgi?id=749935 large number issue, you could try reducing the size of the number (-99999999)?