I'm currently attempting to get the background image of #InnerImage to fade out. Here is the code for #InnerImage:
<div id="InnerImage" style="background-image:url('imgurl.com'););background-repeat:no-repeat;background-position:50% 0%;">
Here's the code that I'm using:
#OuterImage #InnerImage {
-webkit-animation: 3s ease 0s normal forwards 1 fadein;
animation: 3s ease 0s normal forwards 1 fadein;
}
#keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
#-webkit-keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
I'm running into an issue where the code is making every other child(?) div within #InnerImage fade out as well, but I only want the background-image to fade.
I have two questions:
1) I did read that it was not possible for background-image opacity changes that the above code is performing. Is there a work around for this?
2) How do I go about making it so that after the image has been faded in, it fades back out in an infinite loop?
[EDIT]
#OuterImage #InnerImage{
-webkit-animation: 3s ease 0s normal forwards 1 fadein;
animation: 3s ease 0s normal forwards 1 fadein;
animation-iteration-count: infinite;
}
#keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
#-webkit-keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
#OuterImage #InnerImage::before {
background: url('imgurl.com') no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0;
right: 0;
bottom: 0;
left: 0;
transition: opacity 1s ease 2s;
z-index: 1;
}
#OuterImage #InnerImage {
position: relative;}
#OuterImage #InnerImage * {
position: relative;
z-index: 2;
}
#OuterImage #InnerImage
Answer to your first question:
Put the background-image on a pseudo element ::before instead:
#InnerImage::before {
background: url('imgurl.com') no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0; right: 0; bottom: 0; left: 0;
z-index: 1;
}
This requires to set position: relative; on #InnerImage:
#InnerImage {
position: relative;
}
and you need to make sure all other child elements are above the pseudo element using z-index (which only applies the way you need if you position those elements):
#InnerImage * {
position: relative;
z-index: 2;
}
Notice: #OuterImage #InnerImage can be safely shortened to #InnerImage since there may be only one element on a page with any given id value anyway. Also I'd advise not to use id selectors in CSS unless you know for sure why you are doing it.
Regarding your animation, it seems like you want it to start only after two seconds have gone by. This can be achieve using a transition like this:
transition: opacity 1s ease 2s;
where 1s is transition-duration and 2s is transition-delay.
https://developer.mozilla.org/en/docs/Web/CSS/transition
Example:
#InnerImage::before {
background: url(http://lorempixel.com/300/200) no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0;
right: 0;
bottom: 0;
left: 0;
transition: opacity 1s ease 2s;
z-index: 1;
}
#InnerImage {
position: relative;
width: 300px;
height: 200px;
}
#InnerImage * {
position: relative;
z-index: 2;
}
#InnerImage:hover::before {
opacity: 0.25;
}
<div id="InnerImage">
<h2>Hey!</h2>
<button>noop</button>
</div>
If you want a permanently on-going fadein-fadeout, you'll have to go with an animation instead of a transition.
#InnerImage::before {
background: url(http://lorempixel.com/300/200) no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
animation: 3s ease 0s normal forwards 1 fadein;
animation-iteration-count: infinite;
}
#InnerImage {
position: relative;
width: 300px;
height: 200px;
}
#InnerImage * {
position: relative;
z-index: 2;
}
#keyframes fadein{
0% { opacity:0; }
50% { opacity: 1; }
100% { opacity:0; }
}
<div id="InnerImage">
<h2>Hey!</h2>
<button>noop</button>
</div>
To animate in an infinite loop you can use the animation-iteration-count property and set the value to infinite.
#OuterImage #InnerImage {
-webkit-animation: 3s ease 0s normal forwards 1 fadein;
animation: 3s ease 0s normal forwards 1 fadein;
animation-iteration-count: infinite;
}
Changing the opacity of an element will effect all child elements there is no way around that.
A work around you may consider is to create a element inside #InnerImage that solely handles the background. You set the background div to be position absolute, with a z-index of 0, then animate only this div. That way the other elements will not change in opacity as the animation changes.
#InnerImage {
height:200px;
position:relative;
}
.bg {
position: absolute;
height: 100%;
width: 100%;
background: red;
z-index: 0;
animation-name: fadein;
animation-duration: 6s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
}
.content {
position: relative;
}
#keyframes fadein{
0% { opacity:0; }
50% { opacity:1; }
100% { opacity:0; }
}
<div id="InnerImage">
<div class="bg"></div>
<div class="content">other content</div>
</div>
Note in the example the text content does not fade while the background does
Related
I tested with the following answers:
Pure CSS rotate animation broken while in infinite loop
Stop infinite CSS3 animation and smoothly revert to initial state
CSS Image Fade Animation Only Runs First Time,
but the animation duration and timeline (for example, from step by step, from start to end) did not work. The three images need to be in the same place at once.
I wanted to use https://codepen.io/jay-bee-why/pen/Htejl, but unfortunately I do not want to use jQuery. I am CSS and JavaScript purist.
An image is worth a thousand words. You will understand easily the image. I also provide very small snippet code box.
.flipping-images
{
align-items: center;
display: flex;
flex-flow: row nowrap;
height: 80%;
justify-content: center;
/* opacity: 0; */
position: relative;
transform: translateX(100%);
width: 22%;
}
.show-l
{
animation: show-image 5s ease-in-out 300ms infinite;
left: 0;
position: absolute;
transform-origin: left;
}
.hide-l
{
animation: hide-image 5s ease-in-out 800ms infinite;
position: absolute;
transform-origin: left;
}
.hide-l2
{
animation: hide-image 5s ease-in-out 600ms infinite;
position: absolute;
transform-origin: right;
}
#keyframes hide-image
{
0%
{
left: 0;
transform: rotateY(0deg);
}
30%
{
left: 10%;
transform: rotateY(0deg);
}
50%
{
opacity: 1;
}
100%
{
left: -100%;
opacity: 0;
transform: rotateY(90deg);
}
}
#keyframes show-image
{
0%
{
left: 100%;
transform: rotateY(90deg);
}
30%
{
left: 110%;
transform: rotateY(90deg);
}
100%
{
left: 0%;
transform: rotateY(0deg);
}
}
<div class="flipping-images">
<img class="show-l" src="https://via.placeholder.com/432x864/fdc34f/FEFEFE?text=1">
<img class="hide-l2" src="https://via.placeholder.com/432x864/3e72ff/FEFEFE?text=2">
<img class="hide-l" src="https://via.placeholder.com/432x864/222222/FEFEFE?text=3">
</div>
I'm not sure I understand your image since it says the second image should disappear but it also says the animation is infinite. I hope it's working as you intended, if not just leave a comment on what needs to be fixed.
I'm using the animationend event to control the animations.
var counter = 1;
var div = document.querySelector('.flipping-images');
var images = document.querySelectorAll('.flipping-images img');
var showNext = function () {
counter++;
if (counter > 3) counter = 1;
div.classList.remove('image1', 'image2', 'image3')
div.classList.add('image'+counter);
};
for (var img of images) {
img.addEventListener('animationend', showNext);
img.addEventListener('click', showNext);
}
document.querySelector('#next').addEventListener('click', showNext);
.flipping-images {
perspective: 300px;
}
.flipping-images img {
display: none;
animation: rotate 5s linear 1;
}
.flipping-images.image1 img:nth-child(1),
.flipping-images.image2 img:nth-child(2),
.flipping-images.image3 img:nth-child(3) {
display: block;
}
.flipping-images.image2 img:nth-child(2) {
animation: rotate 5s linear infinite;
}
#keyframes rotate {
0% { transform: rotateY(-45deg); }
100% { transform: rotateY(45deg); }
}
button {
margin: 1em;
}
<div class="flipping-images image1">
<img src="https://via.placeholder.com/100x100/fdc34f/FEFEFE?text=1">
<img src="https://via.placeholder.com/100x100/3e72ff/FEFEFE?text=2">
<img src="https://via.placeholder.com/100x100/222222/FEFEFE?text=3">
</div>
<button id="next">Next</button>
I'm trying to create a visual transition between content changes in a toy SPA I'm writing. To that end, I define a simple class for animating the opacity of an element.
.fade {
transition: opacity 1.5s;
}
In my render function, I now change the opacity of my outlet div after content changes like so:
function render(content) {
var outlet = document.getElementById("outlet");
outlet.classList.remove("fade");
outlet.style.opacity = 0;
outlet.innerHTML = content;
outlet.classList.add("fade");
outlet.style.opacity = 1;
}
Unfortunately, the animation never fires. When I delay changing the opacity to 1 via setTimeout for 10ms, say, it works sometimes if I don't change the content again while the animation is still running, indicating a timing issue/race condition.
I used a similar approach in the past to fade out messages, but there I intentionally delayed changing the opacity by a few seconds so users could read the message before it starts fading out.
Pure CSS animation fadeIn
li {
position: absolute;
top: 50%;
left: 50%;
margin-top: -75px;
}
.logo {
width: 300px;
height: 150px;
background: red;
margin-left: -150px;
z-index: 30;
-webkit-animation: fade-in-slogan 4s .2s ease-in forwards;
-moz-animation: fade-in-slogan 4s .2s ease-in forwards;
animation: fade-in-slogan 4s .2s ease-in forwards;
}
.menu {
width: 600px;
height: 150px;
background: blue;
margin-left: -300px;
opacity: 0;
-webkit-animation: fade-in-menu 3s 4s ease-out forwards;
-moz-animation: fade-in-menu 3s 4s ease-out forwards;
animation: fade-in-menu 3s 4s ease-out forwards;
}
#-webkit-keyframes fade-in-slogan {
0% { opacity: 0; }
30% { opacity: 1; }
50% { opacity: 1; }
70% { opacity: 1; }
100% { opacity: 0; }
}
#-webkit-keyframes fade-in-menu {
0% { display: block; opacity: 0; }
30% { display: block; opacity: .3; }
60% { display: block; opacity: .6; }
80% { display: block; opacity: .8; }
100% { display: block; opacity: 1; }
}
<ul class"main">
<li class="logo"></li>
<li class="menu"></li>
</ul>
Try this, I hope this will solve the issue
.fade{
animation-name: example;
animation-duration: 4s;}
#keyframes example {
from {opacity:1}
to {opacity:0;}
}
div{
width:200px;
height:200px;
background:#000;
}
<html>
<head>
</head>
<body>
<div class="fade"></div>
</body>
</html>
I've solved it now inspired by Muhammad's answer. I defined the fade class as follows:
.fade {
animation-name: fadein;
animation-duration: 1.25s;
#keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}
Then in the render function, I do
function render(content) {
outlet.classList.remove("fade");
outlet.innerHTML = "";
setTimeout(() => {
outlet.classList.add("fade");
outlet.appendChild(content);
}, 100);
}
Even though this adds an additional delay before the new content actually starts to fade in, it seems the most elegant and concise solution to me.
The code below is a part of my code :
.myBox:hover::after {
animation-name: underline;
animation-duration: 350ms;
animation-fill-mode: forwards;
}
#keyframes underline {
from { width: 0; }
to { width: 100%; }
}
It works nicley, but I want to do it vice versa when animation completed, I mean when it finished then width should be 0 again, In fact for this part I want to do it when my element is not hovered. Which property can help me ?
You need to use alternate and run 2 iterations of the animation:
.box {
height:200px;
background:red;
animation: underline 500ms alternate 2 forwards;
}
#keyframes underline {
from { width: 0; }
to { width: 100%; }
}
<div class="box">
</div>
Or consider the use of transition if you want the effect on hover:
.box {
height: 200px;
background: red;
width: 0;
transition: 500ms;
}
body:hover .box {
width: 100%;
}
<div class="box">
</div>
You can specify multiple values for animations rather then from and to using percentage:
#keyframes underline {
0%, 100% { width: 0; }
50% { width: 100%; }
}
More detailed information can be found here.
.myBox:hover::after {
animation-name: underline infinite;
animation-duration: 350ms;
animation-fill-mode: forwards;
}
#keyframes underline {
from { width: 0; }
to { width: 100%; }
}
You infinite for this
I currently have the following code in my angular app (2+):
.header {
background: rgba(white, 0);
&.fixed-top {
background: rgba(white, 1);
border-bottom: solid whitesmoke 1px;
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: 1030;
}
}
<nav class="navbar navbar-toggleable-sm header" [class.fixed-top]="stickyHeader" (scroll)="scrollHandler()">...</nav>
The handleScroll() function simply sets stickyHeader to true after the user scrolls down "enough" pixels, and so the header menu becomes sticky. Here it is:
stickyHeader = false;
#HostListener('window:scroll', [])
scrollHandler() {
this.stickyHeader = window.scrollY > 90;
}
My question is: how can I make that menu appear to slide (animated) from top, as if it descended from above the browser?!
I am able to get the desired result by animating transform: translate using CSS animations
I have set animation-iteration-count to infinite for demo purposes. In your case it would be 1
To control the speed use animation-duration
I also use animation-fill-mode and set it to forwards to stop the animation at the end and not have it revert to the original state.
I added transform: translate(0, -20px) to .fixed-top to move it out of the display area until the animation starts.
Finally, I added animation-timing-function: ease; to control how the animation plays.
body {
margin: 0 auto;
padding: 0;
}
.fixed-top {
background: red;
z-index: 1030;
width: 100%;
height: 50%;
animation-name: slide;
animation-duration: 2s;
animation-timing-function: ease;
animation-iteration-count: infinite;
animation-fill-mode: forwards;
transform: translate(0, -20px)
}
#keyframes slide {
0% {
transform: translate(0, -20px);
opacity:.1
}
100% {
transform: translate(0, 0);
opacity:1
}
}
<div class="fixed-top">test</div>
I made a subtle background movement, but the effect isn't that pleasing. While moving it kinda jerks, you can see the image move pixel by pixel.
How can I change this so it becomes a nice smooth animation.
The Code (https://jsfiddle.net/38tf0j21/):
body {
padding:50px;
margin 0;
height:100vh;
}
.landing_img_container {
position: absolute;
right: 0;
width: calc(100% - 100px);
height: 100%;
animation-name: start_animation;
animation-delay: 1s;
animation-direction: normal;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: ease;
}
.landing_img {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color:red;
}
#keyframes start_animation {
0% {
left: 100px;
}
100% {
left: 50px;
}
}
<div class="landing_img_container">
<div class="landing_img"></div>
</div>
This should work like you expect it to: https://jsfiddle.net/38tf0j21/2/
This is using the transform property instead of left
For smooth CSS position animations you need use transform: translate3d property.
See this example