Lazy Load(레이지 로드)란?

오프스크린 이미지(사용자가 보고 있는 화면에 보이지 않는 이미지)를 로딩하지 않고 있다가, 사용자가 스크롤을 움직여서 해당 이미지가 보여야 할 시점에 이미지를 로딩하는 기술입니다.

투명 이미지 업로드

이미지에 오류가 발생하면 티스토리에서 위 이미지를 집어넣습니다.
굳이 로딩하지 않아도 될 이미지를 로딩할 필요가 없으니, 이미지의 src에 1px * 1px짜리 이미지를 하나 넣어줘서 이미지에 아무런 오류가 발생하지 않도록 합니다.

1px * 1px에 아무런 색상 정보도 들어있지 않은 이미지입니다.
95바이트밖에 되지 않으니, 로딩 속도에 큰 영향을 끼치지 않습니다.

위 파일을 내려받아, 관리자 페이지 > 스킨 편집 > 파일업로드에서 이미지를 업로드합니다.

이미지 업로드가 끝나셨으면, 해당 이미지를 우클릭해서 이미지의 경로를 복사해주세요.

자바스크립트

document.addEventListener("DOMContentLoaded", () => {
  let TICKING = false,
    SCROLLY = window.scrollY;

  loadimg = () => {
    [...document.querySelectorAll(".imageblock img")].forEach(img => {
      const offsetTop = img.parentNode.offsetTop;
            
      !img.classList.contains("loaded"&& offsetTop + img.offsetHeight > SCROLLY && SCROLLY + window.innerHeight > offsetTop && (
        // 해당 이미지가 뷰포트 내부에 들어왔을 때 작동
        img.src = img.dataset.src,
        img.srcset = img.dataset.srcset,
        img.removeAttribute("data-src"),
        img.removeAttribute("data-srcset"),
        img.classList.add("loaded")
      )
    })
  },
  [...document.querySelectorAll(".imageblock img")].forEach(img => {
    // 본문에 들어간 이미지 src와 srcset 제거
    img.dataset.srcset = img.getAttribute("srcset"),
    img.dataset.src = img.src,
    img.removeAttribute("srcset"),
    img.src = "복사한_이미지_경로"
  }),
  loadimg(),
  window.addEventListener("scroll", () => {
    TICKING || (
      window.requestAnimationFrame(() => {
        // raf로 스크롤 이벤트 최적화
        SCROLLY = window.scrollY,

        loadimg(),

        TICKING = false
      })
    )
  })
});

복사한 이미지 경로를 위 스크립트에 있는 "복사한_이미지_경로"에 붙여 넣으신 후, 위 스크립트를 앞에 삽입합니다.

document.addEventListener("DOMContentLoaded",()=>{let e=!1,t=window.scrollY;loadimg=(()=>{[...document.querySelectorAll(".imageblock img")].forEach(e=>{const s=e.parentNode.offsetTop;!e.classList.contains("loaded")&&s+e.offsetHeight>t&&t+window.innerHeight>s&&(e.src=e.dataset.src,e.srcset=e.dataset.srcset,e.removeAttribute("data-src"),e.removeAttribute("data-srcset"),e.classList.add("loaded"))})}),[...document.querySelectorAll(".imageblock img")].forEach(e=>{e.dataset.srcset=e.getAttribute("srcset"),e.dataset.src=e.src,e.removeAttribute("srcset"),e.src="복사한_이미지_경로"}),loadimg(),window.addEventListener("scroll",()=>{e||window.requestAnimationFrame(()=>{t=window.scrollY,loadimg(),e=!1})})});

똑같은 스크립트를 압축한 스크립트입니다. 마찬가지로 "복사한_이미지_경로" 를 복사하신 이미지 경로로 바꾸신 후 사용해주세요.

끝!

이제 다시 본인의 블로그로 돌아가셔서, 아무 글이나 클릭하신 후, Ctrl Shift R을 누르시거나 캐쉬를 초기화하신 후 페이지를 불러와 보시면 정상적으로 이미지의 로딩이 지연되고 있는 걸 확인하실 수 있을 겁니다.

profile

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

(?)

  1. document.addEventListener("DOMContentLoaded", () => {
    var sss=document.getElementById("main");
    let TICKING = false,
    SCROLLY = window.scrollY;

    loadimg = () => {
    [...document.querySelectorAll(".imageblock img")].forEach(img => {
    const offsetTop = img.parentNode.parentNode.offsetTop;

    !img.classList.contains("loaded") && offsetTop + img.offsetHeight > SCROLLY && SCROLLY + window.innerHeight > offsetTop && (
    // 해당 이미지가 뷰포트 내부에 들어왔을 때 작동
    img.src = img.dataset.src,
    img.srcset = img.dataset.srcset,
    img.removeAttribute("data-src"),
    img.removeAttribute("data-srcset"),
    img.classList.add("loaded")
    )
    })
    },
    [...document.querySelectorAll(".imageblock img")].forEach(img => {
    // 본문에 들어간 이미지 src와 srcset 제거
    img.dataset.srcset = img.getAttribute("srcset"),
    img.dataset.src = img.src,
    img.removeAttribute("srcset"),
    img.src = "./images/blank.png"
    }),
    loadimg(),
    sss.addEventListener("scroll", () => {
    TICKING || (
    window.requestAnimationFrame(() => {
    // raf로 스크롤 이벤트 최적화
    SCROLLY = window.scrollY,

    loadimg(),

    TICKING = false
    })
    )
    })
    });

    넣어봤는데, 스크롤해도 인식을 안 하네요... 으믐믐... 스킨의 문제려나요...

    1. 거기까진 저도 잘 모르겠네요...ㅎㅎ

      https://imgur.com/rljs3Ez.mp4

    2. lazyload는 포기해야겠네욤 ㅎㅎ 열심히 도와주셨는데 죄송해요~ 좋은 하루 되세요!!

  2. #container에 overflow:hidden, 그 안의 article인 #content에 overflow:hidden, 그리고 그 안에 있는 글 내용인 #content #main이라는 클래스에 overflow-x:hidden; overflow-y:hidden이라 걸려있는 티스토리 스킨을 사용 중입니다, lazyload가 overflow가 걸려있는 스킨에선 작동이 안되는 거 같더라구요. overflow를 풀자니 스킨 스타일이 보기에 엉망으로 되어버려 풀지를 못하겠고, 그렇다고 lazyload를 안 쓰자니 너무 용량 낭비가 심하더라구요. 전에 데이터로 들어갔을 때 엄청나게 데이터를 낭비해버린 기억이 새록새록 떠오르네요... overflow가 걸린 스킨에 lazyload를 적용하려면 어떻게 해야할까요??

    1. window가 아닌 해당 엘리먼트에 이벤트 리스너를 추가하셔야 합니다.
      구조를 정확히 몰라 확답은 어렵지만, overflow-y가 scroll 혹은 auto인 엘리먼트가 있을 겁니다.

    2. #content #main {
      overflow: hidden;
      overflow-x: hidden;
      overflow-y: auto;
      } 라서

      var element = document.getElementById("#content #main");
      element.addEventListener("DOMContentLoaded", () => {
      ... 로 수정했고, 아랫분 댓글 보니 제 것도 imgblock에 들어가있어 const offsetTop = img.parentNode.parentNode.offsetTop;로 바꿔주었는데 작동을 안 하네요. 어디가 잘못된 걸까요??

    3. getElementById("아이디") 라고 적으셔야 해당 ID를 가진 엘리먼트를 반환합니다.
      https://developer.mozilla.org/ko/docs/Web/API/Document/getElementById

    4. var sss=document.getElementById("main");
      sss.addEventListener("DOMContentLoaded", () => {

      로 바꿔주니 콘솔에서 Uncaught TypeError: Cannot read property 'addEventListener' of null란 오류가 떠서 검색해보니 head에 넣어줘서 그렇다고 하더라구요. 그래서 body 아래에 넣어주면 이미 돔 로딩 끝나서 이미지도 다 로딩해서... 어떻게 하면 될까요??

    5. window.addEventListener("scroll", () => {

      이 부분에서 window를 sss로 변경하시면 됩니다.
      document.addEventListener("DOMContentLoaded", () => { 아래에 바로 sss 변수 선언해주시고요.

  3. 안녕하세요 마샬님! 밑에 스크롤 관련 댓글 달았던 익명입니다. 티스토리에 lazyload를 적용하고 나서 정말 편했는데요. 최근 글을 업로드 하고 보니 lazyload가 적용되지 않는 느낌을 받았습니다. 개발자도구를 켜서 확인해보니 lazyload가 이상하게 작동하고 있더라구요. 스크롤을 조금만이라도 내리면 모든 이미지를 한꺼번에 로딩하는 것처럼 보이네요. 스킨 오류인가 싶어서 POSTER 기본 스킨 적용하고 나서 해봐도 같은 결과가 나왔습니다. 스크립트 문제인가? 싶어 스크립트도 모두 지우고 lazyload 스크립트만 넣어뒀는데도 그대로이네요. 뭔가 문제가 생긴 거 같은데, 문제를 찾지 못하겠습니다. 지혜를 빌릴 수 있을까요?

    사이트 주소는 [removed] 입니다. 저번처럼 개발자 도구 키면 어딘가로 리다이렉트 되는 스크립트는 제거해뒀습니다.

    1. CSS 때문에 발생하는 문제입니다.

      .imageblock에 position: relative가 들어가 있네요. 부모 요소의 position이 static이 아니면 offsetTop의 기준점이 body가 아닌 부모 요소가 됩니다.

      익명 님 블로그에서 이미지의 html 구조가

      figure
      span
      img

      위 구조고 figure에 position: relative가 선언되었으니, const offsetTop = img.offsetTop 이 부분을 const offsetTop = img.parentNode.parentNode.offsetTop으로 변경하시면 됩니다.

    2. 헉, css 때문에 자바 스크립트가 꼬일 수도 있군요...!! 처음 알았습니다... 감사드려요!

      + 실례가 되지 않는다면 사이트 주소 지워주실 수 있으신가요?? 😁

    3. 지워뒀습니다!

    4. 감사합니다! ♡♡♡ 좋은 주말 되세요!!

    5. 넵~ 익명 님도 즐거운 주말 보내시길!

  4. 테스트 블로그에 오늘에서야 적용해보았습니다~
    적용이 잘된건지 어떤건지 잘 모르겠어서 테스트로 아이유 사진으로 해보았어요 🙂

    알려주신것처럼 이점이 많은 스크립트라..
    이미지가 많은 본 블로그에서 유용할거 같은데, 막상 적용하려고 하니 고민되네요 ㅎㅎ

    https://t1.daumcdn.net/cfile/tistory/9923A7385DB991BF1F?original

    1. F12 버튼 누르셔서 개발자 도구를 켜시고 네트워크 탭 클릭하신 다음에 스크롤 천천히 내리시면 제대로 적용된 지 쉽게 확인하실 수 있습니다.

      이미지 클릭하면 새 탭에서 열리는 스크립트랑 충돌할 수 있으니, 만약 적용하시고 싶으시면 연락해주세요. 스크립트 조금 손봐서 스킨 보내드릴게요.

      https://i.imgur.com/LY0V2bD.mp4

  5. 안녕하세요 마샬님! 티스토리에서 이미지를 로딩하는데 시간이 너무 많이 걸려 문제이던 차에, lazyload 글을 보고 적용하곤 훨씬 빨라진 로딩 속도에 마음이 편안해졌습니다. 문제가 조금 생겨서 그런데….

    모니터 상으로는 존재하지만 이미지가 나타나지 않습니다. 무조건 화면을 내려야만 나타나는데, 스크롤이 필요없을 정도로 짧은 글이기 때문에 스크롤할 수 없어서 이미지가 나타나지 않는 거 같습니다. 화면 상에 있다면 이미지를 로딩할 수 있게 할 수 없을까요?

    1. 돔 로딩이 끝난 시점에 뷰포트 안에 있는 이미지는 표시하도록 스크립트를 업데이트해뒀습니다.
      본문에 있는 스크립트로 다시 한 번 시도해주세요. 감사합니다!

    2. 본문에 있는 스크립트가 업데이트가 안된 거 같습니다...!

    3. 스크롤을 하지 않으면 로딩이 되지 않으신단 뜻인가요?

      제 테스트 블로그에선 본문에 업데이트한 스크립트를 적용하면 스크롤 없이도 이미지가 로딩되는데, 혹 사용 중이신 스킨의 html / css 때문은 아닐까 싶네요 ㅠㅠ

    4. 헉... 그런 걸까요...! 알겠습니다!

    5. 확인해보니 뷰포트 내부에 있는지 확인하는 스크립트도 문제가 좀 있어 수정해뒀습니다.
      마지막으로 한 번만 확인해주세요! ㅠㅠ

    6. 스크립트 문제가 아니라 제가 해뒀던 스크립트 문제였네요...
      fade in을 위해서 container에 style="display:none;" 준 게 화근이었습니다...
      아마도 display:none; 때문에 없어졌다 나타나 스크립트가 인식을 못했나봐요.
      좋은 스크립트 공유해주셔서 감사합니다!

    7. 아 해결하셨다니 다행이네요.

      jQuery의 fadeIn 없이도 그냥 자바스크립트로 컨테이너에 class 하나 추가하고 css에서 opacity를 조절하시면 fadeIn이 구현 가능합니다.
      css 애니메이션이란 선택지도 있고요.

      아무튼 즐거운 블로깅 되세요!

  6. 이미지가 많은 제블로그에 적용하면 어떨지 궁금하네요
    저녁에 테스트 블로그에 함 적용해봐야겠습니다 🙂

    그나저나 오랜만에 들어왔더니 많은 변화가 있는거같아요
    반가운 인사글 토글도 보이고 무엇보다 폰트가 아기자기하게 바뀌었네요

    폰트만 바꿔도 이렇게 분위기가 달리 느껴지는거같아요 b

    https://imgur.com/xDaLfIy.mp4

    1. 저는 스크롤 내리면 이미지가 바로바로 보이는 게 좋아서 사용하진 않지만, 방문자의 데이터를 아끼고 초기 페이지 로드 시간을 단축해주는 등 꽤 이점은 많은 스크립트입니다. 😀

      TWICE New Tab 사용자들은 홈 화면에서 인사말이 출력되도록 해뒀습니다 ㅎㅎ
      폰트는 한글날 기념으로 기업에서 이런저런 폰트를 많이 풀길래 한 번 바꿔봤고요.

      이런저런 차이점들 알아봐 주셔서 감사합니다! 😁

      https://imgur.com/QXPS5Eh.mp4

  7. 감사 합니다. 오프스크린 이미지 로딩 속도 해결 됐네요. ^^

    1. 댓글 감사합니다!
      저도 확인해보니 잘 작동 중인 것 같네요. ㅎㅎ
      즐거운 블로깅 되세요!