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",
|
"glob": "^10.4.1",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"sass": "^1.77.2",
|
"sass": "^1.77.2",
|
||||||
|
"underscore": "^1.13.6",
|
||||||
"vite": "^5.2.11"
|
"vite": "^5.2.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1332,6 +1333,12 @@
|
||||||
"node": ">=8.0"
|
"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": {
|
"node_modules/vite": {
|
||||||
"version": "5.2.11",
|
"version": "5.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"glob": "^10.4.1",
|
"glob": "^10.4.1",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"sass": "^1.77.2",
|
"sass": "^1.77.2",
|
||||||
|
"underscore": "^1.13.6",
|
||||||
"vite": "^5.2.11"
|
"vite": "^5.2.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -35,5 +35,6 @@
|
||||||
<p>Content</p>
|
<p>Content</p>
|
||||||
<p>Content</p>
|
<p>Content</p>
|
||||||
</div>
|
</div>
|
||||||
|
<script async src="./index.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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-width: 85ch;
|
||||||
$content-padding: 16px;
|
$content-padding: 16px;
|
||||||
$bleed-ratio: 0.2;
|
$bleed-ratio: 0.2;
|
||||||
|
$details-bg: black;
|
||||||
|
|
||||||
.hero {
|
.hero {
|
||||||
height: 50vh;
|
height: 50vh;
|
||||||
|
@ -17,11 +18,19 @@ $bleed-ratio: 0.2;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
|
||||||
.details-wrapper {
|
.details-wrapper {
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
background-color: transparentize($details-bg, 0.6);
|
||||||
color: white;
|
color: white;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
width: calc(100% - 2rem);
|
width: calc(100% - 2rem);
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
transition-property: background-color;
|
||||||
|
|
||||||
|
&.stuck {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
background-color: transparentize($details-bg, 0.1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.details {
|
.details {
|
||||||
|
@ -46,7 +55,10 @@ $bleed-ratio: 0.2;
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100vw;
|
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;
|
grid-column: 2;
|
||||||
|
|
Loading…
Reference in a new issue