이번 포스팅에서는 Next에서 어떻게 이미지 파일을 불러오는지 알아보고자 한다.
Next에서 이미지는 다양한 방법으로 불러와 화면에 보일 수 있다. 일단 크게 두가지 종류가 존재한다.
- public 폴더에 이미지 파일을 저장하고 상대경로로 불러온다.
- 배포된 이미지 파일을 그대로 가져온다.
이 두 가지 방법으로 이미지 파일을 불러올 수 있는데 이제 이것을 어떻게 화면에 표현하느냐가 문제가 될 것이다. ㅎㅎ
const Images: NextPage = () => {
return (
<main>
<hr style={{ margin: '32px 0' }} />
<h1>img tag</h1>
<figure>
<img
src="https://example.com/example.jpg"
alt="example"
width={500}
height={100}
loading="lazy"/>
<figcaption>example img</figcaption>
</figure>
</main>
)
}
이렇게 img
태그를 직접 이용할 수 있으나, 네트워크 페이지를 확인해 보면 미리 example.jpg를 가져오며 용량 그대로 가져옴을 알 수 있다. 만약 이 때 loading
속성에 lazy
를 주면 화면에 보이지 않다가 이미지가 화면에 나타날 때에 네트워크 로딩을 해 준다.
Next/image
를 사용하게 되면 webp
형식으로 이미지를 받아올 뿐만 아니라 사용하는 메모리가 훨씬 줄어들게 된다.
또한 지정하고 싶은 이미지의 가로, 세로 크기를 쉽게 정할 수 있다.
import type { NextPage } from 'next';
import Image from 'next/image';
import LegacyImage from 'next/legacy/image';
import example from '../../public/example.png'
const Images: NextPage = () => {
return (
<main>
<h1>next/image</h1>
<figure>
<Image
src={example}
alt="v13 image"
width={500}
height={100}
/>
<figcaption>v13 image</figcaption>
</figure>
</main>
)
}
속성에 quality
를 준다면 이미지 용량을 얼마나 최적화시킬 것인지에 대하여 정할 수 있다. (기본값은 75)
그리고 속성에 임의로 추가하지 않았지만 lazy loading
속성은 기본적으로 들어가 있다.
만약, placeholder
로 blur를 지정하면 화면이 로딩되는 동안에는 블러 이미지가 자동으로 적용된다. (단 개발환경에서는 확인 불가능)
이는 public 폴더에 이미지를 지정해두고, static하게 이미지를 import 시켰기 때문에 Next 입장에서는 이미지의 너비, 높이, 색에 대하여 미리 알고 있어서 만들고자 하는 이미지에 대하여 대응할 수 있기 때문이다.
그렇기 때문에 주의해야 하는 점 중에 하나는 src
를 string링크 형식으로 넘겨주기보다는 외부에서 import하여 가져온 것으로 표현을 해 주어야 한다.
그럼 이미지를 static하게 불러오지 않고, 외부 배포된 링크로 가져온다면 어떻게 될까?
<figure>
<Image
src="https://inflearn-nextjs.vercel.app/example.jpg"
alt="v13 image"
width={500}
height={100}
/>
<figcaption>v13 image</figcaption>
</figure>
정적인 이미지 같은 경우에는 빌드타임에 그 크기가 어떻게 되는지 알고 있지만 외부 소스를 통해 가져온 이미지 같은 경우에는 크기를 알 방도가 없다. 그렇기 때문에 외부에서 이미지를 가져오는 경우에는 꼭 크기와 높이를 지정해준 이후 넘겨주어야 한다.
항상 외부에서 가져오는 페이지에 대한 높이와 너비를 잘 알고 있지 못할 수도 있다. 그럴 때에는 어떻게 대응해야 할까?
<figure style={{ position: 'relative', width: '500px', height: '100px' }}>
<Image src="https://inflearn-nextjs.vercel.app/example.jpg" alt="v13 fill"
fill
style={{ objectFit: 'cover' }}
/>
</figure>
그럴 때에는 외부(부모) 컨테이너에 대하여 크기를 정해 두고 fill
이라는 속성을 배정한다.
그럴 때에는 허용된 도메인의 이미지 링크만 가져올 수 있도록 NextJs가 막아둔 것이므로 해당 링크의 가이드에 따라서 next.config.js
파일을 새로 작성할 필요가 있다.
module.exports = {
images: {
domains: ['assets.acme.com'],
},
}
하지만 이 부분은 wildcard pattern 매칭과 엄격한 프로토콜 관리에 유용하지는 않다. 최근에 추천하는 것은 아래와 같다.
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/account123/**',
},
],
},
}
위와 같이 작성한다면 https://example.com/account123/
링크로 이동하는 것이고, 만약 일치하지 않는다면 400에러를 발생시킨다.
아니면 요렇게 작성해도 된다!
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**.example.com',
},
],
},
}
이미지에 대한 URL을 string으로 확인할 수 있으며 src
, width
, quality
라는 파라미터가 필요하다.
로더의 예시를 확인해보자.
import Image from 'next/image'
const myLoader = ({ src, width, quality }) => {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
const MyImage = (props) => {
return (
<Image
loader={myLoader}
src="me.png"
alt="Picture of the author"
width={500}
height={500}
/>
)
}
이렇게 로더 함수를 직접 작성하여도 되고, loaderFile
을 next.config.js파일에 작성하여도 된다.
module.exports = {
images: {
loader: 'custom',
loaderFile: './my/image/loader.js',
},
}
width
와 height
를 정확히 명시하는 것 대신 부모 요소를 채우게끔 이미지를 불러올 수 있다.
parent에는 다음 요소가 꼭 명시되어 있어야 한다.
absolute
특성을 가지고 있다.이미지는 부모 요소를 기준으로 stretch되기 때문에, 컨텐츠를 부모 요소에 딱 맞게 만들고 싶다면 object-fit: "contain"
요소를 넣어주자.
기호에 따라 ojbect-fit: "cover"
, overflow: "hidden"
을 사용할 수 있다.
size는 서로 다른 중단점에서 이미지가 어떻게 넓어지는지에 대한 정보를 제공할 수 있다.
가로 세로 길이를 특정하기 어렵지만 브라우저 크기에 대하여 그에 대한 크기 정보가 제공되어야 할 때가 있을 때 sizes는 그 해결점을 제공한다.
아무 것도 설정하지 않는다면
<Image sizes="210px" />
코드를 이렇게 작성하게 되면 이미지 출력 크기는 210px로 고정된다. 예시 코드를 조금 더 살펴보자.
import Image from 'next/image'
const Example = () => (
<div className="grid-element">
<Image
src="/example.png"
fill
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
33vw"
/>
</div>
)
이미지 크기가 큰 것이 필요하지 않는데 33vw
를 지정하지 않으면 3배 더 큰 이미지를 어쩔 수 없이 다운로드 받게 되고, 결론적으로 이미지의 용량은 크기의 제곱이므로 9배 큰 용량을 낭비하게 될 수 있다.
하지만 이렇게 sizes의 값으로 33vw를 전달해줌으로써 작은 크기의 파일을 쓸데없이 큰 크기로 다운받지 않아도 되는 장점이 있는 것이다.
이미지 크기에 대한 최적화를 진행한다. 1 ~ 100 사이의 숫자로 결정할 수 있고, 100을 설정하게 되면 가장 좋은 퀄리티로 이미지 크기를 최적화 진행한다. 75가 기본값이다.
만약 priority가 true로 설정되어 있다면, 가장 먼저 로드(preload)를 진행한다. Lazy loading은 사용할 수 없게 된다.
placeholder는 이미지가 로딩될 때 보여지는 화면이다. 기본값으로는 empty
가 설정되어 있다. empty일 때에는 빈 공간이 존재하고, 주로 blur
라는 값을 많이 사용하는데 이미지 파일의 배경 DATA를 생성해둔다.
이외에도 다양한 props들이 여전히 존재한다. 더욱 자세한 내용을 알고 싶다면 아래 링크를 참고하자.
https://nextjs.org/docs/api-reference/next/image#advanced-props