2017-02-15 78 views
0

我有一個圖像列表並想上下移動圖像緩慢上/下滾動向下/向上。有效的「視差效果」垂直IMG列表滾動

圖像本身由「object-fit:cover;」設置和「對象位置:中心50%;」,所以我有空間將圖像向下移動到「對象位置:中心100%」的最大值。同時滾動。而相反,將圖像移動到「object-position:center 0;」的最小值同時向下滾動。

簡稱:當用戶滾動圖像下的列表中,然後每個圖像應該慢慢表現出更多的來自其隱藏的頂部,反之亦然。

我找到WhatsApp的客戶端(IOS)在這個漂亮的parralax效果。當用戶向下滾動時,媒體內容滾動一點點,反之亦然。我想要達到完全一樣的。

所以我做了下面的代碼 - 它的工作原理,但性能差,我尋找一個更好的解決方案。有沒有人知道這個問題的更好的解決方案?也許通過使用「純粹的css parralax」(http://keithclark.co.uk/articles/pure-css-parallax-websites/)。這將是最好的解決方案 - 但是,我不能採用這種技術來解決我的問題。

您可以將其複製/粘貼到新的index.html,它將按原樣運行。

以下是完整的工作代碼(性能差):

(function() { 
 
    \t document.addEventListener('DOMContentLoaded', function() { 
 
    
 
    \t \t /** returns true, if node is in viewport. 
 
    \t \t */ 
 
function node_is_in_viewport(element) { 
 
    
 
    \t \t \t var rect = element.getBoundingClientRect(); 
 
    \t \t \t var html = document.documentElement; 
 
    \t \t \t 
 
    \t \t \t return (
 
    \t \t \t  rect.top >= 0 && 
 
    \t \t \t  rect.left >= 0 && 
 
    \t \t \t  rect.bottom <= (window.innerHeight || html.clientHeight) && 
 
    \t \t \t  rect.right <= (window.innerWidth || html.clientWidth) 
 
    \t \t \t ); 
 
    \t \t } 
 
    
 
    \t \t /** returns "y-value" of css-property "object-position" 
 
    \t \t */ 
 
    \t \t function getObjectPosY(translateString){ 
 
    \t \t \t var n = translateString.indexOf('%'); 
 
    \t \t \t var n1 = translateString.lastIndexOf("%"); 
 
    
 
    \t \t \t var res = parseInt(translateString.slice(n+1,n1)); 
 
    \t \t \t return res; 
 
    \t \t } 
 
    
 
    \t \t var list_img = document.querySelector('.list-img'); 
 
    \t \t var pos_list = list_img.scrollTop; 
 
    \t \t var all_imgs = document.querySelectorAll('.list-img>li img'); 
 
    \t \t 
 
    \t \t console.log('actual position of the list:'); 
 
    \t \t console.log(pos_list); 
 
    \t 
 
    \t \t list_img.addEventListener('scroll', function(e){ 
 
    
 
    \t \t \t \t var scroll = this.scrollTop; 
 
    \t \t 
 
    \t \t \t \t // positive number means "scroll down" 
 
    \t \t \t \t // negative number means "scroll up" 
 
    \t \t \t \t var offsetScrollTreshold = scroll - pos_list; // unused 
 
    
 
    \t \t \t \t // move image 1 unit up/down 
 
    \t \t \t \t var offsetScroll = 3; 
 
    \t \t \t \t var speed = 1; 
 
    \t \t \t \t 
 
    \t \t \t \t console.log('position of list (pos_list):'); 
 
    \t \t \t \t console.log(pos_list); 
 
    \t \t \t \t 
 
    \t \t \t \t console.log('scroll:'); 
 
    \t \t \t \t console.log(scroll); 
 
    \t \t \t \t 
 
    \t \t \t \t console.log('offset (scroll - pos_list):'); 
 
    \t \t \t \t console.log(offsetScrollTreshold); 
 
    
 
    \t \t \t \t if(scroll > pos_list) { 
 
    \t \t \t \t \t \t console.log('User is scrolling DOWN'); 
 
    \t \t \t \t \t \t console.log('I want to show more from the hidden top of all the images within the actual viewport while user is scrolling down. But each image should not exceed its original image size.'); 
 
    
 
    \t \t \t \t \t \t list_img.classList.add('scroll-down'); 
 
    \t \t \t \t \t \t list_img.classList.remove('scroll-up'); 
 
    
 
    \t \t \t \t \t  [].forEach.call(all_imgs, function(node) { 
 
    \t \t \t \t \t  \t 
 
    \t \t \t \t \t  \t var node_in_view = node_is_in_viewport(node); 
 
    
 
    \t \t \t \t \t  \t // if image is in viewport move it up to "make a parallax effect" 
 
    \t \t \t \t \t  \t if(node_in_view){ 
 
    \t \t \t \t \t  \t \t console.log('-----'); 
 
    \t \t \t \t \t  \t \t console.log('actual img to move up (new Y must be lower):'); 
 
    \t \t \t \t \t  \t \t console.log(node.src); 
 
    
 
    \t \t \t \t \t  \t \t var old_y = 0; 
 
    \t \t \t \t \t \t  \t 
 
    \t \t \t \t \t \t  \t var theCSSprop = window.getComputedStyle(node, null).getPropertyValue('object-position'); 
 
    \t \t \t \t \t \t  \t if(theCSSprop.indexOf('%')!=-1){ 
 
    \t \t \t \t \t \t  \t \t console.log(theCSSprop); 
 
    
 
    \t \t \t \t \t \t  \t \t // returns the actual "y"-position of the image 
 
    \t \t \t \t \t \t  \t \t old_y = getObjectPosY(theCSSprop); 
 
    \t \t \t \t \t \t  \t \t console.log('old_y:'); 
 
    \t \t \t \t \t \t  \t \t console.log(old_y); 
 
    \t \t \t \t \t \t  \t } 
 
    \t \t \t \t \t \t  \t 
 
    \t \t \t \t \t \t  \t 
 
    \t \t \t \t \t \t  \t // User is scrolling down, so I want to view more from the "top of the image" which is actually a little hidden (because of object-fit: center 50%) 
 
    \t \t \t \t \t \t  \t // to view more from the top of the image, I have to set the y-value (actually: 50%) lower, but not more than 0. 
 
    \t \t \t \t \t \t  \t if(old_y > 0 && old_y <= 100){ 
 
    \t \t \t \t \t \t \t \t 
 
    \t \t \t \t \t \t \t \t console.log('scroll image "slowly" up while user is scrolling down (parallax effect)'); 
 
    \t \t \t \t \t \t \t  \t var new_y = old_y - offsetScroll * speed; 
 
    
 
    \t \t \t \t \t \t \t  \t if(new_y<0){ 
 
    \t \t \t \t \t \t \t  \t \t new_y = 0; 
 
    \t \t \t \t \t \t \t \t } 
 
    \t \t \t \t \t \t \t  \t 
 
    \t \t \t \t \t \t \t  \t console.log('new_y:'); 
 
    \t \t \t \t \t \t \t  \t console.log(new_y); 
 
    \t \t \t \t \t \t \t  \t node.style.objectPosition = '50% '+ new_y + '%'; 
 
    \t \t \t \t \t \t  \t } 
 
    \t \t \t \t \t  \t } 
 
    \t 
 
    \t \t \t \t \t }); 
 
    \t \t \t \t  } 
 
    \t \t \t \t  else { 
 
    
 
    \t \t \t \t  \t console.log('User is scrolling UP'); 
 
    \t \t \t \t \t console.log('I want to show more from the hidden bottom of all the images within the actual viewport while user is scrolling up. But each image should not exceed its original image size.'); 
 
    
 
    \t \t \t \t \t list_img.classList.remove('scroll-down'); 
 
    \t \t \t \t \t list_img.classList.add('scroll-up'); 
 
    \t \t \t \t \t  
 
    \t \t \t \t \t [].forEach.call(all_imgs, function(node) { 
 
    \t \t \t \t \t  \t 
 
    \t \t \t \t \t \t var node_in_view = node_is_in_viewport(node); 
 
    
 
    \t \t \t \t \t \t // if image is in viewport move it down to "make a parallax effect" 
 
    \t \t \t \t \t  \t if(node_in_view){ 
 
    
 
    \t \t \t \t \t  \t \t console.log('actual img to move down (new Y must be higher):'); 
 
    \t \t \t \t \t  \t \t console.log(node.src); 
 
    \t \t \t \t \t \t  \t 
 
    \t \t \t \t \t \t  \t var theCSSprop = window.getComputedStyle(node, null).getPropertyValue('object-position'); 
 
    \t \t \t \t \t \t  \t if(theCSSprop.indexOf('%')!=-1){ 
 
    \t \t \t \t \t \t  \t \t console.log(theCSSprop); 
 
    
 
    \t \t \t \t \t \t  \t \t // returns the actual "y"-position of the image 
 
    \t \t \t \t \t \t  \t \t old_y = getObjectPosY(theCSSprop); 
 
    \t \t \t \t \t \t  \t \t 
 
    \t \t \t \t \t \t  \t \t console.log('old_y:'); 
 
    \t \t \t \t \t \t  \t \t console.log(old_y); 
 
    \t \t \t \t \t \t  \t } 
 
    
 
    \t \t \t \t \t \t  \t // User is scrolling up, so I want to view more from the "bottom of the image" which is actually a little hidden (because of object-fit: center 50%) 
 
    \t \t \t \t \t \t  \t // to view more from the bottom of the image, I have to set the y-value (actually: 50%) higher, but not more than 100%. 
 
    \t \t \t \t \t \t  \t if(old_y >= 0 && old_y < 100){ 
 
    \t \t \t \t \t \t \t 
 
    \t \t \t \t \t \t  \t \t console.log('scroll image "slowly" down while user is scrolling up (parallax effect)'); 
 
    \t \t \t \t \t \t  \t \t 
 
    \t \t \t \t \t \t \t  \t var new_y = old_y + offsetScroll * speed; 
 
    
 
    \t \t \t \t \t \t \t  \t if(new_y>100){ 
 
    \t \t \t \t \t \t \t  \t \t new_y = 100; 
 
    \t \t \t \t \t \t \t \t } 
 
    \t \t \t \t \t \t \t  \t 
 
    \t \t \t \t \t \t \t  \t console.log('new_y:'); 
 
    \t \t \t \t \t \t \t  \t console.log(new_y); 
 
    
 
    \t \t \t \t \t \t \t  \t node.style.objectPosition = '50% '+ new_y + '%'; 
 
    \t \t \t \t \t \t  \t } 
 
    \t \t \t \t \t  \t } 
 
    \t \t \t \t \t }); 
 
    \t \t \t \t } 
 
    \t \t \t \t 
 
    \t \t \t pos_list = scroll; 
 
    \t \t \t console.log('pos_list:'); 
 
    \t \t \t console.log(pos_list); 
 
    \t \t \t 
 
    \t \t });/*end eventlistener scroll */ 
 
    \t \t 
 
    \t }); /*end .DOMContentLoaded */ 
 
    }()); 
 
    
 

 
    
 
    body, html, #ctn_infinity, .list-img{ 
 
    \t height: 100%; 
 
    \t width: 100%; 
 
    \t margin: 0; 
 
    \t padding: 0; 
 
    } 
 
    
 
    .list-img{ 
 
    \t height: 90vh; 
 
    \t overflow: auto; 
 
    } 
 
    
 
    
 
    .list-img{ 
 
    \t list-style: none; 
 
    \t width: 400px; 
 
    } 
 
    
 
    .list-img>li{ 
 
    \t display: flex; 
 
    \t flex-direction: column; 
 
    \t border: 2px solid black; 
 
    \t margin: 16px auto; 
 
    } 
 
    
 
    .list-img div{ 
 
    \t background: yellow; 
 
    } 
 
    
 
    .list-img img{ 
 
    \t object-fit: cover; 
 
    \t width: 100%; 
 
    \t /* original image size: 400 width x 200 height */ 
 
    \t /* I use object position center: when scrolling up or down, images should "slowly" show its hidden part of its images (max. 25px top or 25px down) */ 
 
    \t height: 150px; 
 
    \t /* Unfortunately, I cannot use "transform: translateY(-5px);", because this will move the whole img-container instead of the img itself up/down" */ 
 
    \t object-position: center 50%; 
 
    } 
 
    
 
    
 
    
 
