I've been scouring the internet and StackOverflow for quite some time to find a solution to my problem but nothing is working. So figured I'd just make my own post to throw into the ring of questions about triggering animations when scrolling in viewport. I have read CSS3-Animate elements if visible in viewport (Page Scroll) and I've tried adapting every single solution on that answer and it does not fix the issue. My question uses webkit and the solutions in that question similar to mine do not work even if adapted to my code.
I'm trying to highlight some text using a webkit animation. The HTML/CSS works well! I'm just trying to get it to trigger when the text enters the viewport rather than when the page loads. Preferably using only JavaScript since I want the page to load very quickly.
HTML
I don't have any JS to include because I've tried a ton of solutions and it's just not working for the formatting of the code with webkit animation. I'm very new to JS so any help is appreciated.
<h1>
<ol>
<li>Highlight <mark>this text</mark> upon scrolling.</li>
</ol>
</h1>
CSS
mark {
-webkit-animation: 1s highlight 1s 1 normal forwards;
animation: 1s highlight 1s 1 normal forwards;
background-color: none;
background: linear-gradient(90deg, #C7A4D8 50%, rgba(255, 255, 255, 0) 50%);
background-size: 200% 100%;
background-position: 100% 0;
}
#-webkit-keyframes highlight {
to {
background-position: 0 0;
}
}
#keyframes highlight {
to {
background-position: 0 0;
}
}
Thanks for your help.
You can do as follows.
CSS
In the css file add 2 classes. One called "hidden" and the other one called "show". The hidden class will be the default class, which is how the element is positioned when it's not in the viewport. The show class will be used for the trasition when the element will enter the viewport.
In my case, when the element is not in the viewport, it's not visible (opacity: 0), it's positioned on the right with some blur.
.hidden {
opacity: 0;
filter: blur(5px);
transform: translateX(50%);
transition: all 1s;
}
.show {
opacity: 1;
filter: blur(0);
transform: translateX(0);
}
HTML
In the HTML code you will need to add the hidden class to any element you want to keep hidden when out of the viewport.
<!DOCTYPE html>
<html lang="en">
<body>
<h1 class="hidden">My title</h1>
</body>
</html>
JavaScript
In the JavaScript file you will need to add the following code. This code will monitor each element with the "hidden" class and when any of these enter the viewport the "show" class will be added to it. The "show" class will then be removed when it exits the viewport (if you don't want that to happen, and therefore want to play the animation only once remove the else block).
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
console.log(entry)
if (entry.isIntersecting) {
entry.target.classList.add('show');
} else {
entry.target.classList.remove('show')
}
})
})
const hiddenElements = document.querySelectorAll('.hidden');
hiddenElements.forEach((element) => observer.observe(element));
Related
I have set up some scroll animations on many elements of a site I'm building.
I'm using these CSS rules:
.hiddenLeft {
opacity: 0;
filter: blur(5px);
transform: translateX(-090%);
transition: all 1s;
}
.hiddenRight {
opacity: 0;
filter: blur(5px);
transform: translateX(90%);
transition: all 1s;
}
.show {
opacity: 1;
filter: blur(0);
transform: translateX(0);
}
The hiddenLeft and hiddenRight classes are in the elements by default, and then when they are intersected during vertical scroll the show classes are added.
It all works fine, except it has created horizontal scroll to the right out of the width of the site into blank space.
I would like to keep the animations as they are but without the horizontal scroll.
A picture of me scrolling out to the side into the blank space for reference:
enter image description here
I made a very basic replication here:
https://codepen.io/acodeaday/pen/NWMYWNL
I can see that the offending line is
transform: translateX(90%);
But that makes the animation very aesthetically pleasing. So I'm hoping there is a way to solve it while keeping that.
Try using
max-width: 100%!important; height: auto; overflow: hidden!important;
this code whatever you put all of your animation inside. That can be a div. Hope this help~
I'm trying to build a post with comments using React, CSS, and Firebase.
I have this post with 10 comments. Now I want to build animation to scroll up the comments, instead of showing all the 10 comments.
First part is my React JS code.
<div className="scroll-up">
{
comments.map((comment) => (
<p>
{comment.text}
</p>
))
}
</div>
The second part is my CSS code:
.scroll-up {
max-height: 100px;
overflow: hidden;
position: relative;
}
.scroll-up p {
position: relative;
width: 100%;
height: 100%;
margin: 0;
transform:translateY(100%);
animation: scroll-up 3s linear infinite;
}
#keyframes scroll-up {
0% {
transform: translateY(100%);
}
100% {
transform: translateY(-100%);
}
}
The animation works fine if there is only one comment. The comment will scroll up for 3 seconds and repeat. The problem is: if there is more than 1 comment, ALL comments will show up together, on top of each other, and scroll up for 3 seconds.
My question is, how do I let the comments scroll up one by one?
Edit: I took the advice from algo_user, change .scroll-up p position to relative. But now it's showing all comments, scroll up for 3 seconds and repeat. For all 10 comments, 3 seconds only showed the first 4 or 5. My new question is, some post may have 1 comment, some may have 10 comments, how do I scroll them at the same speed, for all comments?
According to w3 School :
position: absolute; -> The element is positioned relative to its first positioned (not static) ancestor element
So, If you change the position property of ".scroll-up p" to initial/relative or even just remove it, then that should work.
You can read more about this property here: https://www.w3schools.com/cssref/pr_class_position.asp
I have two elements, and the top one's visibility is controlled by a v-if on a simple boolean.
transition(name="fade")
#element1(v-if="showFirst")
p Foo
#element2
p Bar
The first element is wrapped in a <transition> tag, exactly as per the Vue documentation.
However, while this does create a fading animation, the rest of the content on the page still jumps very jarringly.
How can I create a transition that will also smoothly transform the position of any and all siblings that follow?
A fiddle demoing this issue.
You need to use a transition-group and key your dynamic div and static div
<transition-group name="fade">
<div v-if="switc" key="dynamic" class="animated">
...
</div>
<div key="main-content" class="animated">
...
</div>
</transition-group>
And use this css classes
.fade-enter,
.fade-leave-active {
opacity: 0;
transform: translateY(-10px);
}
.fade-leave-active {
position: absolute;
}
.animated {
transition: all 0.5s;
/*display: flex;*/
width: 100%;
}
The real trick is to change position to absolute when leaving, then any other content can take correct position.
To know more about how Vue animate things please see this FLIP explanation post
And please see this working fiddle
https://jsfiddle.net/bjfhth7c/4/
Edit
By mistake I did set display: flex; in .animated class, that was causing to every inner element to render in a strange way.
So now, I completely remove .animate class, and instead apply transition: all 0.5s and width:100% to every direct inner element of .wrapper
My final scss looks like this:
.wrapper {
display: flex;
flex-direction: column;
>* {
transition: all 0.5s;
width:100%;
};
}
.fade-enter,
.fade-leave-active {
opacity: 0;
transform: translateY(-10px);
}
.fade-leave-active {
position: absolute;
}
Flex layout is a extend subject, but in short for this particular case flex-direction: column is arranging elements one bellows previous one.
If one of those elements has absolute position will be ignored in flex layout so any other elements will be redistributed on available space.
Please see this guide about flexbox and last working fiddle hope it helps.
You can use a slideDown/slideUp animation instead. For achieve this you don't need to know a height of a sliding element, the principles of max-height transition explained there.
So, as a result it will cause animated moving of elements below target.
Check out my example based on your fiddle.
vue js provides different transition classes, you have to use those properly to smooth the transition, I have tried with your example in this fiddle with some CSS, have a look.
.fade-enter-active, .fade-leave-active {
transition: all .5s;
height: 100px;
opacity: 0.5;
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
height: 0px;
opacity: 0;
}
Some details from documentation:
There are six classes applied for enter/leave transitions.
v-enter: Starting state for enter. Added before element is inserted, removed one frame after element is inserted.
v-enter-active: Active state for enter. Applied during the entire entering phase. Added before element is inserted, removed when transition/animation finishes. This class can be used to define the duration, delay and easing curve for the entering transition.
v-enter-to: Only available in versions >=2.1.8. Ending state for enter. Added one frame after element is inserted (at the same time v-enter is removed), removed when transition/animation finishes.
v-leave: Starting state for leave. Added immediately when a leaving transition is triggered, removed after one frame.
v-leave-active: Active state for leave. Applied during the entire leaving phase. Added immediately when leave transition is triggered, removed when the transition/animation finishes. This class can be used to define the duration, delay and easing curve for the leaving transition.
v-leave-to: Only available in versions >=2.1.8. Ending state for leave. Added one frame after a leaving transition is triggered (at the same time 7. v-leave is removed), removed when the transition/animation finishes.
You can as well use CSS animations where you can provide on different phases of transition what will be your css property to make your transitions more smooth, like following and demo fiddle:
.fade-enter-active {
animation: bounce-in .5s;
}
.fade-leave-active {
animation: bounce-out .5s;
}
#keyframes bounce-in {
0% {
height: 5px;
}
30% {
height: 30px;
}
50% {
height: 50px;
}
100% {
height: 100px;
}
}
#keyframes bounce-out {
0% {
height: 90px;
}
50% {
height: 50px;
}
100% {
height: 0px;
}
}
I am not familiar with css or javascript and I am wondering how to have a notification highlight similar to the case when a person commented on a Facebook post, and upon clicking, you will be directed to the said comment with temporary highlight.
Thanks in advance
You can use the CSS3 animation property. Just make sure to add the -webkit- vendor prefix for it to work in all major browsers. The vendor prefixes you need for other CSS3 properties can be found at caniuse.com.
The trick is to add a special class to the element you want highlighted, and applying the animation to that class with CSS.
Try it:
.post{
padding: 1em;
margin: .2em;
background: #ffffff;
border: 1px solid #eceded;
}
.post.highlighted {
-webkit-animation: highlight 6s ease;
animation: highlight 6s ease;
}
#-webkit-keyframes highlight {
from { background: #ddddff }
to { background: #ffffff }
}
#keyframes highlight {
from { background: #ddddff }
to { background: #ffffff }
}
<p class="post">This is just a regular post</p>
<p class="post highlighted">But this one's new!</p>
It looks like you have a few problems you need to solve. I'll walk you through the logic behind each problem. Some of these problems already have solutions posted online, so in those cases I've linked you to the appropriate pages.
1) Respond to a click on an element
http://clubmate.fi/detect-click-with-pure-javascript/
2) Scroll to a specific part of the page
Smooth scroll to specific div on click
3) Highlight an element
This involves changing attributes of an html element, for example the background color. This can be done by changing the class with javascript, and using css to style the element differently when it has the right class
CSS:
.element {
background-color: #0000ff; /* A blue background by default */
}
.element.highlighted {
background-color: #ff0000; /* A red background when the element is highlighted */
}
JS:
document.getElementsByClassname('element')[0].setAttribute('class', 'element highlighted');
Now you just have to run that line of javascript at the appropriate time (after the scrolling has ended - step 2 should give insight on how to do this)
4) Remove the highlighting after a delay
Take advantage of javascript's setTimeout function to remove the highlight class after a delay:
JS:
setTimeout(function() {
document.getElementsByClassname('element')[0].setAttribute('class', 'element'); // Replace "element highlighted" with just "element"
}, 1000); // 1000 means a one-second delay
I got completely stuck on this. I have a container with background image. Inside the container are 3 little circles. What I am trying to do is to zoom the background image when I hover over it and dim the background image when I hover over any of the 3 little circles.
I got to the point where the 3 circles are properly overlapping the container and the background zooms in on hover. But I have 2 issues
no. 1 I am not very fond of the way I am achieving the overlay of the circles, which is this code
#circle_wrap{
position: absolute;
margin-top: -130px;
}
no. 2 Is that I have no clue how to dim the background. My original intention was to have a hidden black conteniner with 0.5 opacity that would be displayed when I hover over one of the circles. But I couldn't figure out how to select the overlay.
JSFIDDLE here
If anything couldn't be solved with css only, I'd accept jquery solution as well.
I'm looking for any advice/tips/solutions you guys have, I really need to get this working.
Thank you.
Finally got so angry I am not able to do it with css that I made it with jquery :(
If anyone is interested here is the result
I have at least fixed the issue no1 with better css but the second is done with jquery.
solved no.1 with
.circle_wrap{
position: absolute; bottom: 0; width: 100%; height: 100px;
}
and applying position:relative on its parent
and the solution for no.2 is
$(".circle_wrap").hover(function () {
$(this).siblings("img").css("opacity", "0.2");
},
function () {
$(this).siblings("img").css("opacity", "1");
});
EDIT: safari support
.wrap img:hover{
-moz-transition: scale(1.1) rotate(0deg);
transform: scale(1.1) rotate(0deg);
-webkit-animation-name: scaleThis;
-webkit-animation-duration:5s;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function:ease-in-out;
}
#-webkit-keyframes scaleThis {
0% { -webkit-transform:scale(1) rotate(0deg); }
10% { -webkit-transform:scale(1.1) rotate(0deg); }
100% {-webkit-transform:scale(1.1) rotate(0deg); }
}