Ask coding questions

← Back to all posts
CSS Transition
Smart0ne (17)

Okay, so I'm back with a simpler problem on CSS Transitions. How do I trigger an animation when the element is completely in view?

Commentshotnewtop
xxpertHacker (388)

You'll need JavaScript; CSS isn't allowed this much power.
When it's in view, add a CSS class, data attribute, or something that will let your CSS target it, then when it's no longer in view, remove it.

https://repl.it/talk/ask/How-to-determine-when-a-DOMElement-has-finally-come-into-view/53956

Specifically, you'll need an "Intersection Observer" and to target it when there is an "intersection ratio" of 1.0.

As you want the whole thing in view; 100% => 1.00.

Something along the lines of:

const target = document.querySelector(...yourElement...);

new IntersectionObserver(
	() => {
		target.classList.add(...yourClass...);
		// probably add some "if" statements to determine when to remove the class too
	}, {
		threshold: 1.0
	}
).observe(target);

Where your element is styled based on the class / attribute or selector of your choice.

fuzzyastrocat (646)

@xxpertHacker Best answer here. Good to see someone who actually explains their answer rather than just linking to websites.

xxpertHacker (388)

@fuzzyastrocat I'd presume that anyone who knows their stuff and understands someone else's problem could explain how to solve it.

I just wish people would do this if I ask any questions.
*cough https://repl.it/talk/ask/JavaScript-FinalizationRegistry-not-working-right/54745

fuzzyastrocat (646)

