1

I want to transition this h1 when we click on the button, the html for the h1 is added using js, so it is dynamic, I can't specify the opacity 0 and other before the button click, what is the way to do this?

const wow = document.getElementById('wow');
const test = document.querySelector('.test');

wow.addEventListener('click', () => {
    test.innerHTML = `
  <h1 class="title">
        Hello Test
    </h1>
  `;
})
.title {
  opacity: 1;
  transform: translateY(0);
  transition: transform 1s cubic-bezier(.165,.84,.44,1) .1s,opacity 1s cubic-bezier(.165,.84,.44,1) .2s;
}
<div class="test"></div>

<button id="wow">
  Click
</button>
Joel Smith
  • 63
  • 1
  • 13
  • you'll want to maybe add a class after adding the innerHTML, and do your transition that way – Bravo May 05 '22 at 08:36
  • Covered by "[How can I get CSS transitions to run on a newly created HTML element by adding a class?](/q/41937640/90527)", though this question is a few steps before. – outis Aug 10 '22 at 21:13

4 Answers4

2

Add a class to the parent, then create CSS which reveals the child when the parent has the class you created ... e.g. reveal in this case

The setTimeout is needed so that the initial content is added to the DOM pre-transitioned, so that it transitions

const wow = document.getElementById('wow');
const test = document.querySelector('.test');

wow.addEventListener('click', () => {
  test.innerHTML = `<h1 class="title">Hello Test</h1>`;
  setTimeout(() => test.classList.add('reveal'), 0);
})
.title {
  opacity: 0;
  transform: translateY(100vh);
  transition: transform 1s cubic-bezier(.165, .84, .44, 1) .1s, opacity 1s cubic-bezier(.165, .84, .44, 1) .2s;
}

.reveal .title {
  opacity: 1;
  transform: translateY(0);
}
<div class="test"></div>

<button id="wow">
  Click
</button>

I was going to use requestAnimationFrame instead of setTimeout ... but, oddly, that didn't work (has me a little perplexed) ... had to do

requestAnimationFrame(() => requestAnimationFrame() => test.classList.add('reveal')));

I know why that definitely works, I just don't understand why a single RAF doesn't - at least in firefox, probably works fine in those other browsers)

maybe setTimeout always triggers after at least one render cycle, but requestAnimationFrame does not?

Bravo
  • 6,022
  • 1
  • 10
  • 15
  • But as you can see, it initially taken up the space even it is not there, and after that it transform according to the class, I want to do transition once it is clicked button – Joel Smith May 05 '22 at 08:59
  • `it initially taken up the space even it is not there` no it doesn't - did you want it to? – Bravo May 05 '22 at 09:04
  • RE: 2 RAF calls: MDN's page for [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) states: "[it] will request that your animation function be called before the browser performs the next repaint." (Other parts of the page say something similar.) A single call will complete before the next repaint, which is likely the same frame that the newly created element is displayed. The double-call ensures there's at least one repaint in between, so changes resulting from the new class will be displayed starting with the 2nd frame. – outis Aug 10 '22 at 21:11
0

You can put this element in HTML first, but set its opacity to 0, and then animate it by switching CLASS

titleNotShow ==> show

<div class="test">
  <h1 class="titleNotShow">
    Hello Test
  </h1>
   </div>

<button id="wow">
  Click
</button>

const wow = document.getElementById('wow');
const test = document.querySelector('.test');

wow.addEventListener('click', () => {
    test.className = 'show'
})

.titleNotShow {
  opacity: 0;
  transform: translateY(0);
}

.show{
opacity: 1;
  transform: translateY(0);
  transition: transform 1s cubic-bezier(.165,.84,.44,1) .1s,opacity 1s cubic-bezier(.165,.84,.44,1) .2s;
}
ConstFiv
  • 67
  • 6
0

After adding the innerHTML, you can use setTimeout to transform the h1, after a delay of 1 millisecond. You can select the element using querySelector.

const wow = document.getElementById('wow');
const test = document.querySelector('.test');

wow.addEventListener('click', () => {
  test.innerHTML = `<h1 class="title">Hello Test</h1>`;
  setTimeout(() => test.querySelector(".title").style.transform = "translateY(100px)", 1)
})
.title {
  opacity: 1;
  transform: translateY(0);
  transition: transform 1s cubic-bezier(.165, .84, .44, 1) .1s, opacity 1s cubic-bezier(.165, .84, .44, 1) .2s;
}
<div class="test"></div>

<button id="wow">
  Click
</button>
TechySharnav
  • 4,869
  • 2
  • 11
  • 29
0

I would look into jQuery's fadeTo() or animate() functions https://api.jquery.com/fadein/, https://api.jquery.com/animate/

In the example I've put a 1000 duration, you may want to reduce it. You may also want to hide the button, or use the toggle() function to alternate between hide/show https://api.jquery.com/toggle/

$( "#wow" ).click(function() {
  $( ".test" ).animate({
    opacity: 1,
    height: 'show',
    marginTop: 'show',
    marginBottom: 'show',
    paddingTop: 'show',
    paddingBottom: 'show'
  },  
  1000)
});
.test { opacity: 0; display:none}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<h1 class="test">Hello test!</h1>

<button id="wow">
  Click
</button>
 
andrea m.
  • 668
  • 7
  • 15