Trigger a CSS Animation when the user scrolls to page section - html

I have a simple CSS animation on my site, where I want to show 5 divs showing one at a time in a row.
Everything works fine, but I want to make a trigger to that animation, when the user scrolls to that particular section on my site(now the animation starts when the page loads).
Here is my code:
<div id="space"></div>
<div id="container">
<img src="https://cdn1.iconfinder.com/data/icons/user-pictures/100/male3-64.png" />
<img src="https://cdn1.iconfinder.com/data/icons/user-pictures/100/male3-64.png" />
<img src="https://cdn1.iconfinder.com/data/icons/user-pictures/100/male3-64.png" />
<img src="https://cdn1.iconfinder.com/data/icons/user-pictures/100/male3-64.png" />
<img src="https://cdn1.iconfinder.com/data/icons/user-pictures/100/male3-64.png" />
</div>
CSS:
#space {
height: 700px;
background-color: blue;
}
#container img {
opacity: 0;
}
#keyframes fdsseq {
100% { opacity: 1; }
}
#container img {
animation: fdsseq .5s forwards;
}
#container img:nth-child(1) {
animation-delay: .5s;
}
#container img:nth-child(2) {
animation-delay: 1s;
}
#container img:nth-child(3) {
animation-delay: 1.5s;
}
#container img:nth-child(4) {
animation-delay: 2s;
}
#container img:nth-child(5) {
animation-delay: 2.5s;
}
https://jsfiddle.net/Lwb088x5/

You need JavaScript to do this.
In the example(s) below, a scroll event listener to attached, and the animate class is added to the #container element if the img elements are visible:
Updated Example
#container.animate img {
animation: animation .5s forwards;
}
document.addEventListener('scroll', function (e) {
var top = window.pageYOffset + window.innerHeight,
isVisible = top > document.querySelector('#container > img').offsetTop;
if (isVisible) {
document.getElementById('container').classList.add('animate');
}
});
Alternatively, you could also use jQuery as well:
Updated Example
$(window).on('scroll', function (e) {
var top = $(window).scrollTop() + $(window).height(),
isVisible = top > $('#container img').offset().top;
$('#container').toggleClass('animate', isVisible);
});

Related

Hide & show 3 images on a loop using CSS

Trying to loop through 3 images with only showing one at time for 7 seconds, which then disappears and then show the next one in the sequence, then the next image. The loop needs to be infinite without a "transition / fade" delay.
The images are animating GIFs, so trying to line up the timing with the transitions is so far failing to work.
Currently using this:
.images {
margin: auto;
}
.images img {
position: absolute;
-webkit-animation: fade 21s infinite;
animation: fade 21s infinite;
}
#keyframes fade {
0% {
opacity: 1;
}
15% {
opacity: 1;
}
25% {
opacity: 0;
}
90% {
opacity: 0;
}
100% {
opacity: 1;
}
}
-webkit-#keyframes fade {
0% {
opacity: 1;
}
15% {
opacity: 1;
}
25% {
opacity: 0;
}
90% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#img1 {
-webkit-animation-delay: 0s;
animation-delay: 0s;
}
#img2 {
-webkit-animation-delay: -7s;
animation-delay: -7s;
}
#img3 {
-webkit-animation-delay: -14s;
animation-delay: -14s;
}
<div class="images">
<img id="img1" src="https://example.com/gif-1.gif">
<img id="img2" src="https://example.com/gif-2.gif">
<img id="img3" src="https://example.com/gif-3.gif">
</div>
Any help would be greatly appriciated
Here you can define the duration in a variable to control the appearance time of a single image.
I'm using a single set of keyframes, changing the opacity of every image to 1 for ⅓ of the animation-duration (and to 0 for the remaining time).
Unfortunately calc can't be used to define percentages into keyframes, so if you change the number of images you also need to manually change those percentages, as described in the comments inside the code.
Grid display is used as an alternative of position: relative and position: absolute. fetchpriority was used for the first image to increase its priority (since it's the first image of the animation and it has to be loaded soon).
.loop {
--time: 7s;
display: grid;
}
/* show animation only if user hasn't set a preference,
otherwise just show stacked images */
#media (prefers-reduced-motion: no-preference) {
.loop img {
grid-area: 1/1;
animation: rotate calc(var(--time) * 3) linear 0s infinite;
}
.loop img:nth-child(2) { animation-delay: calc(var(--time) * -2); }
.loop img:nth-child(3) { animation-delay: calc(var(--time) * -1); }
}
#keyframes rotate {
/* 33.33% is (100% / number of images) */
0%, 33.33% { opacity: 1; }
/* 33.34% is (100% / number of images) + 0.01 */
33.34%, 100% { opacity: 0; }
}
<div class="loop">
<img src="https://picsum.photos/id/237/300/200/" fetchpriority="high" />
<img src="https://picsum.photos/id/238/300/200/" />
<img src="https://picsum.photos/id/239/300/200/" />
</div>
As a side note, for a matter of accessibility, you should give the user the capability to stop every animation longer than 5 seconds since it can potentially provoke seizures. In any case don't rotate images faster than 3 per second.

