Tistory View

web/javascript

HTML Image lazy loading[느린 로딩] #1

God Dangchy What should I do? 2020. 12. 12. 16:07

이미지를 필요할 때만 로딩하는 방법이 있다. 브라우저는 HTML을 전송받으면 다음으로 이미지를 서버에 요청하게 되는 데, 이 때 HTML파일이 이미지가 100개 있다면, 브라우저는 100개를 모두 서버에 요청하게 된다. 하지만 이 100개의 이미지를 사용자가 다 볼일은 없다. 물론 다 볼 수도 있지만, 보이지 않는 이미지도 있을 것이고, 페이지가 길면 길수록 사용자가 보지 않는 이미지는 더 많아 질 것이다.


이미지의 전송량을 줄이는 것은 서버의 부담을 줄이고, 네트워크 전송량을 줄이는 데 아주 효과적이다. 실제 긴 화면상의 이미지중에 70~80%는 사용자가 보지않고 다른 페이지로 이동을 하는 경우가 대부분이다. 이말은 네트워크사용량을 20% 수준으로 줄일 수 있다는 말이 되고, 서버도 쓸데없이 자원을 허비할 필요가 없으니, 금전적으로 아주 좋을 결과를 뽑아 주게 된다.



사용법은 다음과 같다. img태그에  [loading="lazy"] 만 추가 해주면 된다.


<img src="~~~~~~~~" loading="lazy" />



loading의 값은

auto

 


기본값, 웬만하면 그냥 페이지가 로딩할 때, 같이 다 불러온다. 가끔 "현재 보이는 화면(View-port)"에서 너무 멀리 떨어진 경우는 lazy가 적용이 될 수 있다. 이 것은 브라우저설정마다 다를 수 있다.


eager

 


무조건 불러온다.


 lazy

 


 화면근처에 있는 아직 불러오지 않은 이미지를 로드한다.

이 것은 때로는 그냥 불러오기도 하는 데, 네트웍이 WIFI인지 유선이지, LTE인지 3G인지에 따라 달라 질 수 있다.


필자의 테스트에서는 대부분의 상황에서 뷰포트 근처의 것만을 불러오는 것이 대부분 이었다.







개발자도구에서 구분


[불여우]개발자도구에서 lazy인지 아닌 지 확인할 수 있다.









일일이 이미지 태그를 찾아 전부 넣는 것이 귀찮아서 다음과 같은 코드를 작성하였다.




이미지에 전부 로딩 적용하기 - 동작하지 않는다.

document.addEventListener("DOMContentLoaded", function(event) {
     
    let elmImgs = document.querySelectorAll( "img" );
    console.log( 'count to apply='+ elmImgs.length );
    
    for( var i = 0 ; i < elmImgs.length ; i++ ){
        let img = elmImgs[i];
        //img.lazyLoad=true;                   // not works
        img.setAttribute( "loading", "lazy" ); // not works
    }
    
});


슬프게도 위에 코드는 동작하지 않는다. ㅠㅠ



이 것[loading="lazy"]은 꼭 html코드안에 있어야 한다. javascript로 아무리 img.setAttribute('loading', 'lazy' ); 로 바꾸어도 동작하지 않는다.

다른 방법을 찾아 봤지만, 필자가 테스트한 바로는 어떤 것도 동작하지 않았다. 언젠가 동작하는 것으로 바뀔지는 모르지만, 어쨋든 현재(2020년12월)에는 동작하지 않았다.


결국 일일이 img태그를 찾아서 넣어주는 수 밖에... 솔직히 그리 어려운 작업은 아니지만, 아주 간단히 끝낼 수 있는 좋은 방법을 쓸 수 없다는 것이 많이 아쉽기는 하다.




레이아웃이 잡혀있지 않으면 lazy-loading은 별 효과가 없다.

<img src="이미지1" loading="lazy" />
<img src="이미지2" loading="lazy" />
<img src="이미지3" loading="lazy" />
<img src="이미지4" loading="lazy" />
<img src="이미지5" loading="lazy" />
<img src="이미지6" loading="lazy" />
<img src="이미지7" loading="lazy" />
                     .
                     .
                     .

                ( 100개 )


