-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
208 lines (179 loc) · 13.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
<html>
<head>
<style>
/**
* To make understanding the demo easier, i've separated layout
* related styles and reast of the styles such as colors and fonts.
*/
/**
* LAYOUT RELATED STYLES
*/
.container {
overflow-y: scroll;
box-sizing: border-box;
width: 500px;
height: 90vh;
max-height: 500px;
}
.article {
padding: 30px;
}
.header {
--header-sticky-top: 15px;
--header-sticky-bottom: 20px;
position: sticky;
top: var(--header-sticky-top);
bottom: var(--header-sticky-bottom);
}
.header-sentinel {
position: absolute;
left: 0;
width: 100%;
height: 1px;
pointer-events: none;
}
.header-sentinel-top {
top: calc(-1px + -1 * var(--header-sticky-top));
}
.header-sentinel-bottom {
bottom: calc(-1px + -1 * var(--header-sticky-bottom));
}
/**
* PRESENTATION RELATED STYLES
*/
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 15px;
}
.container {
border: 10px solid darkgrey;
}
.article {
margin-bottom: 30px;
background: antiquewhite;
}
.header {
padding: 5px;
color: #fff;
border-radius: 3px;
background: #0073ff;
font-size: 3em;
}
.header.stuck-to-top {
background: darkgreen;
}
.header.stuck-to-bottom {
background: darkmagenta;
}
.header-sentinel {
background-color: red;
}
</style>
</head>
<body>
<div class="last-event">Scroll to get some events...</div>
<div class="container">
<div class="article">
<div class="header">
Article - 1
<div class="header-sentinel header-sentinel-top"></div>
<div class="header-sentinel header-sentinel-bottom"></div>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec aliquet placerat tortor, non posuere lectus viverra eget. Fusce dictum nulla eget vestibulum porttitor. Mauris mollis metus non lacinia rutrum. Ut venenatis interdum odio, sit amet efficitur ex tincidunt ac. Morbi dictum hendrerit metus sed auctor. Vivamus quam sem, convallis maximus interdum sed, mattis id leo. Morbi faucibus lorem et nisi sodales dictum. Sed elit diam, elementum eu ultrices eget, varius et quam. Vivamus malesuada dignissim nisi, ut fermentum ex gravida non. Maecenas auctor mi vitae dolor aliquam, non imperdiet eros porttitor. Etiam erat lacus, dignissim et nulla eu, mollis placerat ante. Quisque ac mattis diam, at convallis nibh. Fusce in neque accumsan arcu rutrum faucibus. Nam in ex porttitor, pretium massa at, varius ex.</p>
<p>Vivamus lacinia fermentum gravida. Nulla facilisi. Nunc ultrices congue velit, non convallis diam mollis ac. Suspendisse ut tempus odio, sit amet tincidunt orci. Suspendisse aliquet ipsum quis ultrices blandit. Donec ut sagittis metus. Nullam ac nibh et enim porttitor aliquet id non dui.</p>
<p>Suspendisse vel purus auctor, tristique dui at, elementum felis. Donec metus mauris, ornare quis tempor id, pellentesque ac felis. Curabitur lacinia malesuada massa quis sagittis. Cras finibus elementum finibus. Ut in leo faucibus urna aliquam condimentum. Donec non hendrerit orci. Ut at aliquet dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam elementum lacus eu malesuada aliquam. Nulla dictum metus non ipsum dignissim, at rutrum diam rhoncus. Morbi tempor erat nec nisi ornare rutrum eu in orci. In dolor ante, pharetra sodales ornare sit amet, consequat a sapien. Maecenas et arcu vitae erat ultricies convallis a ut risus. Cras commodo ante est, egestas sollicitudin lacus pretium eget. Donec fringilla lectus vitae velit dictum pretium. Maecenas varius risus sit amet ornare scelerisque.</p>
</div>
<div class="article">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec aliquet placerat tortor, non posuere lectus viverra eget. Fusce dictum nulla eget vestibulum porttitor. Mauris mollis metus non lacinia rutrum. Ut venenatis interdum odio, sit amet efficitur ex tincidunt ac. Morbi dictum hendrerit metus sed auctor. Vivamus quam sem, convallis maximus interdum sed, mattis id leo. Morbi faucibus lorem et nisi sodales dictum. Sed elit diam, elementum eu ultrices eget, varius et quam. Vivamus malesuada dignissim nisi, ut fermentum ex gravida non. Maecenas auctor mi vitae dolor aliquam, non imperdiet eros porttitor. Etiam erat lacus, dignissim et nulla eu, mollis placerat ante. Quisque ac mattis diam, at convallis nibh. Fusce in neque accumsan arcu rutrum faucibus. Nam in ex porttitor, pretium massa at, varius ex.</p>
<div class="header">
Article - 2
<div class="header-sentinel header-sentinel-top"></div>
<div class="header-sentinel header-sentinel-bottom"></div>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec aliquet placerat tortor, non posuere lectus viverra eget. Fusce dictum nulla eget vestibulum porttitor. Mauris mollis metus non lacinia rutrum. Ut venenatis interdum odio, sit amet efficitur ex tincidunt ac. Morbi dictum hendrerit metus sed auctor. Vivamus quam sem, convallis maximus interdum sed, mattis id leo. Morbi faucibus lorem et nisi sodales dictum. Sed elit diam, elementum eu ultrices eget, varius et quam. Vivamus malesuada dignissim nisi, ut fermentum ex gravida non. Maecenas auctor mi vitae dolor aliquam, non imperdiet eros porttitor. Etiam erat lacus, dignissim et nulla eu, mollis placerat ante. Quisque ac mattis diam, at convallis nibh. Fusce in neque accumsan arcu rutrum faucibus. Nam in ex porttitor, pretium massa at, varius ex.</p>
<p>Vivamus lacinia fermentum gravida. Nulla facilisi. Nunc ultrices congue velit, non convallis diam mollis ac. Suspendisse ut tempus odio, sit amet tincidunt orci. Suspendisse aliquet ipsum quis ultrices blandit. Donec ut sagittis metus. Nullam ac nibh et enim porttitor aliquet id non dui.</p>
<p>Suspendisse vel purus auctor, tristique dui at, elementum felis. Donec metus mauris, ornare quis tempor id, pellentesque ac felis. Curabitur lacinia malesuada massa quis sagittis. Cras finibus elementum finibus. Ut in leo faucibus urna aliquam condimentum. Donec non hendrerit orci. Ut at aliquet dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam elementum lacus eu malesuada aliquam. Nulla dictum metus non ipsum dignissim, at rutrum diam rhoncus. Morbi tempor erat nec nisi ornare rutrum eu in orci. In dolor ante, pharetra sodales ornare sit amet, consequat a sapien. Maecenas et arcu vitae erat ultricies convallis a ut risus. Cras commodo ante est, egestas sollicitudin lacus pretium eget. Donec fringilla lectus vitae velit dictum pretium. Maecenas varius risus sit amet ornare scelerisque.</p>
</div>
<div class="article">
<div class="header">
Article - 3
<div class="header-sentinel header-sentinel-top"></div>
<div class="header-sentinel header-sentinel-bottom"></div>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec aliquet placerat tortor, non posuere lectus viverra eget. Fusce dictum nulla eget vestibulum porttitor. Mauris mollis metus non lacinia rutrum. Ut venenatis interdum odio, sit amet efficitur ex tincidunt ac. Morbi dictum hendrerit metus sed auctor. Vivamus quam sem, convallis maximus interdum sed, mattis id leo. Morbi faucibus lorem et nisi sodales dictum. Sed elit diam, elementum eu ultrices eget, varius et quam. Vivamus malesuada dignissim nisi, ut fermentum ex gravida non. Maecenas auctor mi vitae dolor aliquam, non imperdiet eros porttitor. Etiam erat lacus, dignissim et nulla eu, mollis placerat ante. Quisque ac mattis diam, at convallis nibh. Fusce in neque accumsan arcu rutrum faucibus. Nam in ex porttitor, pretium massa at, varius ex.</p>
<p>Vivamus lacinia fermentum gravida. Nulla facilisi. Nunc ultrices congue velit, non convallis diam mollis ac. Suspendisse ut tempus odio, sit amet tincidunt orci. Suspendisse aliquet ipsum quis ultrices blandit. Donec ut sagittis metus. Nullam ac nibh et enim porttitor aliquet id non dui.</p>
<p>Suspendisse vel purus auctor, tristique dui at, elementum felis. Donec metus mauris, ornare quis tempor id, pellentesque ac felis. Curabitur lacinia malesuada massa quis sagittis. Cras finibus elementum finibus. Ut in leo faucibus urna aliquam condimentum. Donec non hendrerit orci. Ut at aliquet dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam elementum lacus eu malesuada aliquam. Nulla dictum metus non ipsum dignissim, at rutrum diam rhoncus. Morbi tempor erat nec nisi ornare rutrum eu in orci. In dolor ante, pharetra sodales ornare sit amet, consequat a sapien. Maecenas et arcu vitae erat ultricies convallis a ut risus. Cras commodo ante est, egestas sollicitudin lacus pretium eget. Donec fringilla lectus vitae velit dictum pretium. Maecenas varius risus sit amet ornare scelerisque.</p>
</div>
<div class="article">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec aliquet placerat tortor, non posuere lectus viverra eget. Fusce dictum nulla eget vestibulum porttitor. Mauris mollis metus non lacinia rutrum. Ut venenatis interdum odio, sit amet efficitur ex tincidunt ac. Morbi dictum hendrerit metus sed auctor. Vivamus quam sem, convallis maximus interdum sed, mattis id leo. Morbi faucibus lorem et nisi sodales dictum. Sed elit diam, elementum eu ultrices eget, varius et quam. Vivamus malesuada dignissim nisi, ut fermentum ex gravida non. Maecenas auctor mi vitae dolor aliquam, non imperdiet eros porttitor. Etiam erat lacus, dignissim et nulla eu, mollis placerat ante. Quisque ac mattis diam, at convallis nibh. Fusce in neque accumsan arcu rutrum faucibus. Nam in ex porttitor, pretium massa at, varius ex.</p>
<p>Vivamus lacinia fermentum gravida. Nulla facilisi. Nunc ultrices congue velit, non convallis diam mollis ac. Suspendisse ut tempus odio, sit amet tincidunt orci. Suspendisse aliquet ipsum quis ultrices blandit. Donec ut sagittis metus. Nullam ac nibh et enim porttitor aliquet id non dui.</p>
<p>Suspendisse vel purus auctor, tristique dui at, elementum felis. Donec metus mauris, ornare quis tempor id, pellentesque ac felis. Curabitur lacinia malesuada massa quis sagittis. Cras finibus elementum finibus. Ut in leo faucibus urna aliquam condimentum. Donec non hendrerit orci. Ut at aliquet dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam elementum lacus eu malesuada aliquam. Nulla dictum metus non ipsum dignissim, at rutrum diam rhoncus. Morbi tempor erat nec nisi ornare rutrum eu in orci. In dolor ante, pharetra sodales ornare sit amet, consequat a sapien. Maecenas et arcu vitae erat ultricies convallis a ut risus. Cras commodo ante est, egestas sollicitudin lacus pretium eget. Donec fringilla lectus vitae velit dictum pretium. Maecenas varius risus sit amet ornare scelerisque.</p>
<div class="header">
Article - 4
<div class="header-sentinel header-sentinel-top"></div>
<div class="header-sentinel header-sentinel-bottom"></div>
</div>
</div>
</div>
<script>
(function() {
const container = document.querySelector('.container');
const observer = new IntersectionObserver(records => {
for (const record of records) {
// Saving links to useful elements.
const sentinel = record.target;
const header = sentinel.parentElement;
// Detecting stickied side and status.
const isTopSentinel =
sentinel.classList.contains('header-sentinel-top')
const isStuck =
record.isIntersecting &&
record.intersectionRatio < 0.5 &&
(isTopSentinel ?
record.intersectionRect.top === record.rootBounds.top :
record.intersectionRect.top === record.rootBounds.bottom);
// Do some position related work.
const stuckClassName =
isTopSentinel ? 'stuck-to-top' : 'stuck-to-bottom';
// Dispatch event.
if (isStuck !== header.classList.contains(stuckClassName)) {
header.dispatchEvent(new CustomEvent(
isTopSentinel ?
'stuck-to-top-change' :
'stuck-to-bottom-change',
{
bubbles: true,
detail: {header: header, isStuck: isStuck}
},
));
}
// Apply class.
header.classList.toggle(stuckClassName, isStuck);
}
}, {
root: container,
threshold: [0, 1],
});
[...document.querySelectorAll('.header-sentinel')].forEach(header => {
observer.observe(header);
});
})();
(function() {
const container = document.querySelector('.container');
const lastEvent = document.querySelector('.last-event');
container.addEventListener('stuck-to-top-change', (event) => {
lastEvent.textContent =
event.detail.header.textContent +
' TOP ' +
event.detail.isStuck;
});
container.addEventListener('stuck-to-bottom-change', (event) => {
lastEvent.textContent =
event.detail.header.textContent +
' BOTTOM ' +
event.detail.isStuck;
});
})();
</script>
</body>
</html>