滚动淡入元素后保持显示的JavaScript问题及代码优化咨询
Hey there! I see you're diving into scroll-triggered animations with JavaScript—great start! Let's tackle that frustrating fade-out problem first, then go over some ways to polish your code for better performance and readability.
Why the Fade-Out Happens
Right now, your detection() function removes the in-view class whenever an element scrolls out of the viewport. That's exactly why your elements fade back out once you scroll past them. We need to make sure elements stay visible after their first fade-in, no matter where they are on the page.
Solution: Persist the Visible State
We can add a simple flag (using a data attribute) to mark elements that have already completed their animation. Once an element is marked as "animated", we won't touch its classes anymore.
Here's the updated JavaScript code:
$(function() { var html = $('html'); // Cache jQuery objects upfront to avoid repeated DOM queries var $items = $('*[data-animate-in], *[data-detect-viewport]'); var waiting = false; var $w = $(window); // On Screen Check - keep this handy utility function $.fn.isOnScreen = function() { var elementTop = this.offset().top, elementBottom = elementTop + this.outerHeight(), viewportTop = $w.scrollTop(), viewportBottom = viewportTop + $w.height(); return elementBottom > viewportTop && elementTop < viewportBottom; }; function detection() { $items.each(function() { var $el = $(this); // Skip elements that have already finished animating if ($el.data('animated')) return; if ($el.isOnScreen()) { $el.addClass("in-view").data('animated', true); // Mark as permanently animated } // Remove the else branch that was removing the in-view class }); } // Debounced scroll/resize handler to avoid excessive function calls $w.on("resize scroll", function() { if (waiting) return; waiting = true; detection(); setTimeout(function() { waiting = false; }, 100); }); // Initialize animations on page load $(document).ready(function() { setTimeout(function() { detection(); }, 500); $items.each(function() { var $el = $(this); // Use jQuery's data() method for cleaner, type-safe attribute access var delay = $el.data('animate-in-delay') || 0; var delayInSeconds = delay / 1000 + "s"; $el.css("transition-delay", delayInSeconds); }); }); });
Key Changes:
- Cached jQuery Objects: Converted
itemsto$items(a jQuery collection) upfront, so we don't re-wrap elements in jQuery every time we loop through them (saves DOM query time!). - Animation Flag: Added
data('animated')to mark elements that have finished their fade-in. Thedetection()function skips these elements entirely now. - Removed Unnecessary Logic: Got rid of the
elseclause that was removing thein-viewclass—no more unwanted fade-outs! - Cleaner Data Access: Used
$el.data('animate-in-delay')instead ofgetAttribute()for simpler, more readable code that automatically handles type conversion.
CSS Optimization Tips
Your CSS works, but we can make it more concise and avoid redundant transitions:
/* -- Animation -- */ [data-animate-in] { opacity: 0; transition: transform 0.8s ease, opacity 0.8s ease; } [data-animate-in="up"] { transform: translate3d(0, 24px, 0); } [data-animate-in="left"] { transform: translate3d(-25%, 0, 0); } [data-animate-in="right"] { transform: translate3d(25%, 0, 0); } [data-animate-in="down"] { transform: translate3d(0, -24px, 0); } [data-animate-in="fadeIn"] { transform: translate3d(0, 0, 0); } /* Simplify the in-view state - inherit transition timing if needed */ [data-animate-in].in-view { opacity: 1; transform: translate3d(0, 0, 0); -webkit-transform: translate3d(0, 0, 0); /* Optional: Adjust transition timing here, or remove to use the base timing */ transition: transform 0.6s ease, opacity 0.6s ease; } .fade-in { opacity: 0; transition: opacity 1s ease; } .page-loaded .fade-in, .page-loaded.fade-in { opacity: 1; }
CSS Improvements:
- Grouped related selectors (like the
.page-loadedrules) for better readability - Kept transition properties consistent to avoid unexpected animation behavior
- Made the structure cleaner by separating base styles from animation states
Additional Optimization Ideas
- Reusable Debounce Function: Instead of rolling your own debounce with
waitingandsetTimeout, you could use a reusable debounce utility to clean up the scroll/resize handler even more. - RequestAnimationFrame: Wrap the
detection()call inrequestAnimationFrameto ensure animations run smoothly with the browser's repaint cycle. - CSS Custom Properties: If possible, use CSS variables for delay values instead of setting them via JavaScript—this keeps styling in CSS where it belongs.
Hope this helps you fix the issue and learn a bit more about efficient JavaScript/CSS for animations! 😊
内容的提问来源于stack exchange,提问作者Louie Heaton