HTML이 로드되고 Dom이 완성되면 이미지와 같은 추가적인 리소스를 불러오게 될 텐데, 위의 코드는 이미지의 크기를 서버에서 가지고 오기 전에는 알 수가 없기에, DOM에서는 다닥다닥 붙어있는 것[height=0]이 되어버린다. 브라우저는 이 모든 것이 다 뷰포트안에 있다고 판단할 수 밖에 없으니, lazy고 뭐고 그냥 싹다 서버에서 가지고 올 수 밖에 없다. 개발자 도구에 [lazy-img]라고 찍혀도 의미가 없게 된다.




그림 좀 이쁘게 로딩하기

lazy-loading이 적용되면 단점이 좀 있는 데, 뷰포트 근처에 이미지가 로딩되기 때문에, 스크롤을 빠르게 내리면 툭툭툭툭거리면서 이미지가 화면에 보여지게 된다. 사용자들은 뭐 별로 신경을 쓰지 않겠지만, 가끔 민감한 사람이 있다.(그 사람이 사장이라면 짜증 나지만..)


이미지가 로드되면 Fade-in으로 이미지가 보여지게 변경을 해 보자.


Fade-in을 구현하는 시나리오는 일단 초기에 opacity를 0으로 놓고, 이미지가 로드되면 opacity를 1로 변경 후 transition을 적용하면 된다.



일단 초기에 이미지의 opacity를 0으로 놓는다. 그리고 해당 img태그에 이벤트를 건다.

document.addEventListener("DOMContentLoaded", function(event) {

     

let elmImgs = document.querySelectorAll( "img" );

console.log( 'count to apply='+ elmImgs.length );

for( var i = 0 ; i < elmImgs.length ; i++ ){

let img = elmImgs[i];

// 초기 opacity => 0

img.style.opacity = 0;

// event 걸기

img.addEventListener( "load", myHandlerOnImageLoad, false );

}

});


이미지가 로드된 경우 

function myHandlerOnImageLoad( evt ) {

var img = evt.target;

// opacity를 바꾸고

img.style.opacity = 1.0;

// transition 적용

img.style.transition = 'opacity 0.25s ease-out';

}




이 정도면 사장도 뭐라 하지 않을 것 같다.


이 정도면 대부분의 상황에 대처할 수 있을 것 같다.


하지만, 이 정도로 만족할 수 없는 경우가 있다. img태그를 사용했다면 상관없지만 그렇지 않다면(img태그를 쓰지 못하는 경우가 있다.).. 다음편에 계속


현재 글의 내용을 적용한 링크를 걸어 두겠지만, 이게 연결이 안될 수도 있다.. 좀 불안정한 서버라..


http://mybread.duckdns.org:8084/~blog/lazy_load/lazy_img1.php



아 또 승질난다.


이 놈의 크롬(특히 모바일)에서 위에 코드가 정상적으로 작동하지 않는다. 이전에도 경험한 부분인데..

DOMContentLoaded가 image로드보다 더 늦게 호출이 되는 경우가 발생한다.

아무리 생각해도 이 건 크롬 버그인데, 누군가가 아니라구 강력히 우기는 사람이 있어서..(구글에서 월급받는 사람인가?)

근데 이 건 버그로 보는 것이 맞는 게, 다른 정확한 대안이 없다.

(있긴 있지만 이 건 코드를 꽈서 푸는 방식이라 해결책은 아닌 듯)


특히...

아주 큰 html파일일 경우 html을 로드하면서 이미지를 같이 로드하니 이미지가 먼저 로드되면 event가 나중에 걸리게 되고 나중에 걸린 event는 실행이 되지 않아 opacity가 0이 되는 문제다. 이미지가 캐시된 경우 특히 심해진다.


필자가 의도한 것은 원래 이 글이 중점이 아니고 다음글에 중점을 두었다. 다음 글이 이 문제와 상관없는 코드가 작성될 것이니 다음글이 작성될 때 까지... 기다려주세요..ㅠㅠ



아 갑자기 옛날 생각이 나면서 또 승질 난다.


지금도 그런지 모르겠지만, 크롬에서 javascript function hoisting에 충격적인 버그가 있어서 필자는 크롬을 쓰지 않는다.

그래서 버렸는 데, 다른 사람들이 다 쓰니... 아 승질나..




다음편

HTML Image lazy loading[느린 로딩] #2


Replies
Reply Write