반응형으로 말줄임 CSS + 더보기 버튼 구현하기

Jiseong·2024년 5월 21일
0

javascript

목록 보기
2/2
post-thumbnail

😀 Intro

디자인 요구사항을 모두 만족하면서 구현하기가 생각보다 까다로웠다.
3분이면 될줄 알았지만 며칠동안.. 구현했다.ㅠㅠ

🎨 디자인 요구사항

  1. 3줄이 넘어가면 말줄임 처리
  2. 더보기 버튼이 오른쪽 아래에 위치

요구사항도 정말 간단하다.

😆 3줄 이상일 경우 말줄임 처리

<div className="line-clamp-3">
  <p ref={commentRef}>
    {comment}
  </p>
</div>

끝. ㅋㅋ

tailwind를 사용하기 때문에 line-clamp-3 클래스로 간단하게 구현가능하다.

css를 자세히 들여다보면 아래와 같다.

.line-clamp-3 {
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
}

🔍 3줄이 넘어가는지 어떻게 판단할까?

3줄이 넘어가는 경우만 더보기 버튼을 노출시켜야하기 때문에,
3줄이 넘어가는지 js로 알 수 있어야한다.

속임수가 필요하다.

  1. 말줄임을 한 상태의 높이를 알아내기
  2. 말줄임을 하지 않은 원본 상태의 높이를 알아내기
  3. 두 높이를 비교해 높이가 다르다면 3줄이 넘어간다고 판단!

1. 말줄임을 한 상태의 높이를 알아내기

<div className="line-clamp-3">
  <p ref={commentRef}>
    {comment}
  </p>
</div>

useRef를 사용해 commentRef.current.clientHeight로 알아내면된다.

2. 말줄임을 하지 않은 원본 상태의 높이를 알아내기

<>
  <div className="line-clamp-3">
    <p ref={commentRef}>
      {comment}
    </p>
  </div>
  <div className="overflow-hidden h-0">
    <p ref={originalCommentRef}>{comment}</p>
  </div>
</>

comment를 감싸는 div태그에 h-0, overflow-hidden class를 부여했다.
이러면 originalCommentRef는 말줄임 처리되지 않은 상태의 높이를 가지며,
화면에는 보이지 않게 될것이다.

3. 두 높이를 비교하고 더보기 버튼 노출

const [isEllipsed, setIsEllipsed] = useState(false);
const commentRef = useRef<HTMLParagraphElement>(null);
const originalCommentRef = useRef<HTMLParagraphElement>(null);

useEffect(() => {
  if (!originalCommentRef.current || !commentRef.current) return;
  const { clientHeight: originalHeight } = originalCommentRef.current;
  const { clientHeight: commentHeight } = commentRef.current;
  setIsEllipsed(originalHeight !== commentHeight);
}, []);

말줄임 여부를 isEllipsed 상태로 저장한다.
isEllipsed가 true 일때만 노출시키면 되겠다!

<>
  <div className="line-clamp-3">
    <p ref={commentRef}>
      {comment}
    </p>
    {isEllipsed && 
      <button>더보기</button>
    }
  </div>
  <div className="overflow-hidden h-0">
    <p ref={originalCommentRef}>{comment}</p>
  </div>
</>

하지만 이렇게<p/>태그 밑에 렌더링한다면 line-clamp-3에 의해서 숨김처림 된다.

🔍 어떻게 더보기 버튼을 말줄임 표시 바로 뒤에 배치할까?

float

css float 속성을 활용해야한다!

<>
  <div className="line-clamp-3">
    {isEllipsed && 
      <button className="float-right">더보기</button>
    }
    <p ref={commentRef}>
      {comment}
    </p>

  </div>
  <div className="overflow-hidden h-0">
    <p ref={originalCommentRef}>{comment}</p>
  </div>
</>

comment보다 앞쪽에 렌더링 시키고, float-right 속성을 부여해주면 comment의 오른쪽에 배치된다!

margin을 준 뒤 아래쪽으로 내려보자

<button className="float-right mt-[42px]">더보기</button>

42px을 준 이유는 comment의 line-height가 21px이기 때문이다.

오른쪽에 여백이 생겼다.

shape-outside:border-box로 해결해 주면 끝

<button className="float-right mt-[42px] [shape-outside:border-box]">더보기</button>

🧐 반응형 기능도 추가해보자

  useEffect(() => {
    const handleMoreButton = () => {
      if (!originalCommentRef.current || !commentRef.current) return;
      const { clientHeight: originalHeight } = originalCommentRef.current;
      const { clientHeight: commentHeight } = commentRef.current;
      setIsEllipsed(originalHeight !== commentHeight);
    };

    handleMoreButton();
    window.addEventListener('resize', handleMoreButton);
    return () => window.addEventListener('resize', handleMoreButton);
  }, []);

handleMoreButton 함수로 만들어주고, resize 이벤트를 추가해주면 끝이다!

1개의 댓글

comment-user-thumbnail
2025년 2월 5일

혹시 사파리에서 잘 동작하시나요..?ㅎㅎ ㅠㅠ

답글 달기

관련 채용 정보