Add a simple sticky hero using JS
It's only a small amount of JS, so it doesn't make me cry too much
This commit is contained in:
parent
4d91da4231
commit
fe7347f647
5 changed files with 52 additions and 2 deletions
7
package-lock.json
generated
7
package-lock.json
generated
|
@ -11,6 +11,7 @@
|
|||
"glob": "^10.4.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
"sass": "^1.77.2",
|
||||
"underscore": "^1.13.6",
|
||||
"vite": "^5.2.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1332,6 +1333,12 @@
|
|||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/underscore": {
|
||||
"version": "1.13.6",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
|
||||
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.2.11",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"glob": "^10.4.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
"sass": "^1.77.2",
|
||||
"underscore": "^1.13.6",
|
||||
"vite": "^5.2.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -35,5 +35,6 @@
|
|||
<p>Content</p>
|
||||
<p>Content</p>
|
||||
</div>
|
||||
<script async src="./index.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
29
src/hero/index.js
Normal file
29
src/hero/index.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import _ from "underscore";
|
||||
|
||||
function handleDetailsStick(hero) {
|
||||
const details = hero.querySelector("#details");
|
||||
const heroIsVisible =
|
||||
hero.getBoundingClientRect().bottom >=
|
||||
details.getBoundingClientRect().height;
|
||||
if (heroIsVisible) {
|
||||
details.classList.remove("stuck");
|
||||
} else {
|
||||
details.classList.add("stuck");
|
||||
}
|
||||
}
|
||||
|
||||
function handleIntersection(entries) {
|
||||
handleDetailsStick(entries[0].target);
|
||||
}
|
||||
|
||||
window.addEventListener("load", function () {
|
||||
const hero = document.getElementById("hero");
|
||||
|
||||
let observer = new IntersectionObserver(handleIntersection, {
|
||||
root: null,
|
||||
threshold: _.range(0, 1, 0.01), // 1%
|
||||
});
|
||||
observer.observe(hero);
|
||||
|
||||
handleDetailsStick(hero);
|
||||
});
|
|
@ -9,6 +9,7 @@ html {
|
|||
$content-width: 85ch;
|
||||
$content-padding: 16px;
|
||||
$bleed-ratio: 0.2;
|
||||
$details-bg: black;
|
||||
|
||||
.hero {
|
||||
height: 50vh;
|
||||
|
@ -17,11 +18,19 @@ $bleed-ratio: 0.2;
|
|||
align-items: flex-end;
|
||||
|
||||
.details-wrapper {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
background-color: transparentize($details-bg, 0.6);
|
||||
color: white;
|
||||
line-height: 1;
|
||||
width: calc(100% - 2rem);
|
||||
padding: 0 1rem;
|
||||
transition-duration: 0.15s;
|
||||
transition-property: background-color;
|
||||
|
||||
&.stuck {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
background-color: transparentize($details-bg, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
|
@ -46,7 +55,10 @@ $bleed-ratio: 0.2;
|
|||
display: grid;
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
grid-template-columns: 1fr min($content-width, calc(100% - #{$content-padding} * 2)) 1fr;
|
||||
grid-template-columns: 1fr min(
|
||||
$content-width,
|
||||
calc(100% - #{$content-padding} * 2)
|
||||
) 1fr;
|
||||
|
||||
& > * {
|
||||
grid-column: 2;
|
||||
|
|
Loading…
Reference in a new issue