Overlay divs on scroll
Here is a proof of concept that, whilst works, does need to be tested across browsers (however I'm confident that it will work everywhere) and slightly refined.
The idea is to use JavaScript to monitor the window's scroll position and fix the appropriate content panel accordingly, giving the illusion that the new content is overlapping it when scrolling in to view.
http://jsfiddle.net/amustill/wQQEM/
Overlay 2 DIVs where one is Static and the other is Scrollable
You can achieve that with these steps:
- Set the
position
of the container (i.e. homepage) torelative
. - Set the
position
of the hero tofixed
, so it doesn't scroll with the container. - Set the
position
of the frames toabsolute
withz-index
higher than the hero so it can overlay it.
You can see the example below. I set the container background color so we can see it and set its height to 1000px
so we can test it scrolling, so those settings are for demo purpose only.
To center your hero and frames, you need these steps:
- Set the left and right margins to
auto
. - Set a fixed width. This is required for the auto margins to work.
- Set the
left
andright
to zero. This is required forfixed
andabsolute
layouts to be centered.
.homepage { background-color: #0ff; height: 1000px; position: relative;}
.hero-image { position: fixed; width: 150px; margin: 0 auto; left: 0; right: 0;}
.homeScreen1 { position: absolute; width: 160px; margin: 0 auto; top: 200px; left: 0; right: 0; z-index: 1;}
<div class="homepage"> <div class="hero-image"> <img src="http://placehold.it/150x150"> </div> <div class="homeScreen1"> <img src="http://placehold.it/160x160"> </div> </div>
CSS overlay with scrolling content
You can avoid adding a container to your Bottom element by moving its height to an ::after
pseudo-element:
.bottom {
overflow-y: scroll;
height: calc(100% - 80px);
}
.bottom::after {
content: '';
display: block;
height: 10000px;
}
Updated Fiddle
Prevent body scrolling but allow overlay scrolling
Theory
Looking at current implementation of the pinterest site (it might change in the future), when you open the overlay, a noscroll
class is applied to the body
element (setting overflow: hidden
) making the body
no longer scrollable.
The overlay created on-the-fly or already injected in the page and made visible via display: block
— it makes no difference – has position : fixed
and overflow-y: scroll
, with top
, left
, right
and bottom
properties set to 0
: this style makes the overlay fill the whole viewport (but now we are in 2022, so you may use inset: 0
instead).
The div
inside the overlay is in position: static
so the vertical scrollbar is related to that element. This is resulting in a scrollable but fixed overlay.
When you close the overlay, you have to hide it (using display: none
) and you could even remove the node via javascript (or just the content inside, it's up to you but also depends on the nature of the content).
The final step is to also remove the noscroll
class applied to the body
(so the overflow
property gets back to the value it had previously)
Code
Codepen Example
(it works by changing the aria-hidden
attribute of the overlay in order to show and hide it and to increase its accessibility).
Markup
(open button)
<button type="button" class="open-overlay">OPEN LAYER</button>
(overlay and close button)
<section class="overlay" aria-hidden="true" tabindex="-1">
<div>
<h2>Hello, I'm the overlayer</h2>
...
<button type="button" class="close-overlay">CLOSE LAYER</button>
</div>
</section>
CSS
.noscroll {
overflow: hidden;
}
.overlay {
position: fixed;
overflow-y: scroll;
inset: 0; }
[aria-hidden="true"] { display: none; }
[aria-hidden="false"] { display: block; }
Javascript (vanilla-JS)
var body = document.body,
overlay = document.querySelector('.overlay'),
overlayBtts = document.querySelectorAll('button[class$="overlay"]'),
openingBtt;
[].forEach.call(overlayBtts, function(btt) {
btt.addEventListener('click', function() {
/* Detect the button class name */
var overlayOpen = this.className === 'open-overlay';
/* storing a reference to the opening button */
if (overlayOpen) {
openingBtt = this;
}
/* Toggle the aria-hidden state on the overlay and the
no-scroll class on the body */
overlay.setAttribute('aria-hidden', !overlayOpen);
body.classList.toggle('noscroll', overlayOpen);
/* On some mobile browser when the overlay was previously
opened and scrolled, if you open it again it doesn't
reset its scrollTop property */
overlay.scrollTop = 0;
/* forcing focus for Assistive technologies but note:
- if your modal has just a phrase and a button move the
focus on the button
- if your modal has a long text inside (e.g. a privacy
policy) move the focus on the first heading inside
the modal
- otherwise just focus the modal.
When you close the overlay restore the focus on the
button that opened the modal.
*/
if (overlayOpen) {
overlay.focus();
}
else {
openingBtt.focus();
openingBtt = null;
}
}, false);
});
/* detect Escape key when the overlay is open */
document.body.addEventListener('keyup', (ev) => {
if (ev.key === "Escape" && overlay.getAttribute('aria-hidden') === 'false') {
overlay.setAttribute('aria-hidden', 'true');
body.classList.toggle('noscroll', false);
openingBtt.focus();
openingBtt = null;
}
})
Finally, here's another example in which the overlay opens with a fade-in effect by a CSS transition
applied to the opacity
property. Also a padding-right
is applied to avoid a reflow on the underlying text when the scrollbar disappears.
Codepen Example (fade)
CSS
.noscroll { overflow: hidden; }
@media (min-device-width: 1025px) {
/* not strictly necessary, just an experiment for
this specific example and couldn't be necessary
at all on some browser */
.noscroll {
padding-right: 15px;
}
}
.overlay {
position: fixed;
overflow-y: scroll;
inset: 0;
}
[aria-hidden="true"] {
transition: opacity 1s, z-index 0s 1s;
width: 100vw;
z-index: -1;
opacity: 0;
}
[aria-hidden="false"] {
transition: opacity 1s;
width: 100%;
z-index: 1;
opacity: 1;
}
How to get overlay to cover the entire page even when scrolling
just move: background: #dff9fb;
from .popup
to .overlay
* {padding: 0; margin: 0; box-sizing: border-box; }
body { padding: 152px 32px; position: relative; }
.overlay-text { height: 100%; min-height: 100%;}
.overlay { z-index: 10; position: fixed; top: 0; left: 0; bottom: 0; right: 0; width: 100%; height: 100vh; visibility: hidden; opacity: 0; overflow-y: scroll; background: #dff9fb;}
.overlay:target { visibility: visible; opacity: 1;}
iframe { margin: 0 auto; display: block;}
.popup { height: 100%; position: relative; padding-top: 24px;}
.close { position: absolute; top: 12px; right: 16px;}
<ul>
<li>
<a href=#popup1> <img class="new-tracks__image" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1774776/new.jpg"></a>
<div id="popup1" class="overlay"> <div class="popup">
<h2>Jerry Craft - <em>"New Kid"</em></h2>
<iframe src="https://open.spotify.com/embed/album/2yFC1YqdyPHnpCGJubdGaK" width="300" height="80" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>
<div class="overlay-text"> <p>The three Greystone kids always raced each other home when they got off the school bus, and Finn always won.</p>
<p>It wasn’t because he was the fastest.</p>
<p>Even he knew that his older brother and sister, Chess and Emma, let him win so he could make a grand entrance.</p>
<p>Today he burst into the house calling out, “Mom! We’re home! It’s time to come and adore us!”</p>
<p>“Adore” had been on his second-grade spelling list two weeks ago, and it had been a great discovery for him. So that was what it was called, the way he had felt his entire life.</p>
<p>Emma, who was in fourth grade, dropped her backpack on the rug beside him and kicked off her red sneakers. They flipped up and landed on top of the backpack—someday, Finn vowed, he would get Emma to teach him that trick.</p>
<p>“Twenty-three,” Emma said. There was no telling what she might have been counting. Finn hoped it was a prediction of how many chocolate chips would be in every cookie Mom was probably baking for them right now, for their after-school snack.</p>
<p>Finn sniffed. The house did not smell like cookies.</p>
<p>Oh well. Mom worked from home, designing websites, and sometimes she lost track of time. If today was more of a Goldfish-crackers-and-apple-slices kind of day, that was okay with Finn. He liked those, too.</p>
<p>“Mom!” he called again. “Your afternoon-break entertainment has arrived!”</p>
<p>“She’s in the kitchen,” Chess said, hanging his own backpack on the hook where it belonged. “Can’t you hear?”</p>
<p>“That would mean Finn had to listen for once, instead of talking,” Emma said, rubbing Finn’s head fondly and making his messy brown hair even messier. Finn knew she didn’t mean it as an insult. He was pretty sure Emma liked talking as much as he did.</p>
<a class="close" href="#">×</a> </div> </div> </li>
</ul>
Pure CSS overlay scrolling
position:sticky
can approximate this:
.headervideo {
background: url(https://picsum.photos/id/1064/800/800) center/cover;
height: 100vh;
position: relative;
z-index: 2;
}
.nextsection {
background: url(https://picsum.photos/id/107/800/800) center/cover;
height: 100vh;
margin-top: -100vh;
position: sticky;
top: 0;
}
.container {
height:200vh;
}
body {
margin: 0;
}
<div class="container">
<div class="headervideo"></div>
<div class="nextsection"></div>
</div>
<div style="height:150vh"> more content later </div>
Related Topics
How Do Make Ionic 4 Ion-Col The Same Height
Why Do My Icons Line Up Top-To-Bottom Instead of Flowing Left-To-Right in a Div Layout
Adding Dynamic Class Name in Svelte
What CSS Is Used by Browsers for Styling Invalid <Input Type="Email">S
Why <Big> Is Not in HTML 5 Tag List While <Small> Is
How to Set The Current Frame (Or Similar) of a CSS Animation
HTML/CSS - Div Element Hidden When It Shouldn't Be
The Name 'Media' Does Not Exist in The Current Context
Center Div Vertically in Flexbox Container with Stretch Alignment
Email Clients Ignoring Internal Style Sheet
How to Add Custom Breakpoints in Bootstrap4 and How to Use Responsive Breakpoint Mixins in SCSS
Jekyll Liquid Variables as Inline CSS Values
CSS "Height: [Percentage]" Behaviour Using "Margin" And/Or "Padding"
Copy Chrome Default Input's Outline Style