How to reset the opacity of an image after pressing?

I have an image on my page representing an up arrow and, which is used to jump to the top of the page thanks to a link). This image has an opacity of "0.2", and "1" when hovering over it with the mouse.
From a smartphone or tablet, when you press on this image, the opacity remains at "1".
I would like this opacity to return to "0.2" after pressing this one.
How to do please?
My HTML code :
<img src="./img/up.png" alt="up" title="up">
My CSS code :
a > img {
width: 60%;
height: 60%;
opacity: 0.2;
}
a > img:hover {
opacity: 1;
}
Thanks
A solution with Javascript/Jquery
I modified an answer of mine of few days ago
$('#clickMe').click(function () {
$(this).addClass('tothetop');
$(this).on("animationend", function(event) {
$(this).removeClass('tothetop')
});
});
img {
opacity:0.2;
}
.tothetop {
animation-fill-mode: forwards;
animation-name: test;
animation-duration: 2s;
}
#keyframes test {
50% {opacity:1;}
100% {opacity:0.2;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img id="clickMe" src="https://picsum.photos/200">
A solution using only CSS
#keyframes move {
50% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}
img {
animation-fill-mode: forwards;
opacity:0.2;
}
img:hover {
animation: move 2s;
}
<img src="https://picsum.photos/200">
A Pure CSS Solution without JavaScript
The problem lies with how best to implement :hover on interfaces where the user is not using a cursor controlled by a mouse or trackpad or a keyboard.
There isn't (yet) a perfect way to do this.
It doesn't exist, but we could imagine that the touchscreen counterpart to:
my-div:hover
might be:
my-div:touch
where the :hover behaviour is displayed for a second or two and then no longer displayed.
In the absence of a hypothetical :touch pseudo-class however, we can nevertheless implement one - and in CSS alone, without using JavaScript.
We can do this by introducing an animation for touchscreens - something like this:
#keyframes hoverForTouchScreens {
0%, 50% {
opacity: 1;
}
}
We can also ensure that this animation only fires on touchscreens with a #media query:
#media screen and (hover: none) and (pointer: coarse) {
a > img:hover {
opacity: 0.2;
animation: hoverForTouchScreens 2s ease-out;
}
}
Working Example
Putting it all together:
a > img {
opacity: 0.2;
}
a > img:hover {
opacity: 1;
}
a > img.touchscreen-simulation:hover {
opacity: 0.2;
animation: hoverForTouchScreens 2s ease-out;
}
#keyframes hoverForTouchScreens {
0%, 50% {
opacity: 1;
}
}
#media screen and (hover: none) and (pointer: coarse) {
a > img:hover {
opacity: 0.2;
animation: hoverForTouchScreens 2s ease-out;
}
}
<a href="#top">
<img src="https://picsum.photos/120/120" alt="up" title="up">
<img class="touchscreen-simulation" src="https://picsum.photos/120/120" alt="up" title="up">
</a>
<p>The <code>#media query</code> won't be active on non-touch screens, so the <strong>image on the right</strong> is set up to simulate what <em>would</em> happen on a touchscreen in this setup.</p>
Working Example:

Delay the toggleClass action