@xxpertHacker Agreed! (And yet people mark bad answers as correct because they don't know better... reeee)

I'll try to look into it, maybe I can find a solution and not give you some random advice about HTML that isn't the problem :D.

Smart0ne (17)

@xxpertHacker I'm so sorry, but I'm super noob at Javascript. So I guess I gotta know more Javascript to understand this.. :(

xxpertHacker (388)

@Smart0ne You'll need to know even more JavaScript to understand all of what Coder100 gave you there, what he linked was pure nonsense. Just check out the Repl talk link and the MDN article that I had mentioned there in the comments. MDN is often really good at explaining stuff in detail.

(Btw: try out keyframes)

fuzzyastrocat (646)

@xxpertHacker Oof, I get the following errors when I go to your site:

Module scripts in XML documents are currently not supported. See crbug.com/717643
Uncaught ReferenceError: FinalizationRegistry is not defined

So I guess my version of Chrome doesn't support it... sorry that I can't help :P

xxpertHacker (388)

@fuzzyastrocat Yeah it's an old error message they never removed, I opened chromium bug reports about it, it should execute the script, yet still show the error.

Notice how the next error still occurs.

And yeah, this is bleeding edge stuff, so many people don't have FinalizationRegistry yet. Thank you for actually attempting to look into it nonetheless.

Smart0ne (17)

@xxpertHacker Oh I feel so inferior to you guys.

fuzzyastrocat (646)

@Smart0ne I can try to walk you through the code given.

Let's start here:

const target = document.querySelector(...yourElement...);

This finds your element in the HTML document. So if you did something like this:

<body>
  <div id="watch-me"></div>
</body>

Then you'd say const target = document.querySelector("#watch-me");. The # tells JS (well, CSS really) to look for an element with an id of watch-me. So, it will find your div.

Next, let's look at the rest:

new IntersectionObserver(
    () => {
    	target.classList.add(...yourClass...);
    	// probably add some "if" statements to determine when to remove the class too
	}, {
		threshold: 1.0
	}
)

This creates an "intersection observer" with a threshold of 1.0. As @xxpertHacker explained, this will be what checks if your element is onscreen. The () => { ... } is a lambda function — it's basically a little function that gets run once the element is on the screen. Inside the function, we will do something like target.classList.add("onscreen");. This will transform your element from something like

<div id="watch-me"></div>

to

<div id="watch-me" class="onscreen"></div>

So now, you just have to update the CSS of your HTML so that anything with the class "onscreen" triggers the animation:

#watch-me {
  some-animated-property: 0.1; /* Whatever the thing you want to animate is, set to its "default" (offscreen) value */

  transition: some-animated-property 1s;  /* How long the transition takes.  Note that if you have multiple properties, do something like "transition: prop1 1s, prop2 2s;"  */
}

.onscreen {
  some-animated-property: 1.0; /* The "onscreen" value */
}

Finally, .observe(target); tells the IntersectionObserver to watch your element specifically. Without it, the observer would watch nothing.

If you have more questions, feel free to ask. Note that, if you want the class to be removed at some point, you'll need to add some extra logic like the comment in the code says.

Smart0ne (17)

@fuzzyastrocat Wait, in .observe(target), what do I replace target? The id or what?

fuzzyastrocat (646)

@Smart0ne No, don't replace anything. Remember, we defined const target = ... to be the element you want to watch. target is a variable.

Smart0ne (17)

@fuzzyastrocat TypeError: Failed to execute 'observe' on 'IntersectionObserver': parameter 1 is not of type 'Element'.
at /script.js:11:3

Also, does the variable name have to be "target"? I defined the variable name to be Test_3 at the top and I used Test_3 as the parameter.

fuzzyastrocat (646)

@Smart0ne On the line after const target = ... ;, write console.log(target). What does the console say when you run your site?

I'm assuming you're relatively new to programming in general. A variable can be named whatever you want to — that's why people made the idea of variables, it's an arbitrary name for some value. That way, you can name a value something you will remember and it will make sense to you. So yes, naming it Test_3 is fine, as long as you put Test_3 everywhere where I said "target".

fuzzyastrocat (646)

@Smart0ne Okay, that means it can't find your element. Two things:

  • What is your HTML? I'd like to see it so that I can know what we're working with here.
  • What did you put in for const target = document.querySelector( ... );?
Smart0ne (17)

@fuzzyastrocat HTML:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Test</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <script src="script.js"></script>
    <div id="Test_1">
      <h1>Test 1</h1>
      <p>Test 1</p>
    </div>
    <div id="Test_2">
      <h1>Test 2</h1>
      <p>Test 2</p>
    </div>
    <div id="Test_3">
      <h1>Test 3</h1>
      <p>Test 3</p>
    </div>
  </body>
</html>

I did

const target = document.querySelector("#Test_3");

in Javascript.

fuzzyastrocat (646)

@Smart0ne Hmm, ok. Let's try a different method: change the const target (or const Test_3?) line to const target = document.getElementById("Test_3");

Also, a note about repl posts: Use three backticks to make code, ie:

```

your_code_goes_here

```

Smart0ne (17)

@fuzzyastrocat Well, now it just freezes, and it doesn't log target into the console. I invited you to check the repl out.

xxpertHacker (388)

@Smart0ne Make sure the script is deferred or a module.

<script type="module" ...>

This makes sure that the script is only run after all elements have been generated. Right now it's run right away, meaning the elements don't exist by the time that the #Test_3 has been parsed and created.

Smart0ne (17)

@xxpertHacker Haha, yup, I made that mistake.

Smart0ne (17)

@Coder100 .. is it a language? They said that's the code in Vanilla or something like that. (Or is that just Javascript)

Coder100 (8396)

vanilla js is literally js without libraries smh @Smart0ne

Coder100 (8396)

thats why I said nothing lol @Smart0ne

Coder100 (8396)

now you know :)
did it work? @Smart0ne

Smart0ne (17)

@Coder100 I think the code works, but I'm currently trying to add the opacity styling.

Coder100 (8396)

something like:

[element] { animation: fadein 0.2s; }
@keyframes fadein { from { opacity: 0; } }

@Smart0ne

xxpertHacker (388)

@Coder100 Ooh, always gotta show off questions asked over a decade ago and the ancient tech used to answer it.

Coder100 (8396)

arggh didn't you ask this already? Did it not help?

Smart0ne (17)

@Coder100 :D Yup I know, but I couldn't really find it. (im sorry if i missed it) Also, this question is at least more clear than the other one. The only triggers I know are :hover, :focus (which I don't know how to use), :active, but none of them seem to achieve what I want.

Coder100 (8396)

@Smart0ne yeah, you need JS for this
also :focus is what happens when im typing like this

Basically it's what happens after you click on something

Smart0ne (17)

@Coder100 Grammayee, I see! Nvm, okay.