CSS transitions will not apply if you set the display property of an element to block immediately before changing the property with the transition attached. You can see the issue in the following example:
var dom = {};
dom.creative = document.getElementById('creative');
dom.creative.style.display = 'block';
dom.creative.style.opacity = 1;
#creative {
display: none;
opacity: 0;
transition: opacity 2s;
}
<div id="creative">
<span>Sample text</span>
</div>
The issue can be fixed by forcing a repaint on the element:
var dom = {};
dom.creative = document.getElementById('creative');
dom.creative.style.display = 'block';
var a = dom.creative.offsetHeight; /* <-- forces repaint */
dom.creative.style.opacity = 1;
#creative {
display: none;
opacity: 0;
transition: opacity 2s;
}
<div id="creative">
<span>Sample text</span>
</div>
This solution is not good because it adds the need of a non intuitive extra line of code everytime you need the display transition combination.
A SO user found an elegant solution (https://stackoverflow.com/a/38210213/6004250) to this problem replacing the transition by the animation property. I'm still curious about making it work together with CSS transitions (because they are easier to understand and to use). Any ideas?
Related
I would like to make a Text run from left to right in a loop. Here is the fiddle with my attempt:
https://jsfiddle.net/9Lruxym8/33/
I started with css #keyframes but I think I need the width of the text itself if I want the text to run seamlessly. My idea was to write down the text two times and once the div with the texts has run exactly halfway, the animation starts again.
After #keyframes didn't work, I tried jQuery animation. It did work somewhat but didn't run smoothly. Now I'd like to do it via transition. I thought a combination of intervals and timeouts could do the trick but I still don't get it to work - and now, I don't know why. Does anyone have a hit for me?
function runText() {
var text_width = $('#runningP').width()/2;
console.log(text_width)
setInterval(function(){
console.log("interval");
$('.text').css({'transition':'margin-left 5s'});
$('.text').css({'margin-left':'-' + text_width + 'px'});
moveBack();
}, 3000);
function moveBack() {
console.log("timeout")
setTimeout(function(){
$('.text').css({'transition':'none'});
$('.text').css({'margin-left': 0});
}, 3000);
}
}
runText();
I've recently made a bit of custom code for this functionality.
Looking at my code, it seems a bit much having essentially 3 "levels" (.scrollTextWrap > .scrollingText > .scrollContent) but this was the structure I ended up using to get a clean and consistent effect.
I've added in an initialiser too so that you could simply add the scrollMe class and have them setup the html for you
In the snippet I've added a .parentContainer purely to show how it works when constrained
$(document)
.ready(function(){
// check that scrollingText has 2 scrollContent element
$('.scrollMe')
.each(function(){
initScrollingText($(this));
});
});
function initScrollingText($this){
// store text
var text = $this.text();
// empty element
$this.html(null);
var $wrap = $('<div class="scrollTextWrap" />'),
$text = $('<div class="scrollingText" />'),
$content = $('<div class="scrollContent" />');
// set content value
$content.text(text);
// duplicate content
$text
.append($content)
.append($content.clone());
// append text to wrap
$wrap.append($text)
// add $wrap to DOM
$wrap.insertAfter($this);
// remove old element
$this.remove();
}
/* to simulate width constraints */
.parentContainer {
width: 140px;
position:relative;
overflow:hidden;
}
.scrollTextWrap {
position:relative;
width:auto;
display:inline-block;
}
.scrollingText {
display: flex;
position:relative;
transition:left 0.1s;
animation: scrollText 5s infinite linear;
}
.scrollContent {
white-space: nowrap;
padding-right:5px;
}
#keyframes scrollText {
0% { left:0 }
100% { left:-50% }
}
<div class="parentContainer">
<div class="scrollMe">Content you want to scroll goes here</div>
<!-- alternatively you can just structure the html -->
<div class="scrollTextWrap">
<div class="scrollingText">
<div class="scrollContent">Content you want to scroll goes here</div>
<div class="scrollContent">Content you want to scroll goes here</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I asked a question earlier about fading an element in and out which was answered with the solution I will post later on, however I left out some information that proves to be more relevant than I originally realized.
I am trying to fade an element in on the hover of a separate trigger element and out when the mouse leaves that same trigger element. currently if I move from one trigger element to another trigger element the first element doesn't fade out.
I have tried a number of solutions including the following two jsfiddles which handle the fading fine but still have the issue I was having occuring when switching trigger elements.
Here is the current mock up of code I'm using:
<img id="project1-img" src="https://i.imgur.com/ZEDaxij.jpg" style="height: 100px; width: 100px; opacity: 0;">
<img id="project2-img" src="https://i.imgur.com/ZEDaxij.jpg" style="height: 100px; width: 100px; opacity: 0;">
<img id="project3-img" src="https://i.imgur.com/ZEDaxij.jpg" style="height: 100px; width: 100px; opacity: 0;">
<span id="trigger1">
111111111111
</span>
<span id="trigger2">
22222222222
</span >
<span id="trigger3">
33333333333
</span>
let state = "disappeared"; // disappeared, appearing, appeared, disappearing
let opacity = 0; // Current raw opacity value
let fadeInc = 0.05; // Amount to fade each frame
let findElementToFade = (imageId) => {
let elem = document.getElementById(imageId);
tryDoFade(elem);
}
let tryDoFade = elem =>
requestAnimationFrame(() => {
//console.log("called with " + imageId);
//let state = "disappeared"; // disappeared, appearing, appeared, disappearing
let changed = false;
if (state === "appearing" && opacity < 1)
opacity = Math.min(1, opacity + fadeInc);
else if (state === "disappearing" && opacity > 0)
opacity = Math.max(0, opacity - fadeInc);
elem.style.opacity = opacity;
// Enter a rest state if opacity maxes out in either direction
if (opacity === 0) state = "disappeared";
else if (opacity === 1) state = "appeared";
// Keep animating if not in a rest state
if (state === "disappearing" || state === "appearing") tryDoFade(elem);
});
let e = document.getElementById('trigger1');
e.onmouseover=() =>(state = "appearing") && findElementToFade(`project3-img`)
e.onmouseout=() =>(state = "disappearing") && findElementToFade(`project3-img`)
let f = document.getElementById('trigger2');
f.onmouseover=() =>(state = "appearing") && findElementToFade(`project2-img`)
f.onmouseout=() =>(state = "disappearing") && findElementToFade(`project2-img`)
let g = document.getElementById('trigger3');
g.onmouseover=() =>(state = "appearing") && findElementToFade(`project1-img`)
g.onmouseout=() =>(state = "disappearing") && findElementToFade(`project1-img`)
Here are the JsFiddles I've been playing with:
https://jsfiddle.net/dm9cgysL/1/
This is the solution to my last question which doesn't work in my particular case:
https://jsfiddle.net/03sgm1ot/
Here is a jsfiddle that is more accurate to what I am trying to do:
https://jsfiddle.net/dm9cgysL/6/
I expect for each of the elements to fade in and out independently as soon as the mouse enters/exits the trigger elements, currently if I go from one trigger element to the next it causes the previous fade to stop in its tracks leaving the element on the page.
RESOLVED: I modified the answer I marked as the answer to fit my needs here is what I did:
CSS:
img.transition {
transition: opacity 0.25s;
-moz-transition: opacity 0.25s;
-webkit-transition: opacity 0.25s;
opacity: 0;
}
img.transition.visible {
opacity: 1;
}
The images I used have a class name of transition:
<img id="project1-img" src="/static/media/mtg.4c420286.png" class="ui fluid image transition" >
My trigger elements have the following mouse events:
onMouseOver={() => handleTransition(`project1-img`)}
onMouseOut={() => handleTransition(`project1-img`)}
And my handleTransition function is as follows:
const handleTransition = id => {
let target = document.getElementById(id);
if (target.classList.contains("visible")) {
target.classList.remove("visible");
} else {
target.classList.add("visible");
}
};
This is a much cleaner solution to the issue I was having, I didn't realize that css had built in transitions like this and I'm going to have to look into them further. Thanks to everyone who took a look and thanks to GammaGames for the solution that got me here.
Learning css would really help with this case, especially since you're modifying the element's css manually with the style attribute anyway. I'm sure you could use data attributes to store timeout ids or something hacky, but for a simple solution I:
Add a data-target attribute to each <span> that I want to listen to
On mouseover, add a visible class to the image with the matching target id
On mouseout, remove the visible class to the image with the matching target id
img tags with the transition class have 0 opacity by default and transition with 0.25s time. The visible class makes the opacity into 1, and the element automatically transitions. You can read more about transitions here.
$(".trigger").on("mouseover", function() {
let target = $(this).data("target");
$(`#${target}`).addClass("visible");
});
$(".trigger").on("mouseout", function() {
let target = $(this).data("target");
$(`#${target}`).removeClass("visible");
});
img.transition {
transition: opacity 0.25s;
-moz-transition: opacity 0.25s;
-webkit-transition: opacity 0.25s;
opacity: 0;
}
img.transition.visible {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<img class="transition" id="project1-img" src="https://picsum.photos/100">
<img class="transition" id="project2-img" src="https://picsum.photos/100">
<img class="transition" id="project3-img" src="https://picsum.photos/100">
</div>
<div>
<span class="trigger" data-target="project3-img">
111111111111
</span>
<span class="trigger" data-target="project2-img">
22222222222
</span >
<span class="trigger" data-target="project1-img">
33333333333
</span>
</div>
I have an Opacity transition affecting a div element but it does not seem to change the opacity of the child elements inside the div. My understanding is that the property of the containing div should apply to all child elements as well.
Any help would be greatly appreciated. Below is the HTML and CSS:
.tabtext {
opacity: 0;
transition: opacity 1s;
}
<div id="smartITtext" class="tabtext">
<h2 class="tabtext">Some Text</h2>
</div>
Below is the line in Javascript which changes the Opacity:
document.getElementById(smartITtext).style.opacity= 1;
When applying your javascript code it will add the opacity style on the element in your html. So it doesn't overwrite the css style.
Here is an example on how you could let it work.
document.getElementById("btn").addEventListener("click",function(){
var div = document.getElementById("smartITtext");
div.style.opacity = 0.5;
});
.tabtext {
transition: opacity 1s;
}
<div id="smartITtext" class="tabtext">
<h2 class="tabtext">Some Text</h2>
</div>
<input type="button" id="btn" value="change opacity" />
Your child element has a specific opacity set on it. Therefore, it won't inherit any changes you make to the parent and your transition won't run: you've told it to have opacity: 0;, so that's what it will have despite whatever you set the parent element's opacity to.
That's equivalent to setting the color of a child element to be blue and setting its parent's color to red: that child element will still have blue text as you've explicitly told it to.
You will need to change that specific element's opacity to run your transition. Judging by your code, something like:
document.getElementById(text).firstElementChild.style.opacity = 1;
or
document.querySelector('#' + text + ' .tabText').style.opacity = 1;
would do the trick for you.
Firstly your javascript refences an id that does not match your html.
Secondly the id reference ("text") needs to be in quotes.
Here is an alternative way to get the desired result.
document.getElementById("smartITtext").className += " Active";
.tabtext {
opacity: 0;
transition: opacity 1s;
}
.tabtext.Active{
opacity:1;
}
<div id="smartITtext" class="tabtext">
<h2 class="tabtext">Some Text</h2>
</div>
The property of the parent element should apply to the child element. UNLESS the child element has it's own property.
So if we have this code:
#container {
color: blue;
}
.one {
color: firebrick;
}
<div id="container">
<span class="one">hello </span>
<span class="two">World</span>
<span>. <-- hello should be red, while world and this text should be blue</span>
</div>
play in jsbin: https://jsbin.com/focimuk/edit?html,css,output
So for a solution, try setting just opacity on the parent element, and add a transition to it.
I have a this script :
function ani(){
document.getElementById('para').className ='exeInputapparition';
}
To apply a css animation on my element who has the ID para.
It's working but i wanted to know if it's possible to apply to all element who have the class para instead of the ID because i have more than one element where i need to apply my CSS animation.
Thanks in Advance for your help :)
The Css :
#keyframes inputapparition {
0%
{
opacity: 0;
}
100%
{
opacity: 1;
}
}
.exeInputapparition
{
animation-name: inputapparition;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
#para
{
margin: 0;
font-family: "Roboto"
font-size: 20px;
opacity: 0;
}
The function querySelectorAll returns all elements, it's a "DOM array", therefore there isn't the attribute className. You should loop the list and change one by one:
var allElementsPara = document.querySelectorAll(".para");
for (var i = allElementsPara.length - 1; i >= 0; i--) {
allElementsPara.item(i).classList.add("exeInputapparition");
};
You can use document.querySelectorAll
var x=document.querySelectorAll(".para");
for(var a =0;a<x.length;a++){
x[a].classList.add("exeInputapparition")
}
JSFIDDLE
JSFIDDLE WITH .para
The id is unique. You must use a same class for all element that you want to animate. For all element, put the class animate and edit the function
function ani(){
document.getElementsByClassName('animate').className ='exeInputapparition';
}
A more performing solution would be to apply the class to the body element.
Every access to the DOM takes some ms and when your web page becomes huge, with a lot of JavaScript, it can get slow.
Accessing a single DOM element (<body>) instead N elements with the given class will:
reduce the number of accesses to the DOM;
reduce to 0 the queries you perform on the DOM;
make sure all the elements starts appearing at the same time;
assure that every element with the class para added after the script has run, will have the correct style;
// here I use a `setTimeout` to make the function start automatically
// logically you can take the content of this function and put it
// wherever you prefer
setTimeout(function() {
document.body.className += ' in';
}, 1000);
.para {
opacity: 0;
transition: opacity 0.5s linear;
}
.in .para {
opacity: 1;
}
<div class="para">para 1</div>
<div class="para">para 2</div>
<div class="para">para 3</div>
You can disregard the previous answers, people did and could not know what exactly you want before you posted the css.
You do not the keyframes for this.
Here is a full JS solution, as you need JS for this anyway.
document.querySelector(".reveal3").addEventListener("click", function(){
toggle();
});
function toggle(){
var c = document.querySelector(".reveal3");
if(c.style.opacity == 1){
c.style.opacity = 0;
} else {
c.style.right = "0px";
c.style.opacity = 1;
}
}
See it in action here, the div on the right side, click on it to toggle visibility.
http://codepen.io/damianocel/pen/GopoJB
this solution will help your.it is easy to use jquery with this.I have implemented for a div.you can use it for image also.so try this
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
</head>
<body>
<div class="clickme" style="background-color:orange;width:100px;height:100px;">
<!--use <img src="imageurl"/> here-->
</div>
<!-- js-->
<script type="text/javascript">
$(document).ready(function(){
$(".clickme").click(function(){
$(this).animate({opacity:0.5},1000);
});
});
</script>
</body>
</html>
when I try to make a simple transition with pure CSS all works fine.
But when I try to call a javascript-function which modiefies the CSS when clicked on a link, there is no transition. I want to fade in a grey layer.
HTML:
<a href="someImage.jpg" id="test">
<img src="someImage.jpg" alt="" />
</a>
<section id="grey">
</section>
JS:
var grey = document.getElementById("grey");
var link = document.getElementById("test");
link.onclick = function () {
grey.style.display = "block";
grey.style.opacity = "1";
return false;
};
CSS:
section {
display:none;
size and position...
opacity: 0;
background-color: rgba(0,0,0,0.5);
transition: opacity 1s .5s;
}
(see http://jsfiddle.net/7zEhx/5/ )
I'm using FF22, does anyone know any solutions?
display: none elements don’t transition, and the display: block hasn’t kicked in before you set the other style. There are horrible hacks like this:
setTimeout(function() {
grey.style.opacity = "1";
}, 0);
But I’d just set width to 0 instead of setting display and then put it back at 100%.
Updated jsFiddle