I'm making my own single page application and I don't want the content to be static as I scroll down. I want it to ease in with a smooth animation. I couldn't find any guides on the subject. Here is a perfect example of what I'm talking about: qanplatform.com , as you scroll down the content has these nice transitions between components. Is it code-splitting?
so basically i have my:
<div className='App'>
<Navbar/>
<Hero/>
<Stats/>
<Business/>
<Team/>
<Footer/>
</div>
and I want every component to render with a simple animation only when I scroll down to it and not before. I don't need anyone to write code for me, all I need is a tip on how to proceed. I think qanplatform.com best represents what my idea is.
You can try this alternative one quite simple without an intersection observer, combining the CSS animation keyframes and JS to detect and reveal the content height
article: https://alvarotrigo.com/blog/css-animations-scroll/
function reveal() {
var reveals = document.querySelectorAll(".reveal");
for (var i = 0; i < reveals.length; i++) {
var windowHeight = window.innerHeight;
var elementTop = reveals[i].getBoundingClientRect().top;
var elementVisible = 150;
if (elementTop < windowHeight - elementVisible) {
reveals[i].classList.add("active");
} else {
reveals[i].classList.remove("active");
}
}
}
window.addEventListener("scroll", reveal);
#import url("https://fonts.googleapis.com/css2?family=Asap&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Asap", sans-serif;
}
body {
background: #42455a;
}
section {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
section:nth-child(1) {
color: #e0ffff;
}
section:nth-child(2) {
color: #42455a;
background: #e0ffff;
}
section:nth-child(3) {
color: #e0ffff;
}
section:nth-child(4) {
color: #42455a;
background: #e0ffff;
}
section .container {
margin: 100px;
}
section h1 {
font-size: 3rem;
margin: 20px;
}
section h2 {
font-size: 40px;
text-align: center;
text-transform: uppercase;
}
section .text-container {
display: flex;
}
section .text-container .text-box {
margin: 20px;
padding: 20px;
background: #00c2cb;
}
section .text-container .text-box h3 {
font-size: 30px;
text-align: center;
text-transform: uppercase;
margin-bottom: 10px;
}
#media (max-width: 900px) {
section h1 {
font-size: 2rem;
text-align: center;
}
section .text-container {
flex-direction: column;
}
}
.reveal {
position: relative;
opacity: 0;
}
.reveal.active {
opacity: 1;
}
.active.fade-bottom {
animation: fade-bottom 1s ease-in;
}
.active.fade-left {
animation: fade-left 1s ease-in;
}
.active.fade-right {
animation: fade-right 1s ease-in;
}
#keyframes fade-bottom {
0% {
transform: translateY(50px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
#keyframes fade-left {
0% {
transform: translateX(-100px);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
#keyframes fade-right {
0% {
transform: translateX(100px);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
<section>
<h1>Scroll Down to Reveal Elements ↓</h1>
</section>
<section>
<div class="container reveal fade-bottom">
<h2>Caption</h2>
<div class="text-container">
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
</div>
</div>
</section>
<section>
<div class="container reveal fade-left">
<h2>Caption</h2>
<div class="text-container">
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
</div>
</div>
</section>
<section>
<div class="container reveal fade-right">
<h2>Caption</h2>
<div class="text-container">
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
<div class="text-box">
<h3>Section Text</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore
eius molestiae perferendis eos provident vitae iste.
</p>
</div>
</div>
</div>
</section>
You can use IntersectionObserver for new elements entering into view. After that, applying styles has animation on newly entered elements. You can utilise the same technique in React with refs if you don't want to use class names or inline styles.
const intersectionCallback = (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
//add a new class
entry.target.classList.add('fade-in-up');
}
});
}
const options = {
rootMargin: '0px',
threshold: 0 //when it just appear in your viewport, you can modify it based on your needs
}
const observer = new IntersectionObserver(intersectionCallback, options);
//find all elements which have a class name `content` to observe, you can use React's refs as well
const contentElements = document.querySelectorAll('.content')
for (const contentElement of contentElements) {
observer.observe(contentElement)
}
#keyframes fadeInUp {
from {
transform: translate3d(0, 40px, 0);
}
to {
transform: translate3d(0, 0, 0);
opacity: 1;
}
}
/*Animation styles*/
.fade-in-up {
opacity: 0;
animation-duration: 2s;
animation-fill-mode: both;
animation-name: fadeInUp;
}
.content {
height: 100vh;
width: 100vw;
}
<div class="content">
<h1>
Scroll down to see the animation
</h1>
</div>
<div class="content">
<h1>
Scroll down to see the animation
</h1>
</div>
<div class="content">
<h1>
End
</h1>
</div>
You can use Animate On Scroll (AOS) or GSAP for this!
They're both pretty easy to use but for this example I'll use AOS since it's quite simpler:
// Initialize the lbrary after the page loads
AOS.init();
/* Basic styling (not needed) */
div {
margin-top: 50vh;
}
<!-- Add the required libraries for AOS -->
<link href="https://unpkg.com/aos#2.3.1/dist/aos.css" rel="stylesheet"/>
<script src="https://unpkg.com/aos#2.3.1/dist/aos.js"></script>
<body>
<div data-aos="fade-up">This element fades up on scroll</div>
<div data-aos="fade-up">This element fades up on scroll</div>
<div data-aos="fade-up">This element fades up on scroll</div>
<div data-aos="fade-right">This element fades right on scroll</div>
<div data-aos="fade-right">This element fades right on scroll</div>
<div data-aos="fade-right">This element fades right on scroll</div>
<div data-aos="fade-right">This element fades right on scroll</div>
<div data-aos="fade-right">This element fades right on scroll</div>
<div data-aos="fade-right">This element fades right on scroll</div>
More examples in the AOS homepage
</body>
To use this in react just import the libraries
Related
I suspect the issue is with the line const active = document.querySelector(".accordion.active"); in JS code below. It doesn't seem to be retrieving that element. Could you please help me debug it? Or should I use something else instead of querySelector? It is also found that this.classList.add("active"); is not adding the "active class" to the accordion element when it is clicked.
document.addEventListener("DOMContentLoaded", function(event) {
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
const active = document.querySelector(".accordion.active");
console.log(active);
if (active) {
active.classList.remove('active'); // remove active class from accordions
}
this.classList.add("active"); // add it to this one
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
});
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 1.5rem;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
background: red;
}
.active+.panel {
display: block;
}
<div class="row">
<button class="accordion"><div class="question"><?php echo $label; ?></div></button>
<div class="panel">
<p class="answer">
<?php echo $answer; ?>
</p>
</br>
</div>
</div>
<div class="row">
<button class="accordion"><div class="question"><?php echo $label; ?></div></button>
<div class="panel">
<p class="answer">
<?php echo $answer; ?>
</p>
</br>
</div>
</div>
You probably should re-think your approach since in your case, you will not even be in need of JavaScript - for the basics! If you need a custom accordion, then you can use JavaScript, and I try to explain to you how.
What you need is a clean HTML with <details> and <summary>. See this example:
<details class="accordion">
<summary>Question 1</summary>
<strong>Answer:</strong> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus molestias ex, rem ducimus quibusdam nihil aliquam corporis id sint aperiam dolores, accusantium culpa adipisci similique doloremque eius reiciendis. Veniam, perferendis.
</details>
<details class="accordion">
<summary>Question 2</summary>
<strong>Answer:</strong> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laborum doloribus tenetur tempore esse consectetur incidunt, distinctio eaque suscipit error fugit tempora, quas accusantium recusandae autem voluptatibus qui quasi molestiae odit.
</details>
With CSS you can style it the way you want it. If you want to remove the arrows, you can try it with details > summary { list-style: none; }. Also, you can use any other characters. In this example, we use the signs + (plus) and when the accordion is already opened, it should be - (minus.):
details > summary {
list-style-type: '+ ';
}
details[open] > summary {
list-style-type: "- ";
}
details > summary::-webkit-details-marker {
display: none;
}
summary {
background-color: #ccc;
}
<details class="accordion">
<summary>Question 1</summary>
<strong>Answer:</strong> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus molestias ex, rem ducimus quibusdam nihil aliquam corporis id sint aperiam dolores, accusantium culpa adipisci similique doloremque eius reiciendis. Veniam, perferendis.
</details>
<details class="accordion">
<summary>Question 2</summary>
<strong>Answer:</strong> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laborum doloribus tenetur tempore esse consectetur incidunt, distinctio eaque suscipit error fugit tempora, quas accusantium recusandae autem voluptatibus qui quasi molestiae odit.
</details>
As you can see, all open questions remain open. If you want only the active question to stay open, you may use JavaScript.
document.querySelectorAll('details').forEach((accordion) => {
accordion.addEventListener('click', (e) => {
document.querySelectorAll('details').forEach((event) => {
if (accordion !== event) {
event.removeAttribute('open');
}
});
});
});
details > summary {
list-style-type: '+ ';
}
details[open] > summary {
list-style-type: "- ";
}
details > summary::-webkit-details-marker {
display: none;
}
summary {
background-color: #ccc;
}
<details class="accordion">
<summary>Question 1</summary>
<strong>Answer:</strong> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus molestias ex, rem ducimus quibusdam nihil aliquam corporis id sint aperiam dolores, accusantium culpa adipisci similique doloremque eius reiciendis. Veniam, perferendis.
</details>
<details class="accordion">
<summary>Question 2</summary>
<strong>Answer:</strong> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laborum doloribus tenetur tempore esse consectetur incidunt, distinctio eaque suscipit error fugit tempora, quas accusantium recusandae autem voluptatibus qui quasi molestiae odit.
</details>
You don't need to manipulate the display of the active element, your CSS already does that. Also you should not both add and toggle the active class on this - that is equivalent to removing it.
I've also added an if statement to check if the clicked element is already active so that collapsing it again works.
document.addEventListener("DOMContentLoaded", function(event) {
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
const active = document.querySelector(".accordion.active");
console.log(active);
if (active) {
active.classList.remove('active'); // remove active class from accordions
}
if (active !== this) {
this.classList.toggle("active");
}
});
}
});
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 1.5rem;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
background: red;
}
.active+.panel {
display: block;
}
<div class="row">
<button class="accordion"><div class="question">Label1</div></button>
<div class="panel">
<p class="answer">
Answer goes here
</p>
</div>
</div>
<div class="row">
<button class="accordion"><div class="question">Label2</div></button>
<div class="panel">
<p class="answer">
Second answer
</p>
</div>
</div>
//
this.classList.add("active"); is not adding the "active class" to the accordion element when it is clicked.
//
It is adding. But immediately the class is toggled, so it is removed. That toogle class line is commented.
I have added the css for green color to active accordion, which you can see after moving the cursor off the accordion element.
document.addEventListener("DOMContentLoaded", function(event) {
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
const active = document.querySelector(".accordion.active");
console.log(active);
if (active) {
active.classList.remove('active'); // remove active class from accordions
// this is if other heading is clicked
}
// this.classList.toggle("active"); // not needed
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
this.classList.remove("active"); // remove it to this one
panel.style.display = "none";
} else {
this.classList.add("active"); // add it to this one
panel.style.display = "block";
}
});
}
});
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 1.5rem;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.accordion.active{
background:green;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
background: red;
}
.active+.panel {
display: block;
}
<div class="row">
<button class="accordion"><div class="question">Accordion Label 1</div></button>
<div class="panel">
<p class="answer">
Accordion Answer 1
</p>
</br>
</div>
</div>
<div class="row">
<button class="accordion"><div class="question">Accordion Label 2</div></button>
<div class="panel">
<p class="answer">
Accordion Answer 1
</p>
</br>
</div>
</div>
I always prefer delegation.
I am wrapping the accordion in a DIV and delegate the clicks from there
No need to show / hide the panes since the CSS .active+.panel { display: block; } does that for us
document.addEventListener("DOMContentLoaded", function(event) { // when page has loaded
const acc = document.getElementById("accodionContainer"); // the container
const buttons = acc.querySelectorAll(".accordion"); // the buttons in the container
acc.addEventListener("click", e => { // any click in the container
const currentButton = e.target.closest(".accordion"); // you have stuff inside the relevant element, make sure we use the .accordion element
if (!currentButton) return // something not a (in a ) button was clicked
// toggle clicked button, remove active from the rest
buttons.forEach(acc => acc.classList[acc === currentButton ? "toggle" : "remove"]("active"));
});
});
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 1.5rem;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
}
.active+.panel {
display: block;
}
.accordion.active span::after {
content: "➖";
}
.accordion span::after {
content: "➕";
}
<div id="accodionContainer">
<div class="row">
<button class="accordion"><span></span> Question 1</button>
<div class="panel">
<p class="answer">
Answer 1
</p>
</div>
</div>
<div class="row">
<button class="accordion"><span></span> Question 2</button>
<div class="panel">
<p class="answer">
Answer 2
</p>
</div>
</div>
</div>
The below answer is not related to the question, but it is good to have the html hierarchy.
const accordionToggles = document.querySelectorAll('.accordion-toggle');
const accordionItems = document.querySelectorAll('.accordion-item');
const flush = true; // set to true,if only one accordion bodyto be open. set false, to open multiple accordion-body
accordionToggles.forEach((toggleBtn) => {
toggleBtn.addEventListener('click', (event) => {
const accordionItem = event.target.closest(".accordion-item");
if (!flush) {
accordionItem.classList.toggle('active');
return;
}
if (accordionItem.classList.contains('active')) {
accordionItem.classList.toggle('active');
return;
}
accordionItems.forEach((item) => {
item.classList.remove('active');
})
accordionItem.classList.add('active');
})
});
.accordion {}
.accordion-item {
border: 1px solid gray;
}
.accordion-item+.accordion-item {
border-top: none;
}
.accordion-header {}
.accordion-toggle {
width: 100%;
border: none;
height: 30px;
border-bottom: 1px solid black;
text-align: left;
position: relative;
}
.accordion-toggle:after {
position: absolute;
top: 5px;
right: 5px;
font-size: 18px;
}
.accordion-body {
padding: 10px;
display: none;
}
.accordion-item.active .accordion-body {
display: block;
}
.accordion-item .accordion-toggle:after {
content: "+"
}
.accordion-item.active .accordion-toggle:after {
content: "-"
}
<div class="accordion">
<div class="accordion-item">
<div class="accordion-header">
<button class="accordion-toggle">Title 1</button>
</div>
<div class="accordion-body">
Accordion Content 1
</div>
</div>
<div class="accordion-item">
<div class="accordion-header">
<button class="accordion-toggle">Title 2</button>
</div>
<div class="accordion-body">
Accordion Content 2
</div>
</div>
</div>
So this div doesn't respond when I click on the h3 inside it or on the span
I used flex box in the "question-title" div, I guess that what causes the problem, is there a way I can make this div showing more/less when I click on it, not specifically outside h3 and the span, because it only works when I click in the space between h3 and the span.
let downBtn = document.querySelectorAll(".main-question .question-title");
downBtn.forEach(dbtn => {
dbtn.addEventListener("click", (e)=> {
let paragraphElement = e.target.parentNode.querySelector("p");
paragraphElement.classList.toggle("showHide");
let spanSign = dbtn.querySelector("span");
if (paragraphElement.classList.contains("showHide")) {
spanSign.innerHTML = "--";
} else {
spanSign.innerHTML = "+";
}
});
});
.question {
width: 60%;
margin: 0 auto;
}
.part-one h3 {
color: var(--main-color);
font-size: 30px;
margin: 0 0 20px;
}
.main-question {
margin: 20px auto;
padding: 20px;
text-align: center;
border: 1px solid rgb(207, 207, 207);
border-radius: 6px;
position: relative;
overflow: hidden;
}
.main-question h4 {
margin: 0;
color: #607d8b;
}
.main-question h4::selection {
background-color: transparent;
}
.main-question p {
margin: 34px 0 0;
text-align: justify;
color: var(--main-color2);
display: none;
}
.main-question p.showHide {
display: block;
}
.question-title {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
height: 20%;
width: 100%;
background-color: #EEE;
padding: 20px;
}
.question-title span {
font-size: 20px;
font-weight: bold;
color: #607d8b;
letter-spacing: -3px;
}
.question-title span::selection {
background-color: transparent;
}
<!-- Start questions -->
<div class="container">
<div class="question">
<div class="part-one">
<h3>Some Frequent Questions</h3>
<div class="main-question">
<div class="question-title">
<h4>Lorem ipsum dolor sit amet consectetur adipisicing elit</h4>
<span>+</span>
</div>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dolorum fugiat ullam molestias dignissimos deleniti inventore aspernatur nam excepturi vitae nihil, temporibus accusantium tempore deserunt error libero, itaque earum sapiente sequi.</p>
</div>
<div class="main-question">
<div class="question-title">
<h4>Lorem ipsum dolor sit amet consectetur adipisicing elit</h4>
<span>+</span>
</div>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dolorum fugiat ullam molestias dignissimos deleniti inventore aspernatur nam excepturi vitae nihil, temporibus accusantium tempore deserunt error libero, itaque earum sapiente sequi.</p>
</div>
<div class="main-question">
<div class="question-title">
<h4>Lorem ipsum dolor sit amet consectetur adipisicing elit</h4>
<span>+</span>
</div>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dolorum fugiat ullam molestias dignissimos deleniti inventore aspernatur nam excepturi vitae nihil, temporibus accusantium tempore deserunt error libero, itaque earum sapiente sequi.</p>
</div>
</div>
</div>
</div>
<!-- End questions -->
Your issue here is this line of code:
let paragraphElement = e.target.parentNode.querySelector("p");
Since you didn't set the indentations on your HTML properly, I didn't notice this issue in the first place.
You need to use this instead:
let paragraphElement = e.target.closest(".main-question").querySelector("p")
The answer of your question in the comment is NO, but when you click h4, you also click div because they are occupying the same area, unless you added stopPropagation to your function. But "e.target" is the item you clicked directly. If it's h4, its parentNode is "question-title" and it has no "p" child.
When you work with JS, always use console.log(). You can see the problem most of the time.
//This part is not necessary because the class "showHide" will be toggled below
document.querySelectorAll(".main-question").forEach(el ...
Also change your CSS for ".question-title" => "justify-content: space-around;" to show the icon
let downBtn = document.querySelectorAll(".main-question .question-title");
downBtn.forEach(dbtn => {
dbtn.addEventListener("click", (e) => {
let paragraphElement = e.target.parentNode.parentNode.querySelector("p");
paragraphElement.classList.toggle("showHide");
let spanSign = dbtn.querySelector("span");
if (paragraphElement.classList.contains("showHide")) {
spanSign.innerHTML = "--";
} else {
spanSign.innerHTML = "+";
}
});
});
I am trying to add an on-click-smooth-scroll effect like this one: https://michalsnik.github.io/aos/
I have read this: Smooth scroll to specific div on click and I am unable to adapt it. I don't understand what scrollTop: $("#page2").offset().top does.
My issue is that the scroll is "snapping". And that's probably because I have applied scroll-snap on the containers.
Also, when you're in-between the pages and click on the scroll down arrow it will either move up or down.
I would like to get the second page on full view whenever I press on that arrow. It should Scroll Down until #page2 has height: 100vh or it occupies the whole view port.
// eliminate scroll-bar
var child = document.getElementById('child-container');
child.style.right = child.clientWidth - child.offsetWidth + "px";
//scroll down effect on scroll-down-arrow
$(".scroll-down-arrow").click(function() {
$('html,body,#child-container').animate({scrollTop: $("#page2").offset().top}, 'slow', 'linear');
});
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* *** index.html - START *** */
body, html {
height: 100%;
width: 100%;
overflow: hidden;
}
#parent-container {
height: 100%;
width: 100%;
overflow: hidden;
position: relative;
}
#child-container {
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px; /* exact value is given through JavaScript */
overflow: auto;
scroll-snap-type: both proximity;
}
header {
height: 100%;
background-color: grey;
background-attachment: fixed;
background-position: bottom center;
background-repeat: no-repeat;
background-size: cover;
text-align: center;
scroll-snap-align: center;
}
header h1 {
font-size: 32px;
font-weight: bold;
position: sticky;
top: 5%;
margin-bottom:10px;
}
header p {
position: sticky;
width: 450px;
text-align: center;
margin: auto;
margin-top: 100px;
font-size: 1.5em;
}
header .scroll-down-arrow {
position: absolute;
left: 50%;
bottom: 20px;
display: block;
text-align: center;
font-size: 20px;
z-index: 100;
text-decoration: none;
text-shadow: 0;
width: 30px;
height: 30px;
border-bottom: 2px solid #fff;
border-right: 2px solid #fff;
left: 50%;
transform: translate(-50%, 0%) rotate(45deg);
animation: fade_move_down 3s ease-in-out infinite;
cursor: pointer;
}
/*animated scroll arrow animation*/
#keyframes fade_move_down {
0% { transform:translate(0,-15px) rotate(45deg); opacity: 0; }
25% {opacity: 1;}
/* 50% { opacity: 1; } */
100% { transform:translate(0,10px) rotate(45deg); opacity: 0; }
}
.container_page_2 {
width: 100%;
height: 100vh;
scroll-snap-align: center;
overflow: hidden;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div id="parent-container">
<div id="child-container">
<!-- #header -->
<header>
<div class="nav-container">
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<h1 id="sticky-title">Lorem ipsum</h1>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Modi debitis in libero tenetur suscipit iusto eum nulla dolorum aperiam adipisci unde veritatis vel iure, a nam, saepe exercitationem illum vitae.</p>
<div class="scroll-down-arrow"></div>
</header>
<!-- #page2 -->
<div id="page2" class="container_page_2">
<div class="column active">
<div class="content">
<h1>1</h1>
<div class="box">
<h2>background-attachment: fixed;</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Inventore necessitatibus possimus fuga voluptate incidunt enim eius sed, ad suscipit error quasi ex blanditiis ipsa, at vero officiis voluptatem a modi!
</p>
</div>
</div>
<div class="bg bg1"></div>
</div>
<div class="column">
<div class="content">
<h1>2</h1>
<div class="box">
<h2>background-attachment: scroll;</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Inventore necessitatibus possimus fuga voluptate incidunt enim eius sed, ad suscipit error quasi ex blanditiis ipsa, at vero officiis voluptatem a modi!
</p>
</div>
</div>
<div class="bg bg2"></div>
</div>
<div class="column">
<div class="content">
<h1>3</h1>
<div class="box">
<h2>background-attachment: scroll;</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Inventore necessitatibus possimus fuga voluptate incidunt enim eius sed, ad suscipit error quasi ex blanditiis ipsa, at vero officiis voluptatem a modi!
</p>
</div>
</div>
<div class="bg bg3"></div>
</div>
<div class="column">
<div class="content">
<h1>4</h1>
<div class="box">
<h2>background-attachment: fixed;</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Inventore necessitatibus possimus fuga voluptate incidunt enim eius sed, ad suscipit error quasi ex blanditiis ipsa, at vero officiis voluptatem a modi!
</p>
</div>
</div>
<div class="bg bg4"></div>
</div>
</div>
https://codepen.io/bleah1/pen/gjYBgQ
I haven't added all the elements from the second page, but it doesn't matter, because the scrolling isn't affected. As you can see it's not smooth at all, it's actually pretty snappy.
What do you think ? I would like to keep the scroll-snap, because I like that idea.
Hi can you try this solution.
Basically I removed the css when click event starts then added it when the scrollTop event ends.
Remember to remove it from your css #child-container
$(".scroll-down-arrow").click(function() {
$('#child-container').css('scroll-snap-type','')
$('html,body,#child-container').animate({
scrollTop: $("#page2").offset().top}, 'slow', 'linear')
.promise()
.done(() => {$('#child-container')
.css('scroll-snap-type','both proximity')
});
});
Based on #Ekin Alcar answer I was able to fix my issue. I followed his idea of removing the scroll-snap-type css attribute from #child-container by using $('#child-container').css('scroll-snap-type',''); inside of the original script, like this:
$(".scroll-down-arrow-container").click(function() {
$('#child-container').css('scroll-snap-type','');
$('html, body, #child-container').animate({
scrollTop: $(window).height()
}, 1000)
.promise()
.done(() => {$('#child-container')
.css('scroll-snap-type','both proximity')
});
});
The trick with .css is that it can only remove attributes that are used in the style tag inside a .html file. It won't work with a .css stylesheet.
From the API's documentation:
It does not, however, remove a style that has been applied with a CSS rule in a stylesheet or < style > element.
As such scroll-snap-type: both proximity; was removed from the .css file and added in the .html file:
<div id="child-container" style="scroll-snap-type: both proximity;">
Also, to fix the effect of scrolling up or down whenever you're in between pages I've replaced scrollTop: $("#page2").offset().top with scrollTop: $(window).height(). Don't ask me why it works, but it does.
I'm trying to make some animations for my application but I can't figure it out. I want the text and description to move depending on how much of the page scrolls. For the first div I managed to do it, but for the others, nothing happens. How could I do that when I scroll more than 40% to move the div according to the scroll?
Here is my code
$(window).on('scroll', function () {
let height = $('body').height();
let scroll = $(document).scrollTop();
if (scroll > height * 0.01) {
$('.div1 .title').css({
left: -350 + Math.min(350, scroll)
});
$('.div1 .description').css({
left: -350 + Math.min(350, scroll)
});
}
if (scroll > height * 0.4) {
$('.div2 .title').css({
right: -350 + Math.min(350, scroll)
});
$('.div2 .description').css({
right: -350 + Math.min(350, scroll)
});
}
});
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.div1 {
}
.div1, .div2, .div3 {
display: flex;
justify-content: center;
margin-top: 500px;
}
.left {
width: 500px;
}
.right {
width: 500px;
margin-left: 50px;
}
.right img, .left img {
width: 100%;
}
.div1 .title {
position: relative;
left: -350px;
}
.div1 .description {
position: relative;
left: -350px;
}
.div2 .title {
position: relative;
right: -350px;
}
.div2 .description {
position: relative;
right: -350px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div class="div1">
<div class="left">
<div class="title">
<h1>Some title</h1>
</div>
<div class="description">
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ipsam iste aliquid nihil
mollitia, cum recusandae molestias quod veritatis amet odit officiis quo assumenda ullam fugiat est
dolorum
ea pariatur doloribus.
</p>
</div>
</div>
<div class="right">
<img src="https://images.pexels.com/photos/207962/pexels-photo-207962.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260">
</div>
</div>
<div class="div2">
<div class="left">
<img src="https://images.pexels.com/photos/207962/pexels-photo-207962.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260">
</div>
<div class="right">
<div class="title">
<h1>Some title</h1>
</div>
<div class="description">
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ipsam iste aliquid nihil
mollitia, cum recusandae molestias quod veritatis amet odit officiis quo assumenda ullam fugiat est
dolorum
ea pariatur doloribus.
</p>
</div>
</div>
</div>
<div class="div3">
<div class="left">
<div class="title">
<h1>Some title</h1>
</div>
<div class="description">
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ipsam iste aliquid nihil
mollitia, cum recusandae molestias quod veritatis amet odit officiis quo assumenda ullam fugiat est
dolorum
ea pariatur doloribus.
</p>
</div>
</div>
<div class="right">
<img src="https://images.pexels.com/photos/207962/pexels-photo-207962.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260">
</div>
</div>
Try the following function to move the title and desription in each divs depending on the scroll position:
function moveOnViewPort(el, mult) {
let scrollPos = $(document).scrollTop();
let viewPortHeight = $(window).height();
let elementScrollPos = $(el).offset().top;
if((scrollPos + viewPortHeight) > elementScrollPos) {
let moveVal = (scrollPos + viewPortHeight - elementScrollPos) * mult;
if($(el).hasClass('move-left')) {
$(el).find('.move').css({
left: -350 + Math.min(350, moveVal)
});
}
else if($(el).hasClass('move-right')) {
$(el).find('.move').css({
right: -350 + Math.min(350, moveVal)
});
}
}
}
Working demo and implementation details can you find here: https://jsfiddle.net/dat57qse/
I have some content in my post. But I want to hide it until I click to a link in this post. I have yet to build this site, but I will say my idea.
The first Heading
The second Heading
The third Heading
The fourth Heading
/* The content following are hidden Until I clicked to a link above. /
/ Content is available wrapped in a div tag, do not loaded from another site. */
Content 1 will be show only click to "1. The first Heading"
Content 2 will be show only click to "2. The second Heading"
Content 3 will be show only click to "3. The third Heading"
Content 4 will be show only click to "4. The fourth Heading"
Can use CSS or Ajax / jQuery to create the effect?
You could do it using the following jquery code:
$(document).ready(function(){
$("#hide").click(function(){
$("p").hide();
});
$("#show").click(function(){
$("p").show();
});
});
Here is the complete demo how you can hide and show the element by click event.
I have made a pure css accordion that achieves the same functionality.Checkout the following link at codepen
HTML:
<div class="container">
<ul>
<li>What is java Programming Language?
<div class="acc-content" id="first">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo harum vel aliquid. Quaerat soluta sed aperiam temporibus ipsum obcaecati porro commodi error unde reprehenderit ipsa, dolore id, totam dolores, quae.
</p>
</div></li>
<li>How is javascript different from java?
<div class="acc-content" id="second">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo harum vel aliquid. Quaerat soluta sed aperiam temporibus ipsum obcaecati porro commodi error unde reprehenderit ipsa, dolore id, totam dolores, quae
</p>
</div></li>
<li>Other front end technologies
<div class="acc-content" id="third">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo harum vel aliquid. Quaerat soluta sed aperiam temporibus ipsum obcaecati porro commodi error unde reprehenderit ipsa, dolore id, totam dolores, quae
</p>
</div></li>
</ul>
</div>
CSS:
*{
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body{
padding-top: 50px;
font : 1em cursive;
background-image: url(http://www.mrwallpaper.com/wallpapers/fantasy-winter-scenery-1920x1200.jpg);
background-size: cover;
color: #fff;
overflow-x: hidden;
}
.container{
position: relative;
width: 100%;
max-width: 500px;
margin: auto;
padding: 5px;
}
ul{
margin: 0;
padding: 0;
list-style: none;
}
.acc-header{
display: block;
cursor: pointer;
padding: 10px 20px;
background-color: #000;
opacity: 0.7;
text-transform: uppercase;
text-decoration: none;
text-align: center;
color: #fff;
border-radius: 2px;
margin-bottom: 10px 0 0 10px;
}
.acc-content p{
margin: 10px;
}
.acc-content{
background-color: #222;
opacity: 0.7;
height: 0px;
overflow: hidden;
-webkit-transition: height 0.4s ease;
-moz-transition: height 0.4s ease;
-ms-transition: height 0.4s ease;
-o-transition: height 0.4s ease;
transition: height 0.4s ease;
}
.acc-content:target{
height: 170px;
}
With jQuery it can be pretty easy. By default you hide .content divs with CSS and display the corresponding one on heading click. Consider bellow example.
var $content = $('.content');
$('h2').click(function() {
$content.removeClass('show')
.filter('.content-' + $(this).data('content'))
.addClass('show');
});
.content {
display: none;
padding: 5px;
background: #EEE;
}
.content.show {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2 data-content="1">Heading #1</h2>
<h2 data-content="2">Heading #2</h2>
<h2 data-content="3">Heading #3</h2>
<div class="content content-1">Content #1</div>
<div class="content content-2">Content #2</div>
<div class="content content-3">Content #3</div>
If I understand well, I would recommend to load from ajax the content on first click and then hide it instead of deleting the toggled panel and retrieve it again from AJAX each time (so that there is no wait on each click and less requests).
So here's a way of doing it:
$('.header').click(function()
{
var clickedHeader= $(this);
if (clickedHeader.next().is('.toggle:visible'))
{
clickedHeader.next().slideDown(800);
}
else if (clickedHeader.next().is('.toggle:hidden'))
{
clickedHeader.next().slideUp(800);
}
else
{
$.get(url, data, function(data)
{
// First do some treatment if needed...
clickedHeader.after('<div class="toggle" style="display:none;">'+data+'</div>');
clickedHeader.next().slideDown(800);
});
}
});
This will work if you have HTML like this for ex.
<div class="header">First header</div>
<div class="header">Second header</div>
<div class="header">Third header</div>
<div class="header">Fourth header</div>
and after each header you would toggle a div that has class '.toggle'.
Hope it helps.