반응형 웹 디자인(responsive web design, RWD)이란 하나의 웹사이트에서 PC, 스마트폰, 태블릿 PC 등 접속하는 디스플레이의 종류에 따라 화면의 크기가 자동으로 변하도록 만든 웹페이지 접근 기법을 말한다.
위키피디아, 반응형 웹 디자인
요즘 반응형 웹(이하 RWD)을 적용하지 않은 서비스가 있을까? RWD를 적용하는 게 아무짝에도 쓸모가 없는 경우가 아니면 아마 대부분의 서비스가 RWD를 적용해 사용자의 원활한 웹 접근을 지원하고 있을 것이다. RWD를 적용하는 방법에는 여러가지가 있지만 여기서는 그중에서도 가장 기본적인 것, 이미지를 적절하게 리사이징하는 방법에 대해 알아볼 것이다.
말하자면 이런 것 👆👆👆
<img>
태그의 srcset
속성 사용하기srcset
은 브라우저에게 제시할 이미지 목록과 그 크기를 정의한다. 속성값은 다음과 같이 작성한다.
<img srcset="./small.png 400w,
./medium.png 700w,
./large.png 1000w"
sizes="(max-width: 401px) 400px,
(max-width: 700px) 7000px,
1000px"
src="./large.png"
alt="IMAGE" />
srcset
은 브라우저에게 제시할 이미지 목록과 그 크기를 정의한다. 기본적인 구조는 이미지 주소 + 이미지 크기
로 되어있는데 여기서 이미지 크기를 표현하는 단위는 px
이 아닌 w
를 사용한다. w
는 이미지의 고유 픽셀 너비로, 이미지의 실제 사이즈를 말한다.
sizes
는 미디어 조건문을 정의하고 특정 미디어 조건문이 참일 때 어떤 이미지 크기가 최적인지를 나타낸다. 기본적인 구조는 (미디어 조건문) + 조건문이 참인 경우 이미지가 채울 슬롯의 너비
로 되어있다.
이 코드를 만난 브라우저의 동작은 다음과 같다.
srcset
에 연결된 이미지 렌더링srcset
을 지원하지 않는 브라우저의 경우 src
에 정의된 이미지를 렌더링한다.
그리고 위 코드는 다음과 같이 동작한다.
왜죠
이 당혹스러운 현상을 이해하려면 srcset
의 정의를 다시 돌이켜 봐야 한다. srcset
은 브라우저에게 제시할 이미지 목록과 그 크기를 정의하는 속성이다. 이게 무슨 말이냐면, 브라우저에 띄울 이미지의 크기를 결정하는 것이 개발자가 아니라 브라우저라는 뜻이다. 즉, srcset
속성은 브라우저의 사이즈가 변경될 때마다 렌더링을 새로 하는 것이 아니라 처음에 브라우저가 그려질 때의 크기에 따라 이미지를 렌더링한다.
이 같은 특성 때문에 srcset
은 일반적으로 이해하기 어려운 이상한 동작을 하는데,
전자의 동작만 보면 srcset
이 마치 조건문에 따라 적절한 이미지를 렌더링해주는 것처럼 보이지만 실상은 그렇지 않다. 브라우저 사이즈가 커지면서 처음에 렌더링된 이미지가 적절하지 못한 사이즈로 판단될 경우 큰 이미지를 다시 렌더링하지만, 처음부터 브라우저 사이즈가 커서 큰 이미지를 렌더링했을 경우 브라우저 사이즈가 작아지더라도 이미지를 다시 렌더링하지 않는다.
어차피 용량이 가장 큰 이미지를 렌더링했다면 더 작은 이미지를 렌더링하기 위해 브라우저가 reflow, repaint 과정을 거치느니 그대로 큰 이미지를 사용하는 것이 낫기 때문이다.
즉, srcset
은 모바일과 같이 작은 화면에 적절한 용량의 이미지를 제공하기 위한 속성이다. 모바일 사용자가 데스크탑 사용자와 같이 아주 큰 용량의 이미지를 렌더링하려면 더 많은 비용을 지불해야 하기 때문이다.
그러므로 RWD를 구현하기 위해 srcset
을 사용하는 것은 적절하지 않은 방법이다. 이때 <picture>
태그를 사용할 수 있다.
<picture>
태그 사용하기<picture>
태그는 0개 이상의 <source>
요소와 <img>
요소를 포함한다. 브라우저는 각각의 <source>
요소를 고려해 적절한 이미지를 제공하게 된다. <picture>
태그도 srcset
속성과 마찬가지로 브라우저에서 지원하지 않는 경우 <img>
태그의 src
속성에 정의된 이미지를 렌더링한다.
<picture>
태그의 속성값은 다음과 같이 정의한다.
<picture>
<source srcset="./large.png" media="(min-width: 1000px)" />
<source srcset="./medium.png" media="(min-width: 700px)" />
<source srcset="./small.png" media="(min-width: 400px)" />
<img src="./large.png" alt="이미지">
</picture>
정의된 <picture>
태그는 아래와 같이 동작한다.
브라우저의 사이즈에 따라 이미지가 새롭게 렌더링되는 것을 볼 수 있다. 따라서 <picture>
태그를 사용하면 RWD를 구현할 수 있다. 그런데 처음에 만들고자 했던 방식과는 조금 다른 것을 확인할 수 있다. 이미지가 리사이징 되는 것이 아니라 고정된 사이즈에 다른 이미지가 들어가는 방식으로 구현된다. 즉, <picture>
태그를 사용하는 경우는 고정된 사이즈 내에서 적절한 용량의 이미지가 렌더링되도록 할 때 가장 알맞게 사용할 수 있다. 만약 맨 처음에 보여졌던 이미지대로 리사이징까지 하고 싶다면 javascript를 활용해 렌더링 되는 이미지에 따라 사이즈를 변경해주거나 다음에 소개할 미디어쿼리를 사용하면 된다.
<picture>
태그를 사용할 때 주의할 점
1.<img>
태그와 달리 반드시 높은 해상도 기준을 가진 이미지 소스 태그가 상위에 위치해야 한다.
2.<picture>
태그 내에<img>
태그가 빠져서는 안 된다.
3.srcset
에 정의되어 있는 이미지와<img>
에 정의되는 이미지는 같은 것이어야 한다.
미디어 쿼리는 단말기의 유형(출력물 vs. 화면)과, 어떤 특성이나 수치(화면 해상도, 뷰포트 너비 등)에 따라 웹 사이트나 앱의 스타일을 수정할 때 유용합니다. MDN, 미디어 쿼리 사용하기
미디어 쿼리는 미디어 유형(all, print, screen, speech)과 하나 이상의 미디어 특성 표현식으로 이루어진다. 표현식에는 브라우저의 사이즈, 호버 상태, 사용자 OS의 다크 모드 적용 여부 등 다양한 조건에 따라 다른 스타일 시트를 적용할 수 있다. 즉, 지금 적용하고자 하는 미디어 쿼리는 브라우저의 사이즈에 따라 다른 이미지를 적용하는 방식으로 표현식을 작성하면 된다.
미디어 쿼리를 작성하는 방법은 아래와 같다.
<div class="ex-midea"></div>
.ex-midea {
max-width: 100%;
width: 400px;
height: 400px;
background-image: url(./small.png);
background-repeat: no-repeat;
background-size: contain;
padding: 10px
}
@media (min-width: 401px) {
.ex-midea {
width: 700px;
height: 700px;
background-image: url(./midium.png);
}
}
@media (min-width: 701px) {
.ex-midea {
width: 1000px;
height: 1000px;
background-image: url(./large.png);
}
}
이렇게 작성한 코드는 처음에 구현하고자 했었던 형태로 구현할 수 있다.
미디어 쿼리의 장점은 기존에 스크립트를 접목해서 표현해야 했던 RWD를 CSS 코드만으로 간단하게 구현할 수 있게 해준다는 점이다. 물론 여러 상황에 대응하는 RWD를 제작하기 위해서는 스크립트를 사용하지 않고 구현하기 어렵겠지만 브라우저의 사이즈에 따라 이미지가 변경된다거나, 혹은 한 줄에 들어가는 아이템의 갯수 등을 조절하는 간단한 방식에서는 미디어 쿼리를 사용하는 것이 훨씬 더 간결하고 쉬운 방법이다.