디자인 요구사항을 모두 만족하면서 구현하기가 생각보다 까다로웠다.
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줄이 넘어가는지 js로 알 수 있어야한다.
속임수가 필요하다.
<div className="line-clamp-3">
<p ref={commentRef}>
{comment}
</p>
</div>
useRef를 사용해 commentRef.current.clientHeight
로 알아내면된다.
<>
<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
는 말줄임 처리되지 않은 상태의 높이를 가지며,
화면에는 보이지 않게 될것이다.
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에 의해서 숨김처림 된다.
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 이벤트를 추가해주면 끝이다!
혹시 사파리에서 잘 동작하시나요..?ㅎㅎ ㅠㅠ