문제

Next.js에서 display를 비롯한 스타일링이 제대로 작동하지 않았다. 그 이유는 무엇일까?

Untitled

해결 방법

이 역시 고질적인 next/image에 대한 이슈였다.

기본적으로 next/image에서는 제대로 된 스타일링 기능을 보장해주지 않았다.

따라서 이를 해결하는 방법은, 상위 컴포넌트를 컨테이너처럼 씌워, 해당 이미지를 스타일링하는 방법이었다.

따라서, 다음과 같이 ImageContainer을 만든 후, display 등 이미지를 스타일링하였다.

import * as React from 'react';
import NextImage from 'next/image';
import styled from '@emotion/styled';
import { css, Interpolation, Theme } from '@emotion/react';

export interface ImageContainerProps {
  loader?: string;
  src: string;
  alt: string;
  width?: string | number;
  height?: string | number;
  margin?: string | number;
  padding?: string | number;
  position?:
    | undefined
    | 'static'
    | 'relative'
    | 'absolute'
    | 'fixed'
    | 'sticky';
  placeholder?: 'blur' | 'empty';
  blurDataUrl?: string;
  sizes?: string;
  objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
  layout?: 'intrinsic' | 'fixed' | 'fill' | 'responsive';
  isCircle?: boolean;
  css?: Interpolation<Theme>;
}

const StyledImageContainer = styled.div`
  overflow: hidden;
  ${({
    width,
    height,
    margin,
    padding,
    position,
    isCircle,
  }: Partial<ImageContainerProps>) => css`
    ${position ? `position: ${position};` : ''}
    width: ${typeof width === 'string' ? width : `${width}px`};
    height: ${typeof height === 'string' ? height : `${height}px`};
    padding: ${typeof padding === 'string' ? padding : `${padding}px`};
    margin: ${typeof margin === 'string' ? margin : `${margin}px`};
    border-radius: ${isCircle ? '50%' : 0};
  `}
`;

const ImageContainer: React.FC<ImageContainerProps> = ({
  src,
  alt,
  width = 40,
  height = 40,
  margin = 0,
  padding = 0,
  position = undefined,
  placeholder = 'empty',
  isCircle = false,
  objectFit = 'cover',
  layout = 'intrinsic',
  sizes = '100vw',
  ...props
}) => {
  return (
    <StyledImageContainer
      {...props}
      width={width}
      height={height}
      margin={margin}
      padding={padding}
      isCircle={isCircle}
      position={position}
    >
      <NextImage
        src={src}
        alt={alt}
        width="100%"
        height="100%"
        placeholder={placeholder}
        layout={layout}
        sizes={layout === 'fill' || layout === 'responsive' ? sizes : undefined}
        objectFit={objectFit}
      />
    </StyledImageContainer>
  );
};

export default ImageContainer;

즉, css 적인 요소는 위의 요소에 위임하고, 나머지 요소들은 NextImage에 위임하는 꼴이다.

결과적으로 어떻게 동작할까?

<div>
  {Array.from(new Array(20), (_, k) => k).map((i) => (
    <ImageContainer
      key={i}
      isCircle
      src={`https://picsum.photos/${i + 1}00`}
      alt="사진 테스트"
      css={{ display: 'inline-block' }}
    />
  ))}
</div>

결과

호출할 때 전달한 css Prop이 옵션 값에 따라 잘 동작한다!

Untitled

참고 자료