1
Fork 0

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:
Jake Howard 2024-06-21 17:35:02 +01:00
parent 4d91da4231
commit fe7347f647
Signed by: jake
GPG key ID: 57AFB45680EDD477
5 changed files with 52 additions and 2 deletions

7
package-lock.json generated
View file

@ -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",

View file

@ -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": {

View file

@ -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
View 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);
});

View file

@ -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;