Airpods Pro sayfasında tersine mühendislik yaparken , animasyonun a değil video, a kullandığını fark ediyoruz canvas. Uygulama aşağıdaki gibidir:
- HTTP2 üzerinden yaklaşık 1500 görüntü önyükleme yapın, aslında animasyon kareleri
- Şeklinde bir dizi resim oluşturun
HTMLImageElement
- Her
scrollDOM etkinliğine tepki verin ve en yakın resme karşılık gelen bir animasyon karesi isteyin.requestAnimationFrame
- Animasyon çerçeve talepleri geri arama olarak, kullanarak görüntüyü göstermek
ctx.drawImage( ctxolma 2dbağlamında canvaselemanı)
Bu requestAnimationFramefonksiyon, kareler ertelendiğinden ve hedef ekranın "saniye başına kare" hızıyla senkronize edileceğinden daha yumuşak bir efekt elde etmenize yardımcı olmalıdır.
Kaydırma etkinliğinde bir karenin düzgün görüntülenmesi hakkında daha fazla bilgi için şunu okuyabilirsiniz: https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event
Bununla birlikte, ana sorununuzla ilgili olarak aşağıdakilerden oluşan bir çalışma çözümüm var:
- Öğeyle aynı yükseklik ve genişlikte bir yer tutucu oluşturma
video. Amacı, videonun absolutekonum olarak ayarlandığında geri kalan HTML ile çakışmasını önlemek
- İçine
scrollVideonun konumunu ayarlamak tutucu görünümün üst ulaşır olay geri çağırma, absoluteve sağ topdeğeri
Fikir, videonun her zaman akıştan uzak kalması ve alta doğru kaydırırken yer tutucunun üzerinde doğru anda gerçekleşmesidir.
İşte JavaScript:
//Get video element
let video = $("#video-effect-wrapper video").get(0);
video.pause();
let topOffset;
$(window).resize(onResize);
function computeVideoSizeAndPosition() {
const { width, height } = video.getBoundingClientRect();
const videoPlaceholder = $("#video-placeholder");
videoPlaceholder.css("width", width);
videoPlaceholder.css("height", height);
topOffset = videoPlaceholder.position().top;
}
function updateVideoPosition() {
if ($(window).scrollTop() >= topOffset) {
$(video).css("position", "absolute");
$(video).css("left", "0px");
$(video).css("top", topOffset);
} else {
$(video).css("position", "fixed");
$(video).css("left", "0px");
$(video).css("top", "0px");
}
}
function onResize() {
computeVideoSizeAndPosition();
updateVideoPosition();
}
onResize();
//Initialize video effect wrapper
$(document).ready(function () {
//If .first text-element is set, place it in bottom of
//text-display
if ($("#video-effect-wrapper .text.first").length) {
//Get text-display position properties
let textDisplay = $("#video-effect-wrapper #text-display");
let textDisplayPosition = textDisplay.offset().top;
let textDisplayHeight = textDisplay.height();
let textDisplayBottom = textDisplayPosition + textDisplayHeight;
//Get .text.first positions
let firstText = $("#video-effect-wrapper .text.first");
let firstTextHeight = firstText.height();
let startPositionOfFirstText = textDisplayBottom - firstTextHeight + 50;
//Set start position of .text.first
firstText.css("margin-top", startPositionOfFirstText);
}
});
//Code to launch video-effect when user scrolls
$(document).scroll(function () {
//Calculate amount of pixels there is scrolled in the video-effect-wrapper
let n = $(window).scrollTop() - $("#video-effect-wrapper").offset().top + 408;
n = n < 0 ? 0 : n;
//If .text.first is set, we need to calculate one less text-box
let x = $("#video-effect-wrapper .text.first").length == 0 ? 0 : 1;
//Calculate how many percent of the video-effect-wrapper is currenlty scrolled
let percentage = n / ($(".text").eq(1).outerHeight(true) * ($("#video-effect-wrapper .text").length - x)) * 100;
//console.log(percentage);
//console.log(percentage);
//Get duration of video
let duration = video.duration;
//Calculate to which second in video we need to go
let skipTo = duration / 100 * percentage;
//console.log(skipTo);
//Skip to specified second
video.currentTime = skipTo;
//Only allow text-elements to be visible inside text-display
let textDisplay = $("#video-effect-wrapper #text-display");
let textDisplayHeight = textDisplay.height();
let textDisplayTop = textDisplay.offset().top;
let textDisplayBottom = textDisplayTop + textDisplayHeight;
$("#video-effect-wrapper .text").each(function (i) {
let text = $(this);
if (text.offset().top < textDisplayBottom && text.offset().top > textDisplayTop) {
let textProgressPoint = textDisplayTop + (textDisplayHeight / 2);
let textScrollProgressInPx = Math.abs(text.offset().top - textProgressPoint - textDisplayHeight / 2);
textScrollProgressInPx = textScrollProgressInPx <= 0 ? 0 : textScrollProgressInPx;
let textScrollProgressInPerc = textScrollProgressInPx / (textDisplayHeight / 2) * 100;
//console.log(textScrollProgressInPerc);
if (text.hasClass("first"))
textScrollProgressInPerc = 100;
text.css("opacity", textScrollProgressInPerc / 100);
} else {
text.css("transition", "0.5s ease");
text.css("opacity", "0");
}
});
updateVideoPosition();
});
İşte HTML:
<div id="video-effect-wrapper">
<video muted autoplay>
<source src="https://ndvibes.com/test/video/video.mp4" type="video/mp4" id="video">
</video>
<div id="text-display"/>
<div class="text first">
Scroll down to test this little demo
</div>
<div class="text">
Still a lot to improve
</div>
<div class="text">
So please help me
</div>
<div class="text">
Thanks! :D
</div>
</div>
<div id="video-placeholder">
</div>
<div id="other-parts-of-website">
<p>
Normal scroll behaviour wanted.
</p>
<p>
Normal scroll behaviour wanted.
</p>
<p>
Normal scroll behaviour wanted.
</p>
<p>
Normal scroll behaviour wanted.
</p>
<p>
Normal scroll behaviour wanted.
</p>
<p>
Normal scroll behaviour wanted.
</p>
</div>
Burada deneyebilirsiniz: https://jsfiddle.net/crkj1m0v/3/