캐러셀 슬라이드의 이미지가 느리게 로딩되면서 슬라이드의 레이아웃이 깨지는 현상이 해결되지 않고 있었다.
priority
true 인 경우 높은 우선순위 및 사전 로드되는 이미지로 간주되며, lazy loading이 비활성화 된다.
placeholder
이미지가 로드되는 동안 blur, empty 등의 값으로 자리를 표시하는 속성이다. 동적 이미지의 졍우 base64로 인코딩된 이미지를 blurDataURL을 통해 Image 태그에 제공해야 한다.
처음에는 위의 속성들을 통해 레이아웃의 변경을 막고, 대체 이미지를 통해 사용성을 개선해보려고 시도했다.
그러나 결과는 달라지지 않았다.
browser 컴포넌트는 각 컨텐츠의 열림 상태를 통해 화면에 렌더링 되도록 설계해 놓았다.
export default function Desktop() {
//...
return (
//...
{APPList.map((app) => (
isOpenApp[app] && <Browser
key={`${app} browser`}
//...
/>
))}
//...
)
}
isOpenApp[app] === false
인 경우 browser 컴포넌트는 DOM에서 삭제된다.
carousel slide는 browser 컴포넌트 안에서 다음과 같은 모습으로 존재 한다.
// Browser.tsx
export default function Browser() {
//...
const slideRef = useRef<HTMLDivElement>(null);
const slideBoundary = slideRef.current;
return (
//...
<div ref={slideRef}>
<CarouserlSlide images={data.images} boundary={slideBoundary} />
</div>
//...
)
}
// CarouselSlide.tsx
export default function CarouselSlide() {
const [size, setSize] = useState({ w: 500, h: 308 });
// useEffect
// ResizeObserver callback 내부에서 size 값 업데이트
setSize({
w: width,
h: height,
});
return (
//...
{images.map((image,i) => (
<Image
key={i+image}
src={image}
width={size.w}
height={size.h}
/>
))}
//...
)
}
size의 기본값을 주어서 priority={true}
를 통한 사전 로딩을 기대해 봤으나 최초 1회에는 무조건 이미지가 늦게 뜨고 있었다.
처음부터 원인은 얼추 파악하고 있었다 이미지가 최초 1회 늦게 로딩되는 이유는 carousel slide의 부모인 browser 자체가 특정 상태에만 DOM 트리에 추가되기 때문이다. 로딩을 진행할 대상이 아니니 next에서 제공하는 도구들로 해결하기에는 근본적으로 맞지 않는 방법인 것이다.
그럼에도 next에서 제공하는 도구들을 통해 다른 컴포넌트를 수정하지 않고, 해결할 수는 없을까 해서 여러 시도와 고민을 했었다. 하지만 나의 portfolio 프로젝트가 ssg나 ssr에 적합하지 않은 설계였기 때문에 결국 browser의 open, close 방식을 손보기로 했다.
기존 browser 컴포넌트는 close 시에 DOM 트리에서 삭제되고 있었기에 최초 1회 open에는 이미지의 로딩을 사용자가 기다려야 했다.
스켈레톤 ui를 통해 사용성으 높여 해결해 볼까 했지만 현재 portfolio에서 보여줄 프로젝트의 개수가 많지 않기 때문에 이후 배포 방식을 바꾸거나 프로젝트의 개수가 많이 증가하기 전까지는 안보이는 곳에서 미리 로딩을 시켜놓는 방법을 사용하기로 했다.
기존 Browser는 isOpen === true
일때 나타나도록 코드를 짰다면 이제는 isOpen === false
일때 Browser가 viewport 아래로 내려가도록 만드는 것이다.
이를 위해서 나는 다음과 같이 코드를 작성했다.
isOpen state를 Browser에 props로 전달
isOpen이 false일 때 적용될 tailwind css를 변수로 만들어 적용
//Browser.tsx
export default function Browser({isOpen, isHidden}: {
isOpen: boolean;
isHidden: boolean;
}) {
const {x,y,w,h} = browserConfig;
// 기존 숨김 스타일을 사용하고 싶어서 삼항 조건식에 isOpen만 추가했다
const browserHiddenStyle = isHidden || !isOpen ? "scale-0 -translate-x-1/2" : "";
return (
<div
className={browserHiddenStyle + " absolute "}
style={{
left: isHidden || !isOpen ? "50%" : x,
top: isHidden || !isOpen ? "100%" : y,
width: w,
height: h,
}}
aria-disabled={!isOpen} // 설정된 요소와 해당 요소의 포커스 가능한 모든 하위 항목이 비활성화 상태임을 나타내는 속성
>
{//...}
</div>
)
}
이렇게 내가 고민하면 이미지 로딩에 관한 문제를 해결했다. 꽤 많은 타협을 통해 간단하게 해결한 터라 추후에 해당 코드를 수정해야 하지만 현재 상황에서는 충분한 조치라 생각한다.
다른 프로젝트에서는 조금 더 정석적인 방법을 통해 이미지 최적화나 사용성 개선 등의 문제를 해결해 보려고 한다.