<!DOCTYPE html> 
 
    <html> 
 
    <head> 
 
    <meta charset="UTF-8"> 
 
    <title>HTML-TEST</title> 
 
    
 
    
 
    </head> 
 
    <body> 
 
    \t <div id="ctn_infinity"> 
 
    \t \t <ul class="list-img"> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t \t <li><img src="http://lorempixel.com/400/200"> 
 
    \t \t \t \t <div>lorem epsum..</div></li> 
 
    \t \t </ul> 
 
    \t </div> 
 
    </body> 
 
    </html>

回答

0

我找不到csstriggers.com對象的位置。但是我自己檢查了一下,一旦我用object-fit:cover更改了一個元素的對象位置,我得到了一個Recalculate style和一個Paint

如果你不熟悉這些,這些辦法你的瀏覽器的特定事件後更新您的屏幕。你的代碼觸發的事件非常重要。現在,在每個滾動事件中,您的代碼會在瀏覽器窗口上觸發昂貴的繪畫事件。

基本上你想要做的是重構它使你的代碼沒有被重繪。您可能需要將objectPosition更改爲.style.transorm = "translate3d(0, " + new_y + ", 0)";。那些不應該像現在那樣觸發繪畫事件。

事情與這雖然,這有可能是方法還是會引發塗料。我建議你閱讀關於滾動性能,因爲它是太多的堆棧溢出解釋,Paul Lewis wrote關於這個不錯的文章。

+0

我的第一個解決方案是基於translate3d(translateY)。但是,我不能使用「translate3D」,因爲在使用時,整個圖像將移動而不是其內容。 – nimo23

+0

最好的解決方案將是一個真正的基於CSS的技術,如http://keithclark.co.uk/articles/pure-css-parallax-websites/。但是我不能對這個問題採取這種解決方案。也許我錯過了一些觀點。 – nimo23