Responsive Images

반응형 이미지가 필요한 이유는?

전형적인 웹사이트에는 헤더 이미지가 있을 것이고, 헤더 밑 컨텐츠 영역에도 이미지가 있을 것이다. 보통의 경우, 헤더 이미지는 헤더 가로 너비 전체(100%)를 차지할 것이고, 컨텐츠 영역의 이미지는 컨텐츠 너비 안에서 일정 영역을 차지할 것이다.

body {
   width: 100%;
   max-width: 1200px;
   margin:0 auto;
   background-color: white;
}
header {
   background: url(header.jpg) no-repeat center;
   height: 200px;
}


위의 코드는 노트북이나 데스크탑처럼 화면이 넓은 기기에서는 잘 동작한다.

  • 사이트 전체 넓이는 1200px 이고, 뷰포트가 1200px 이 넘는 경우 공간안에서 가운데 정렬된다. 1200px 이하일 경우에는 전체 너비를 차지한다.
  • 헤더 이미지는 너비가 얼마든간에 언제나 헤더의 가운데에 오게 설정하였고, 높이는 200px 로 고정시켰다.


이 코드는 화면이 넓은 기기에서는 잘 동작할 수 있으나, 화면이 좁은 기기로 사이트를 봤을때 이미지가 화면 높이를 너무 많이 차지한다. 개선책은 좁은 화면에서 사이트를 볼 때 이미지의 중요한 부분만을 자른 이미지를 보여주는 것이다.

이를 보통 아트 디렉션 문제(art direction problem) 라고 하는데, 이미지의 의도가 제대로 전달되도록 기기에 따라 사진의 핵심을 확대하거나 줄여서 보여주는 방식을 의미한다.

게다가, 작은 모바일 화면에서는 페이지에 그렇게 큰 이미지를 포함할 필요가 전혀 없다. 이것을 해상도 전환 문제(resolution switching problem)라고 부른다.

예로, 화면이 확대 되었을 때 이미지가 손상을 막기위해 래스터 이미지(jpg,png..)보다는 벡터 그래픽(svg)를 사용한다. (벡터 이미지는 화면에 렌더링 될때 이미지가 어떻게 보이는지 알아내기 위해 모양 및 경로의 정의가 포함되어 있다.)

역으로, 훨씬 작은 화면에서 굳이 큰 이미지를 표시할 필요가 없다. 그렇게 하는 것은 모바일 사용자가 오히려 커다란 이미지를 다운로드하느라 대역폭을 낭비하게 만든다.
이상적인 솔루션은 다양한 해상도의 이미지를 준비해두고, 웹사이트 데이터를 받는 기기에 따라 적당한 사이즈를 제공하는 것이다.

또 다른 경우, 어떤 기기는 고해상도를 지원해서 더 세밀하게 보여주려고 하면 더 큰 사이즈의 이미지가 필요하다. 근본적으론 같은 문제지만, 약간 맥락이 다르다.
당연히 벡터 이미지를 사용함으로써 이 문제를 해결할 수 있다. 그러나 벡터 이미지는 간단한 그래픽, 패턴, 인터페이스 요소 등에는 적합하지만, 사진 같은 상세한 종류의 이미지를 벡터 기반으로 만드려고 하면 복잡해지기 시작한다.

이러한 문제들은 90년대 초중반에 웹이 처음 등장했을 때는 존재하지 않았다. 당시 웹으로 접속가능한 기기는 데스크탑과 노트북뿐이었기 때문이다.
하지만 현재는 많은 기기들로 웹을 이용할 수 있으므로 아트 디렉션 문제(공간에 맞게 자른 이미지를 보여줌) , 해상도 전환 문제(픽셀수가 다르지만 동일한 이미지를 보여줌)의 중요성은 더욱 커지고 있다.

어떻게 만드는가?

  1. 해상도 전환 – 같은 이미지, 다른 크기
<img src="dylan-800w.jpg" alt="img">

위 코드와 같이 <img> 요소는 전통적으로 브라우저에게 하나의 소스 파일만 제시하도록 되어있었다.

