Imagine I have the following:
<label style="height:50px;width:50px">
<img src="test.svg" width="30" height="30" style="cursor:pointer">
</label>
My objective is to make the <img> do a visual pop when it is pressed (on a mobile device). By pop, I mean a quick fade in and fade out (e.g. via applying lowered opacity, and then reverting it).
To achieve this, I added a class to the <label>. This class affects opacity when the label is focused, like so:
.pop:focus img{
opacity: 0.5;
}
<label class="pop" style="height:50px;width:50px">
<img src="https://www.clipartkey.com/mpngs/m/100-1009872_png-file-svg-laughing-emoji-black-and-white.png" width="30" height="30" style="cursor:pointer">
</label>
Needless to say, this does not work.
I need the simplest solution available that solves this problem. To be specific, I prefer pure CSS solutions (that too, using well-supported CSS properties as per caniuse.com). JS or esoteric CSS properties should not be needed for simple tasks like these, in my opinion. Unless of course, I am wrong and this task is not simple.
You can use a checkbox to trigger an animation like this:
HTML:
<label class="pop">
<input type="checkbox" class="trigger">
<img src="https://www.clipartkey.com/mpngs/m/100-1009872_png-file-svg-laughing-emoji-black-and-white.png" width="30" height="30" style="cursor:pointer">
</label>
CSS:
.pop {
display: inline-flex; //to center img
position: relative; //for the checkbox sizing
}
.pop > img {
margin: auto; //center image in the label
opacity: 1; //default opacity
}
.trigger {
position: absolute; //make checkbox the same size as the label
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0; //hide the checkbox so it isn't visible
}
.trigger:checked ~ img {
animation: pop 300ms; //add an animation property to the img sibling when the checkbox is clicked(checked)
}
// pop animation
#keyframes pop {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
JS Fiddle
It is easy to do, if you have a little Javascript and a CSS animation. Maybe something like this:
document.getElementById("img").addEventListener("click", function() {
this.style.animation = "fade 1s linear 1";
setTimeout(function() {
document.getElementById("img").style.animation = "";
}, 1000)
});
#keyframes fade {
0% {
opacity: 1
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#img {
background-color: red;
border: 1px solid black;
width: 100px;
height: 100px;
}
<label id="label">
<div id = "img"></div>
</label>
Or, if you don't want Js, you could do something like this:
#img {
width: 100px;
height: 100px;
background-color: red;
transition: 1s;
}
#img:active {
opacity: 0;
}
<label id="label">
<div id = "img"></div>
</label>
If you move the text input to before the label, then you can trigger the animation on focusing the input, which happens when the label is clicked. It then possible to display the input after the label again by, for example, use flex with row-reverse.
<div class="pop-label-image">
<input type="text" id="example">
<label for="example">
<img src="https://via.placeholder.com/30">
</label>
</div>
.pop-label-image {
display: flex;
flex-direction: row-reverse;
align-items: baseline;
justify-content: start;
}
#keyframes pop {
0% {
opacity: 1
}
50% {
opacity: .5;
}
100% {
opacity: 1;
}
}
.pop-label-image input:focus + label {
animation: pop 500ms;
}
Related
The demo is quite simple, and similar to the example in the Vue.js docs.
new Vue({
el: '#demo',
data: {
show: true
}
})
p {
width: 100px;
border: 1px solid red;
}
.fade-enter-active,
.fade-leave-active {
transition: all 5s;
}
.fade-enter {
opacity: 0;
width: 500px;
background: red;
}
.fade-enter-to {
background: black
}
.fade-leave {
opacity: 0;
background: red
}
.fade-leave-to {
background: black;
width: 1000px;
opacity: 1
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
The question is, when the leave animation begins, it seems it's removed from the DOM (v-if is false) so quickly that there isn't any animation at all!
But, if I remove opacity, the animation works! Why does opacity matter?
.fade-leave {
/* opacity: 0; */
background: red;
}
.fade-leave-to {
background: black;
width: 1000px;
/* opacity:1; */
}
There is another question, I thought the leave animation should be that the DOM background becomes red firstly (while the result is it didn't or I just can't tell), then change to black slowly. So, is it my misconception?
The opacity is important because the animation is fading according to it.
Here I have added to opacity of 0 directly to the class fade-enter-active of the button Hello. You can see the animation fading step by step.
Instead, with an opacity of 1, there is no direction to your fading. It stays at 1.
I have two divs that appear like this:
The idea is that when you close the bottom div (click on the 'X'), it should disappear.
And when you close the top div, it should disappear, and also the bottom div should slide up and take its place.
I'm very new to jQuery, but this is my first attempt:
function initAnnouncements() {
$(document)
// Closes announcement modules
.on('click', 'annoucements-close', function () {
$('announcement-div').hide();
})
}
#keyframes slideInFromRight {
0% {
transform: translateX(100%);
}
.1%{
opacity: 1;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
.announcements-container {
position: fixed;
top: 80px;
right: 20px;
z-index: 1001;
display: flex;
flex-direction: column;
width: 300px;
/* align-items: flex-end; */
}
.announcements-1 {
animation: slideInFromRight 0.4s ease;
opacity: 0;
animation-fill-mode: forwards;
}
.announcements-2 {
/* animation: 0.4s ease-out 0s 1 slideInFromRight; */
animation: slideInFromRight 0.4s ease;
opacity: 0;
animation-fill-mode: forwards;
animation-delay: .4s;
margin-top: 15px;
}
.annoucements-header {
background-color: #1481C3;
color: #ffffff;
font-family: "Proxima Nova Bold";
padding: 7px 10px;
}
.annoucements-close {
position: absolute;
right: 5px;
width: 24px;
height: 36px;
cursor: pointer;
opacity: .85;
}
.annoucements-close:hover {
opacity: 1;
}
.annoucements-close::before,
.annoucements-close::after {
content: '';
width: 24px;
height: 2px;
background: white;
position: absolute;
top: 7px;
left: 0;
}
.annoucements-close::before {
transform: rotate(-45deg);
}
.annoucements-close::after {
transform: rotate(45deg);
}
/*opened or closed*/
.announcement-div-opened {
display: none;
}
.announcement-div.opened .announcement-div-opened {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class="announcements-container">
<div class="announcement-div announcements-1">
<div class="annoucements-header">
<span class="annoucement-type-quantity">2 School Announcements</span>
<i class="annoucements-close"></i>
</div>
</div>
<div class="announcement-div announcements-2">
<div class="annoucements-header">
<span class="annoucement-type-quantity">1 Admin Announcement</span>
<i class="annoucements-close"></i>
</div>
</div>
</div>
</body>
As you can see this isn't doing anything. I'm trying to toggle the class from 'open' (display:block) to 'closed' (display:none) when the annoucements-close <i> element is clicked on.
And ideally I would like for the second div to slide up when the top one is closed, but first I'd just like to get either one to disappear.
What's wrong with my code where that's not working as expected?
Link to JSFiddle
There are 2 issues with your code: the click() event is inside the function initAnnouncements that doesn't get called. You could move it outside of this function or call the function. Then you have issues with your selectors: It's
.on('click', '.annoucements-close', function () {
$('.announcement-div').hide();
})
instead of
.on('click', 'annoucements-close', function () {
$('announcement-div').hide();
})
for class selectors. Working Fiddle.
If you just want to hide the annoucement which was clicked upon, just change it to
.on('click', '.annoucements-close', function () {
$(this).closest('.announcement-div').hide();
})
I looked at your code and adjusted it a little to demonstrate:
Added your common class on the two announcements "announcement-div"
Attached the document click handler with the jQuery ready event
Used the delegated event selector to listen to clicks within the document that match that common selector
On click of one of the announcement-div's animate the height to 0 and then remove the element
Comments are included in the fiddle. Hope this is helpful!
// Fire this function when the document is ready
$(function() {
// Listen on the whole document for click events on the .announcement-div element
$(document).on('click', '.annoucements-close', function () {
// From the close button find the closest parent "announcement-div"
var annoucement = $(this).closest('.announcement-div');
// Function to run after animating the element (use .hide() to keep element but display:none)
function destroy() {
annoucement.remove();
}
// Animate the annoucement's height to 0 over 400ms and then call the destroy function
annoucement.animate({ height: "0px" }, 400, destroy);
});
});
Updated JS Fiddle
I want to animate (fade-in) a div at or after the initial mounting of a component. After the animation is done, the div shouldn't disappear. I am trying to use CSSTransition component and looking examples on reactcommunity.org but I couldn't achieve any animation at all. I don't have any value that comes from somewhere for in, so I tried both trueand false but nothing changed.
CSS
.example-enter {
opacity: 0;
}
.example-enter-active {
opacity: 1;
transition: opacity 300ms;
}
.example-exit {
opacity: 1;
}
.example-exit-active {
opacity: 0;
transition: opacity 300ms;
}
React
<CSSTransition classNames='example' in={false} timeout={200}>
<div
className='abc'
data-description="abc">
<div className='inner'>
<div className='head'>A</div>
<div className='explanation'>A</div>
</div>
</div>
</CSSTransition>
If you want to transition on the first mount set appear to true: Transition-prop-appear
You can try this:
<CSSTransition
in={true}
timeout={1000}
classNames="fade"
appear={true}
>
<div className="box" />
</CSSTransition>
Css:
.fade-appear {
opacity: 0;
transform: scale(0.2);
}
.fade-appear-active {
opacity: 1;
transform: scale(1);
transition: all 1000ms;
}
.box {
width: 50px;
height: 50px;
background: aqua;
}
See my code detail here: https://codesandbox.io/s/csstransition-component-okpue
Another easy way is to use CSS animations. no need to set extra class for your element.
Just use it in your desired element's CSS code :
Thanks to animate.css plugin for CSS, take a look at it:
https://daneden.github.io/animate.css/
the example:
#-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.elem {
padding: 40px 30px;
background: #aaa;
animation: fadeIn 2s;
}
<div class="elem">
Hello, this is a text
</div>
I wrote such a code to operate opacity at check time. This worked.
#check1:checked+.box {
animation: blink 1s;
}
#keyframes blink {
0%,
99% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<input type="checkbox" id="check1">
<div class="box">
<div class="content">
<p>content</p>
<button type="button">
<label for="check1">click me</label>
</button>
</div>
</div>
I also wanted to do the same operation when unchecking, so I added the animation property.
However, this will not work and the animation at check will not work. Why does this happen?
#check1 + .box {
animation: blink 1s;
}
#check1:checked + .box {
animation: blink 1s;
}
#keyframes blink {
0%, 99% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<input type="checkbox" id="check1">
<div class="box">
<div class="content">
<p>content</p>
<button type="button">
<label for="check1">click me</label>
</button>
</div>
</div>
Also, I defined an animation with the exact same processing as another name, and it worked normally. Why does this happen? Is there a smart CSS solution?
#check1+.box {
animation: blink1 1s;
}
#check1:checked+.box {
animation: blink2 1s;
}
#keyframes blink1 {
0%,
99% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#keyframes blink2 {
0%,
99% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<input type="checkbox" id="check1">
<div class="box">
<div class="content">
<p>content</p>
<button type="button">
<label for="check1">click me</label>
</button>
</div>
</div>
go through it, I hope it will work for you
#check1+.box {
opacity:1;transition: 1s;
}
#check1:checked+.box {
opacity:0;transition: 1s;
}
<input type="checkbox" id="check1">
<div class="box">
<div class="content">
<p>content</p>
<button type="button">
<label for="check1">click me</label>
</button>
</div>
</div>
"...but why does it stop working when changing it to the checked pseudo-class?"
The unchecked state needs to have an explicit selector like:
#check1:not(:checked)
but that won't work with current layout because:
The trigger (i.e. <label>) is nested within the target (i.e. .box). That looks very awkward. In the updated demo, I had to remove the trigger from the flow by using:
position:absolute; z-index: 1; pointer-events:auto
and then the target (i.e. .box) pointer-events: none
The checkbox "state" is persistent so if selectors are similar, more than likely the latest version overrides previous selectors. In order to make everything animate from one keyframe I needed behavior that did not persist and had only one state -- :active.
:active
The animation occurs when the checkbox is checked/unchecked. If you take a step back check/uncheck looks a lot like click and the animation itself behaves briefly (like its namesake "blink"). The state of :active occurs when the user clicks -- specifically mousedown until mouseup.
HTML
Required
<br id='target'>
...
<a href='#target' class='link'>X</a>
CSS
Required
.box { pointer-events: none; }
.link { ...position: relative; z-index: 1;...pointer-events: auto; }
:target + .box :not(:active) { ... }
Demo 1
.box {
pointer-events: none;
}
.X {
display: inline-block;
position: relative;
z-index: 1;
background: rgba(0, 0, 0, 0.1);
width: 5ch;
height: 2.5ex;
line-height: 2.5ex;
border: 2px outset grey;
border-radius: 4px;
color: #000;
text-align: center;
text-decoration: none;
padding: 1px 3px;
pointer-events: auto;
}
:target+.box :not(:active) {
animation: blink 2s linear 0.1s;
}
#keyframes blink {
0% {
opacity: 0s;
}
70% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<br id='target'>
<article class="box">
<section class="content">
<p>Content inside .box</p>
<a href='#target' class='X'>X</a>
</section>
</article>
<p>Content outside of .box</p>
.box {
width: 100px;
height: 100px;
background: red;
transition: all 1s ease-in-out;
}
.box:hover {
background: yellow;
}
<div class="box"></div>
If the cursor is over the .box for less than a second, the transition stops and falls back to it's original phase.
Is there a way to somehow force the whole animation, regardless of hover duration?
fiddle
Edit: Similar solution but relying on transition and animation: https://jsfiddle.net/ok7pnrsL/
This is my solution: https://jsfiddle.net/9yu0cozq/1/
Basically you need to add a container for the box and then play with CSS animations.
<div id="container">
<div class="box"></div>
</div>
When the mouse enters the .box then the hidden container appears (please note that for this to work that container should have enough width and height to fit the whole area where the mouse might go).
This container creates an animation for itself to "hide" back in 1s. and while it is shown the .box has an animation for the same time.
#container {
position:absolute;
z-index:1;
width: 0;
height: 0;
}
#container:hover{
animation-name:changeSize;
animation-duration: 1s;
}
#container:hover .box{
animation-name:changeColor;
animation-duration: 1s;
}
.box {
z-index:0;
position:absolute;
width: 100px;
height: 100px;
background: red;
transition:1s background;
}
.box:hover {
background: yellow;
}
#keyframes changeColor {
0% {
background: red;
}
100% {
background: yellow;
}
}
#keyframes changeSize {
0%,99% {
width: 100%;height: 100%;
}
100% {
width: 0;height: 0;
}
}
So, without knowing the real context, this solution gives a series of assumptions that might or might not fit your exact case but gives an idea of how to solve it using pure CSS.
I think you heave to use JS for this. First you need to create animation for background change, and and then you can set it as class and add that class on hover, and remove it when animation ends or on webkitAnimationEnd.
$('.box').hover(function() {
$(this).addClass('animate');
$(this).on('webkitAnimationEnd', function() {
$(this).removeClass('animate');
})
})
.box {
width: 100px;
height: 100px;
background: red;
display: inline-block;
margin: 10px;
}
.box.animate {
animation: changeColor 2s linear;
}
#keyframes changeColor {
0% {
background: red;
}
50% {
background: yellow;
}
100% {
background: red;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box"></div>
<div class="box"></div>
I don't think you can do this without javascript, but it would be interesting to find out.
A light weight javascript solution could be something like this:
// Get the elemnt
var myDiv = document.getElementById('box');
// Detect hover
myDiv.onmouseover = function() {
// Add a force class to the element
myDiv.className += " force";
// Reset the cass name after 1sec (100ms)
setTimeout(function(){ myDiv.className = "box"; }, 1000, myDiv);
}
Change your markup slightly to make things easier for now:
<div id="box" class="box"></div>
And add an extra class to your css styles along with the hover state:
.box {
width: 100px;
height: 100px;
background: red;
transition: all 1s ease-in-out;
}
.box.force,
.box:hover {
background: yellow;
}
Check the jsfiddle