Refactoring parallax background

This commit is contained in:
jme9
2024-12-10 17:17:32 -08:00
parent 2cec6d3c1b
commit 4ce963d21e
4 changed files with 104 additions and 73 deletions
+4
View File
@@ -710,3 +710,7 @@ We have already done some of the work for this with our dynamic scrolling.
**The plan** **The plan**
We are going to create additional _background_ layers that will be layered on top of the actual background. We will update our JavaScript scroll event listener to control the scroll speed of each of these layers. Finally we will use CSS to ensure the layers are styled correctly to get our parallax effect. We are going to create additional _background_ layers that will be layered on top of the actual background. We will update our JavaScript scroll event listener to control the scroll speed of each of these layers. Finally we will use CSS to ensure the layers are styled correctly to get our parallax effect.
First I tried adding additional layers to the body however this proved difficult to control the position on various screen sizes.
+10 -9
View File
@@ -233,15 +233,16 @@
</form> </form>
</div> </div>
</section> </section>
<section class="page-bottom-section"></section>
<section id="credits" class="credits-section">
<div class="credits-box">
<div class="title-text">
<p>I made this website! Copyright Jesse M. Ellis 2024 &#128522</p>
</div>
</div>
</section>
</div> </div>
<section id="credits" class="credits-section">
<div class="parallax-layer layer-1"></div>
<div class="parallax-layer layer-2"></div>
<div class="parallax-layer layer-3"></div>
<div class="credits-box">
<div class="title-text">
<p>I made this website! Copyright Jesse M. Ellis 2024 &#128522</p>
</div>
</div>
</section>
</body> </body>
</html> </html>
+14 -32
View File
@@ -15,15 +15,17 @@ document.addEventListener("DOMContentLoaded", () => {
const titleBox = document.querySelector(".title-box"); const titleBox = document.querySelector(".title-box");
const aboutSection = document.querySelector("#about"); const aboutSection = document.querySelector("#about");
const contactSection = document.querySelector("#contact"); const contactSection = document.querySelector("#contact");
const creditsSection = document.querySelector("#credits");
const parallaxlayer1 = document.querySelector(".layer-1");
const parallaxlayer2 = document.querySelector(".layer-2");
const parallaxlayer3 = document.querySelector(".layer-3");
const scrollY = window.scrollY; const scrollY = window.scrollY;
const aboutTop = aboutSection.getBoundingClientRect().top + scrollY; const aboutTop = aboutSection.getBoundingClientRect().top + scrollY;
const contactTop = contactSection.getBoundingClientRect().top + scrollY; const contactTop = contactSection.getBoundingClientRect().top + scrollY;
const sectionTop = creditsSection.offsetTop;
const slowScrollRate = 0.5; const slowScrollRate = 0.5;
// Get viewport height for parallax background offsets
const viewportHeight = window.innerHeight;
// Move title-box if it's above the viewport and not yet touching about-section
if (scrollY < aboutTop) { if (scrollY < aboutTop) {
const opacity1 = scrollY / aboutTop; const opacity1 = scrollY / aboutTop;
titleBox.style.transform = `translateY(${scrollY * slowScrollRate}px)`; titleBox.style.transform = `translateY(${scrollY * slowScrollRate}px)`;
@@ -33,32 +35,17 @@ document.addEventListener("DOMContentLoaded", () => {
titleBox.style.opacity = 0; titleBox.style.opacity = 0;
} }
// Adjust navbar opacity when below the contact section if (scrollY > contactTop) {
const contactBottom = contactTop + contactSection.offsetHeight; const opacity2 = (scrollY - contactTop) / (document.body.scrollHeight - contactTop);
if (scrollY > contactBottom) { navBar.style.opacity = Math.max(1 - opacity2, 0.5);
// Calculate opacity based on how far below the contact section we are
const fadeDistance = 100;
const distanceBelow = scrollY - contactBottom;
const opacity2 = Math.max(1 - distanceBelow / fadeDistance, 0);
navBar.style.opacity = opacity2;
} else { } else {
navBar.style.opacity = 1; navBar.style.opacity = 1;
} }
// Parallax background scroll rates const relativeScrollY = sectionTop - scrollY;
const body = document.body; parallaxlayer1.style.transform = `translateY(${relativeScrollY * 0.2}px)`;
const bridgeScrollRate = 0.4; parallaxlayer2.style.transform = `translateY(${relativeScrollY * 0.4}px)`;
const treesScrollRate = 0.5; parallaxlayer3.style.transform = `translateY(${relativeScrollY * 0.6}px)`;
const castleScrollRate = 0.7;
const cloudsScrollRate = 0.9;
body.style.backgroundPosition = `
left ${scrollY * bridgeScrollRate + viewportHeight * 3.05}px,
left ${scrollY * treesScrollRate + viewportHeight * 2.55}px,
left ${scrollY * castleScrollRate + viewportHeight * 1.5}px,
left ${scrollY * cloudsScrollRate + viewportHeight * 0.4}px,
left 0px
`;
}); });
// Function to load text from a file into an html component // Function to load text from a file into an html component
@@ -120,12 +107,10 @@ document.addEventListener("DOMContentLoaded", () => {
document document
.getElementById("contact-form") .getElementById("contact-form")
.addEventListener("submit", async function (event) { .addEventListener("submit", async function (event) {
// Take control of form submission
event.preventDefault(); event.preventDefault();
const form = event.target; const form = event.target;
const formData = new FormData(form); const formData = new FormData(form);
try { try {
// Submit the form data using the Fetch API and catch response
const response = await fetch(form.action, { const response = await fetch(form.action, {
method: form.method, method: form.method,
body: formData, body: formData,
@@ -134,15 +119,12 @@ document.addEventListener("DOMContentLoaded", () => {
}, },
}); });
if (response.ok) { if (response.ok) {
// Success! give user a message
alert("Thank you! Your message has been sent."); alert("Thank you! Your message has been sent.");
form.reset(); // Clear the form form.reset();
} else { } else {
// Fail :( give user a message
alert("Oops! There was a problem submitting your form."); alert("Oops! There was a problem submitting your form.");
} }
} catch (error) { } catch (error) {
// Log any errors
console.error("Error:", error); console.error("Error:", error);
alert( alert(
"There was a problem submitting your form. Please try again later." "There was a problem submitting your form. Please try again later."
+70 -26
View File
@@ -1,20 +1,17 @@
body { body {
margin: 0; margin: 0;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
background-image: url("../images/Bridge.png"), url("../images/Trees.png"), background-image: url("../images/Moon.png");
url("../images/Castle.png"), url("../images/Clouds.png"), background-size: cover;
url("../images/Moon.png"); background-position: left;
background-size: auto, auto, auto, auto, cover; background-repeat: no-repeat;
background-repeat: no-repeat, no-repeat, no-repeat, no-repeat, no-repeat; background-attachment: fixed;
background-attachment: scroll, scroll, scroll, scroll, fixed;
background-position: left 300vh, left 300vh, left 300vh, left 350vh, left top;
min-width: 768px; min-width: 768px;
} }
.page-container { .page-container {
max-width: 1440px; max-width: 1440px;
margin: 0 auto; margin: 0 auto;
padding: 0 1rem;
} }
.navbar { .navbar {
@@ -79,25 +76,7 @@ body {
align-items: center; align-items: center;
} }
.page-bottom-section {
height: 90vh;
margin-top: 3rem;
}
.credits-section {
display: flex;
justify-content: center;
align-items: center;
}
.credits-box {
display: flex;
background: rgba(0, 0, 0, 1);
border-radius: 100px;
width: 400px;
padding: 10px;
margin-bottom: 2rem;
}
.title-box { .title-box {
display: flex; display: flex;
@@ -410,6 +389,10 @@ button:hover {
/* Contact Form */ /* Contact Form */
.contact-section {
overflow: visible;
}
.contact-box { .contact-box {
margin-top: 10rem; margin-top: 10rem;
background: rgba(0, 0, 0, 0.8); background: rgba(0, 0, 0, 0.8);
@@ -472,6 +455,60 @@ button[type="reset"] {
color: white; color: white;
} }
/* Credits Section - parallax background */
.credits-section {
position: relative;
display: flex;
height: 100vh;
min-width: 768px;
justify-content: center;
align-items: center;
overflow: visible;
}
.credits-section .parallax-layer {
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.credits-box {
display: flex;
background: rgba(0, 0, 0, 1);
border-radius: 100px;
width: 400px;
padding: 10px;
margin-bottom: 5rem;
}
.parallax-layer {
position: absolute;
width: 100%;
height: 100%;
background-size: cover;
background-position: left;
background-repeat: no-repeat;
min-width: 768px;
z-index: -1;
}
.layer-1 {
background-image: url('images/Clouds.png');
top: 0;
}
.layer-2 {
background-image: url('images/Trees.png');
top: 0;
}
.layer-3 {
background-image: url('images/Bridge.png');
top: 0;
}
/* Media Queries */ /* Media Queries */
@media (min-width: 1440px) { @media (min-width: 1440px) {
@@ -525,3 +562,10 @@ button[type="reset"] {
padding-right: 5rem; padding-right: 5rem;
} }
} }
@media (max-width: 768px) {
.parallax-layer {
height: 120%;
}
}