재사용 방문자를 위해 캐시 설정을 진행할 수도 있다.
필요한 정보를 저장하는 가장 쉬운 방법이 최상위 도메인을 이용해 쿠키를 설정하는 것인데 이렇게 되면 자바스크립트 파일이나 스타일시트 파일, 이미지 등 쿠키 정보가 필요없는 구성 요소를 요청할 때도 헤더 정보에 쿠키가 포함되며 헤더를 전송할 때 데이터 크기가 커진다.
이미지 확장자별 특성을 파알하고 무분별한 압축이 아닌 경우에 따라 적절한 효율의 압축을 함으로써 이미지 손상을 줄이고 궁극적으로 트래픽 절감 및 빠른 로딩 속도를 구현해볼 수 있다.
페이지에서 사용하는 이미지는 보통 가로폭이 1000px을 넘지 않으므로 사이즈가 큰 이미지가 있다면 폭을 조절하여 사이즈를 줄여준다.
많이 사용되는 JPG는 카메라로 찍은 실제 사진 이미지에서 최적화 되어있고, PNG 포맷은 만들어진 이미지일 경우 최적화 되어있다.
이미지 특성에 따른 확장자
PNG
GIF
picture, source, img 태그를 이용하여 지원하지 않는 포맷을 파일일 경우 특정 포맷의 파일을 이용하게 할 수 있다.
<picture>
<source srcset="image.avif" type="image/avif" />
<source srcset="image.webp" type="image/webp" />
<img src="image.jpeg" />
</picture>
어떤 액션이나 이벤트에 의해 DOM요소의 크기나 위치 등을 변경하면 해당 노드의 하위 노드와 상위의 노드들을 포함하여 레이아웃 단계를 다시 수행하게 되는데, 변경하려는 요소의 위치와 크기 뿐만 아니라 연관된 요소들의 위치와 크기도 재계산을 하기 때문에 브라우저의 퍼포먼스를 저하시킨다.
치수가 없는 이미지들은 reflow를 발생시켜 퍼포먼스를 저하시키기 때문에 이미지 및 비디오 요소에 width와 height 속성을 항상 포함하거나 css를 사용하여 필요한 공간 aspect-ratio를 잡는다. 이렇게 사용하게 되면 이미지가 로드되는 동안 브라우저가 문서의 공간을 올바르게 할당할 수 있다.
반응형일 경우 css 를 사용하여 이미지의 크기를 조정하게 될 수 있는데, 단점은 다운로드가 시작되고 브라우저가 크기를 결정할 수 있는 경우에만 이미지를 위한 공간을 할당할 수 있다. 이미지가 로드되어 화면에 나타나면 reflow 되어 텍스트가 갑자기 화면 아래로 튀어나가는 등의 문제가 발생할 수 있는데 이를 방지하기 위해 aspect-ratio를 사용할 수 있다. 이 속상을 사용하면 복잡한 계산 없이 간단하게 속성으로 레이아웃 이동 방지를 할 수 있다.
여러 이미지 버전을 지정해서 브라우저에서 사용하기 가장 적합한 버전을 선택한다.
<img src="image.jpg" srcset="image-small.jpg 280w, image-large.jpg 1080w" sizes="50w>
브라우저가 srcset과 sizes 속성을 지원하지 않으면 fall back 으로 src 속성이 동작하기 때문에 src 속성은 모든 디바이스 크기에서 동작할 수 있을만큼 충분히 커야한다.
srcset 은 이미지 파일명과 width 또는 density 설명을 쉼표고 구분하며 브라우저에서 그기르르 결정하기 위해 이미지를 다운로드할 필요 없다.
size 속성은 이미지가 표시될 때의 너비를 브라우저에게 말해주지만 display 크기에 영항을 주지 않고 브라우저는 로드할 이미지를 결정하기 위해 유저의 디바이스 정보와 함께 size 속성의 정보를 사용한다.
더 많은 이미지를 제공하는 만큼 성능이 향상 되지만 서버에서 많은 공간을 차지하기 때문에 몇개의 버전을 제공할지는 잘 고려하도록 한다.
sharp npm package(이미지 크기 조절 자동화) 혹은 ImageMagick CLI tool(커맨드 라인을 이용한 일회성 이미지 크기 조절)이 있다.
Image content delivery networks 로 전환하면 이미지 파일 크기를 40~80% 줄일 수 있다.
Image CDN이란 이미지 변환, 최적화 및 전송을 전문으로 하며 사이트에서 사용되는 이미지에 대한 접근이나 조작을 위한 API로 생각할 수 있다. Image CDN에서 로드된 이미지의 경우 URL은 이미지 뿐만 아니라 크기, 포맷, 품질 같은 매개변수도 제공하며 이를 통해 다양한 사용 사례에 대한 이미지를 쉽게 변형할 수 있다.
Image CDN이 사용하는 uri은 이미지 변형 및 최적화와 관련된 중요한 정보를 전송하는데, URL 포맷은 다음과 같다.
페이지를 로드할 때 모든 이미지를 로드하지 않고 중요하지 않은 자원 또는 당장 필요하지 않은 자원의 경우 서버에 요청을 미루고 필요한 경우 해당 자원을 요청받는다.
lazy loading 을 사용하면 데이터의 낭비를 막을 수 있고 브라우저의 렌더링 시간을 줄여준다.
사용방법
img 태그 내의 속성을 사용한다. 단, 모던 부라우저가 아닐 경우 해당 속성은 무시된다.
<img loading="lazy">
loading의 속성은 auto(디폴트 값으로 속성값을 지정하지 않은 것과 동일), lazy(뷰포트 상에서 해당 이미지의 위치를 계산하여 이미지 지원을 요청한다.), eager(어느 위치에 있던지 이미지 자원을 바로 요청받음) 세가지의 값이 있다.
해당 속성을 사용할 경우 되도록 해당 이미지 영역의 크기를 지정하는 것이 권장되는데, 영역의 크기에 대한 정보가 없으면 해당 영역의 크기를 알 수 없어 해당 영역을 0x0으로 인식하고 해당 이미지 영역으로 스크롤 할 경우 이미지가 로드 되며 layout shift가 일어날 수 있기 때문에 되도록 해당 img 태그에 명시적으로 높이/너비 값을 지정해야한다.
페이지의 첫 시작부터 보이는 페이지 및 backgorund-image에서는 lazy loading을 사용하지 않도록 한다.
Intersection Observer ÅPI (*아래에서 자세히 설명)
비동기적으로 사용자의 이벤트를 관찰하는 방법을 제공하는 웹 API로서 사용자가 웹 페이지를 스크롤 할 떄 어떤 element 이미지가 해당 뷰포트 내에 Intersection 되었는지를 판단할 수 있어서 해당 이미지가 교차되면 이미지를 로딩할 수 있도록 핸들링 한다.
const io = new IntersectionObserver(callback[, optons])
포맷의 특성에 따라 이미지를 저장하지만 저장시 포함되는 메타 정보를 제거해 조금 더 줄일 수 있다.
래스터 이미지: 우리가 사용하는 대부분의 이미지 유형이며, 각각의 픽셀들이 모여 하나의 큰 이미지를 완성한다. 정보를 담은 픽셀들을 추가해야만 컴퓨터그 정상으로 표현하며 확장성은 떨어진다.
백터 이미지: 좌표, 원, 사각형 등의 형상, 크기 등의 정보를 제공하여 컴퓨터가 그림을 그리듯 화면에 표현한다. SVG 파일이 W3C 표준 포맷으로 많이 사용한다. 메타 정보를 담고 있어서 화면에 따라 정보가 달라지지 않는다. 또한 화면 스케일에 상관 없이 선명한 이미지를 표현한다.
무손실 이미지 형식: 원본 이미지의 정보 손실을 허용하지 않는다.
손실 이미지 형식: 이동할 수 있는 형태를 만들기 위해 정보 손실을 허용한다. 손실 압축으로 이미지를 손실시켜 파일 크기를 줄이고 이미지 색이 비슷한 부분을 하나의 색으로 통일한다. 원하는 만큼의 화질을 얻지못할 수 있으므로 100~75% 사이의 품질을 권장한다.
GIF: 몇개 이미지를 묶어 움직임을 표현한다. 컬러(8bit)로 제한적이다.
PNG: 24 비트 색상을 사용 가능하며 고품질 이미지를 표현할 수 있고, 웹 사이트에는 알파 채널이라고 불리는 투명 기능 때문에 이미지의 백그라운드 투명도를 조절할 수 있다.
JPEG: 사진을 저장하는 표준 형식으로 사람의 눈이 인식할 수 있는 색상만 나믹고 나머지를 제거하는 방식의 기술로 고해상도 이미지를 크게 압축한 파일로 저장할 수 있다.
JPEG 2000: JPEG 단점을 보완하려고 개발 되었고, 새로운 방식으로 이미지 압축률을 높이고 무손실 압축 및 투명기능, 애니메이션 기능을 지원한다. 사파리를 제외한 대부분 브라우저에서 지원하지 않는다.
WebP: 손실 압축 방식을 사용하는 구글의 프로그램이다. JPEG 이미지 형식을 대체하기 위해 웹 사이트 트래픽 감소, 로딩 속도 단축을 목적으로 한다.
초기 렌더링시에 Ajax 통신으로 받은 데이러를 화면에 그리게 되면 렌더링이 끝난 후 데이터를 받아 다사ㅣ 화면에 그리므로 체감 속도를 느리게 한다. 초기 렌더링 시에 마크업 전체를 서버에서 보내는 방식으로 개발하면 체감 속도를 높일 수 있고 그 후 사용자의 행동이 있을 때 Ajax 요청을 실행해서 데이터를 받은 다음 화면을 그리게한다.
CDN은 사용자에게 효울적으로 컨텐츠를 제공하기 위해 여러 지역에 걸쳐 분산된 우베 서버의 집합체로 사용자가 요청했을 때 고객의 네트워크에서 가장 가까운 서버를 측정하여 선택하기 때문에 가장 빠른 응답시간의 서버가 선택된다.
마크업 최적화의 목표는 빈 페이지가 한참 있다가 전체 화면이 한꺼번에 나타나는 것이 아니라 영역별로 차츰 렌더링 하게 하는 것이다.
특히 인터넷 익스플로러에서는
태그를 렌더링할 떄 표 안에 이쓴ㄴ 텍스트와 이미지 ㅡㄷㅇ을 모두 파싱할 때까지 화면 표를 그리지 않는다. 반면 파이어폭스에서는 해당 태그가 모두 완료되기 전에 표 안에 있는 각 요소가 보이기 때문에 부분적인 렌더링이 가능하다.또한 태그의 중첩을 최소화 하는 것이 좋다. 전체 태그 개수를 줄이는 것도 중요하지만 중첩된 태그를 최소로 하는 것이 더 중요하다. 전체적으로는 태그의 개수를 줄이고 부분적으로는 중첩된 태그를 최소화해 간결하게 디자인하는 것이 렌더링 속도를 높이는 방법이다.
callback: 타겟 element가 교차되었을 때 실행할 함수로 entries(IntersectionObserverEntry 객체의 리스트로 배열 형식으로 반환하기 떄문에 forEach를 사용해서 처리한다.), observer(콜백 함수가 호출되는 IntersectionObserver)를 parameter로 받는다.
IntersectionObserver의 callback 함수를 통해 생성된 객체의 배열의 속성은 다음과 같다.
options