I have a tab and once I click it the tab fades in. The content gets loaded in with AJAX. After the animation is done I want to load in the content. Right now the content is loading in immediately when I click the button. I tried toggleClass with delay but it didn't work.
How can I delay the content from being loaded in?
This is the HTML :
$("#button-1").on("click", function() {
$(".hidden-content-1", 2000).toggleClass("show-hidden-content", 2000);
$(".main-page-content-1", 2000).toggleClass("hide-shown-content", 2000);
})
#modal-1 {
width: 33.33%;
height: 100vh;
background-color: green;
left: 0;
top: 0;
}
.modals {
transition-timing-function: ease-out;
transition-duration: 1000ms;
position: absolute;
}
.active {
width: 100vw !important;
height: 100vh !important;
}
.show-hidden-content {
display: block !important;
}
.hidden-content-1 {
display: none;
}
.hide-shown-content {
display: none !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="modal-1" class="modals">
<div class="hidden-content-1">
<h1> TEST </h1>
</div>
<div class="main-page-content-1">
<h1>TEST </h1>
</div>
<a id="button-1" href="template-parts/panel1.php"><input onclick="change1()" type="button" value="See More" id="button-text-1"></input>
</a>
</div>
It seems you are looking something like:
$('#button-1').on('click', function () {
setTimeout(() => {
$('.hidden-content-1').toggleClass('show-hidden-content');
$('.main-page-content-1').toggleClass('hide-shown-content');
}, 2000);
});
You might want to use animation-delay
#target {
animation: fade-in 250ms ease-out 1s 1 normal both running;
}
#keyframes fade-in {
0% {
opacity:0;
} 100% {
opacity:1;
}
}

run css animation when visible on scroll

I'm creating my test webpage and I ran into a problem, there are quite a few "answers" on my issue but none was I able to implement in my code. I know I have to use javascript but I was not able to get it working.
So, I need to run css animation of movement on chosen picture, when that picture is visible on screen when I scroll down to it. Basically like on this page: https://www.photoblog.com/
So I have this code in the html as for the picture:
<img class="movepic" src="pictures/test.jpg">
And then there is this simple code for the CSS movement:
.movepic {
position: relative;
animation-name: move;
animation-duration: 3s;
visibility: visible;
animation-fill-mode: forwards;
z-index:10;
}
#keyframes move {
0% { right:0px; top:150px;}
100% {right:700px; top:150px;}
}
Is there a way to make it work so I do not need to completely redo this? Or if so, could some please give me a advice how to do it maybe with code ilustration.
Thanks a lot
I use this code for this effect:
HTML:
<img class="movepic" src="pictures/test.jpg">
CSS:
.movepic {
opacity: 0;
margin: 25px 0 0;
color: white;
padding: 10px;
}
.FadeIn {
-webkit-animation: slideIn 0.8s ease 0.3s forwards;
animation: slideIn 0.8s ease 0.3s forwards;
}
#keyframes slideIn {
0% {
-webkit-transform: translateY(40px);
opacity: 0;
}
100% {
-webkit-transform: translateY(0px);
opacity: 1;
}
}
JQuery:
var $fade = $(".movepic"); //Calling the class in HTML
$(window).scroll(function () { //Using the scroll global variable
$fade.each(function () {
fadeMiddle = $(this).offset().top + (0.4 *$(this).height());
windowBottom = $(window).scrollTop() + $(window).height();
if (fadeMiddle < windowBottom) {
$(this).addClass("FadeIn");
}
});
});
/* On Load: Trigger Scroll Once*/
$(window).scroll();
Remove the animation-name from your style rule:
.movepic {
position: relative;
animation-duration: 3s;
animation-fill-mode: forwards
visibility: visible;
z-index:10;
}
and add this class to stylesheet:
.animation-class {
animation-name: move
}
Now add the jQuery:
var has_fired;
$("html").on("scroll", function () {
if (!has_fired && $(this).scrollTop() >= $("#imgContainer").offset().top) {
$("#imgContainer").addClass("animation-class");
has_fired = true; // use this if only want fired once
}
});
The animation will now run. BTW I would add an ID (imgContainer) to your container of interest and use this as selector for matching because unless .movepic is a unique class, this function will fire for any container with the .movepic class (if .movepic is the selector).

Transition on 5 images