그러나 srcset sizes 라는 두 가지 새로운 속성(attribute)을 사용해  브라우저가 이미지를 로드할때 사이즈에 맞는 이미지를 로드하게끔 할 수 있다.

srcset 은 브라우저에게 제공할 이미지 목록(경로)과 원본 크기를 정의한다.
sizes 은 미디어 조건문들을 정의하고, 특정 미디어 조건문이 참일 때 최적화되어 출력될 이미지 크기를 지정한다.

<img srcset="dylan-320w.jpg 320w,
             dylan-480w.jpg 480w,
             dylan-800w.jpg 800w"
     sizes="(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px"
     src="dylan-800w.jpg" alt="img">

위의 코드에서 예를 들자면, 뷰포트 너비가 480px인 브라우저가 페이지를 불러온다고 하면, (max-width: 480px) 미디어 조건문이 참이 될 것이고, 따라서 440px 사이즈가 최적의 사이즈로 선택된다.
440px에 가장 가까운 고유 너비(480w)가 선택되고 ‘dylan-480w.jpg 480w’가 로딩된다.

2. 해상도 전환 – 같은 크기, 다른 해상도

<img srcset="dylan-320w.jpg,
             dylan-480w.jpg 1.5x,
             dylan-640w.jpg 2x"
     src="dylan-640w.jpg" alt="img">

만약 다양한 디스플레이 해상도를 지원해야하는데, 모두가 이미지를 실제 사이즈로 동일하게 봐야한다면, x를 사용하여 브라우저가 적절한 해상도의 이미지를 선택하게 할 수 있다.

3. 아트 디렉션

다음과 같이 가운데 사람이 있는 커다란 가로 사진이 있을때, 이를 모바일 브라우저로 줄여서 보면 사람이 보기 힘들 정도로 작아진다. 이 때, 사람이 확대된 좀 더 작은 세로 사진으로 보여주는게 나을 것이다. 이는 <picture> 을 사용하여 구현할 수 있다.

<picture>
  <source media="(max-width: 799px)" srcset="dylan-480w-close-portrait.jpg">
  <source media="(min-width: 800px)" srcset="dylan-800w.jpg">
  <img src="dylan-800w.jpg" alt="img">
</picture>

위의 코드에서, <source> 요소에는 media 속성이 있다. 아까전의 srcset 처럼, 이 조건들도 어떤 이미지를 보여줄지 결정한다. 만약 뷰포트 너비가 799px 이하라면, 첫 번째 <source> 요소 이미지가 표시될 것이다.
(중요 : 모든 경우에서 src,alt 속성이 있는 img 요소를 </picture> 바로 앞에 반드시 제공해야한다 => 이것은 true를 리턴하는 미디어 조건문이 없는 경우 기본이미지를 제공하는것이다.)

CSS와 자바스크립트를 이용해 처리할순 없을까?

브라우저가 페이지를 불러오기 시작할때, 메인 파서가 CSS와 자바스크립트를 로드하고 해석하기전에 이미지들을 다운로드하기 시작한다. 이렇게 하는 것은 평균적으로 페이지 로딩시간을 20%정도 단축시켜주는 유용한 방법이다. 그러나 반응형 이미지에는 이 방법이 도움이 안된다. 따라서 srcset 같은 해결책으로 구현해야 한다. 예를 들면, <img> 요소를 불러온 후, 자바스크립트로 뷰포트 너비를 감지하고, 필요하면 더 작은 소스 이미지로 동적으로 바꾸는 식으로 처리해야하는데 그 시점에 이미 원래의 이미지가 로드된 상태고, 작은 이미지까지 추가로 로드해야한다. 이건 오히려 더 손해…라고 볼 수 있다.

추가 정보

  • WebP , JPEG-2000 과 같은 이미지 포맷들을 사용하자 (작은 용량과 퀄리티를 동시에 유지시켜준다) 하지만 브라우저 지원에… 문제가 있을 수 있다.