I'm given the following task,
Actual html which I have: Two images are stacked on top of each other.(below html) when the user hovers on the foreground image, as per the CSS rules opacity will be transitioned to 0 in 4 seconds and this keeps happening in a cycle.
Fiddle
Modification I have to do: Now I have to perform the same for 5 images. I've tried doing the same as below, could not succeed(See second code snippet). Any hints as to how this can be done only using css ? thanks
Fiddle2
<!-- Melting one image into another using CSS3. -->
<html>
<head>
<meta charset = "utf-8">
<title>Melting Images</title>
<style type = "text/css">
#cover
{
position: relative;
margin: 0 auto;
}
#cover img
{
position: absolute;
left: 0;
-webkit-transition: opacity 4s ease-in-out;
transition: opacity 4s ease-in-out;
}
#cover img.top:hover
{ opacity:0; }
</style>
</head>
<body>
<div id = "cover">
<img class = "bottom" src = "jhtp.png" alt = "Java 9e cover">
<img class = "top" src = "jhtp8.png" alt = "Java 8e cover">
</div>
</body>
</html>
What I've tried
<html>
<head>
<meta charset = "utf-8">
<title>Melting Images</title>
<style type = "text/css">
#cover
{
position: relative;
margin: 0 auto;
}
#cover img
{
position: absolute;
left: 0;
-webkit-transition: opacity 4s ease-in-out;
transition: opacity 4s ease-in-out;
}
#cover img.top:hover
{ opacity:0; }
#cover img.top1:hover
{ opacity:0; }
#cover img.top2:hover
{ opacity:0; }
#cover img.top3:hover
{ opacity:0; }
</style>
</head>
<body>
<div id = "cover">
<img class = "bottom" src = "jhtp.png" alt = "Java 9e cover">
<img class = "top" src = "jhtp8.png" alt = "Java 8e cover">
<img class = "top1" src = "jhtp1.png" alt = "Java 8e cover">
<img class = "top2" src = "jhtp2.png" alt = "Java 8e cover">
<img class = "top3" src = "jhtp3.png" alt = "Java 8e cover">
</div>
</body>
</html>
You can do that only in CSS, and applying the styles to the container and the children, whatever this are.
I have set an example using div as children, but you can modify it to whatever you want
<div class="container">
<div class="item1">1</div>
<div class="item2">2</div>
<div class="item3">3</div>
<div class="item4">4</div>
<div class="item5">5</div>
</div>
CSS
.container{
width: 80px;
height: 80px;
position: relative;
}
.container div {
position: absolute;
width: 100%;
height: 100%;
font-size: 60px;
opacity: 0;
}
.container div:nth-child(1) {
background-color: yellow;
opacity: 1;
}
.container:hover div {
-webkit-animation: anim 5s infinite;
animation: anim 5s infinite;
}
.container div:nth-child(2) {
-webkit-animation-delay: -4s;
animation-delay: -4s;
}
.container div:nth-child(3) {
-webkit-animation-delay: -3s;
animation-delay: -3s;
}
.container div:nth-child(4) {
-webkit-animation-delay: -2s;
animation-delay: -2s;
}
.container div:nth-child(5) {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
#-webkit-keyframes anim {
0%, 15% {opacity: 1;}
20%, 95% {opacity: 0;}
100% {opacity: 1;}
}
#keyframes anim {
0%, 15% {opacity: 1;}
20%, 95% {opacity: 0;}
100% {opacity: 1;}
}
fiddle
As hovering is a binary process (you're either hovering an element or you're not), I'm afraid this is not possible with CSS only. You write some JS code that will be also triggeren on hover and that will take care of replacing images below and sorting them. However, that seems like an ugly mishmash.
Maybe you could do it using keyframes, but again, you'd need a way to trigger an animation for each image. I'm talking about building a 20s animation for each image and then modifying the opacity value for each in 4 second intervals. But again, seems like too much effort.
So, I'd strongly suggest you write a simple JS image fader that will handle both the image sorting and fade animations at a slight cost of performance.
If you still want to use as much CSS as possible, go with the keyframes, and set a JS listener on the container element which will add a class to each image - that class would trigger the CSS animation for each image. You'll have to repeat the first image and put it at the bottom. The animation would make the 1st image transparent by the second 4, 2nd image by second 8, etc...