textarea text 높이 따라 자동으로 높이 조절하기
with Tailwind css
이 글은 비교적 동적 스타일 적용이 번거로운 tailwind css를 사용하는 과정에서
textarea의 높이를 자동으로 조절하는 방법에 대해 다루고 있습니다.
tailwind css가 아니라면 이것보다 더 편리한 다른 방법도 있을 것 같습니다만,
우선 해당 조건에서 실행되어야만 하는 상황이기에 최선을 다해 방법을 찾아보았습니다.
이점 참고하시기 바랍니다.
onChange 이벤트 리스너를 이용해
scrollHeight를 textarea.style.height에 직접 적용하는 방법
위와 같이 적용 한 후 콘솔로그로 높이를 확인해보면 이렇게 event.target.scrollHeight가 정상적으로 확인됩니다.
그리고 text 높이에 맞춰서 길이도 자동으로 늘어났습니다.
🚨 높이가 줄어들지 않는 문제점 발생 🚨
하지만 이렇게 text를 지워도 계속해서 event.target.scrollHeight가 108로 찍히는걸 볼 수 있습니다.
늘어나는 것은 잘 체크 되지만 줄어드는것은 체크가 되지 않는 상태입니다.
event.target.scrollHeight는 textarea의 모든 내용의 높이를 포함한 전체 높이를 나타낸다고 합니다.
그래서 event.target.clientHeight는 textarea의 실제 컨텐츠가 표시되는 높이를 나타낸다고하니 바꿔보겠습니다.
역시나 길이가 변하지 않고 그대로 있습니다.
overflow-hidden을 적용하여 스크롤이 생기지 않는 상태로 텍스트가 입력되고 있습니다.
그래서 다른 방법을 검색을 해보니 useRef를 이용한 방식이 있었습니다.
useRef를 이용해
scrollHeight를 textarea.style.height에 직접 적용하는 방법
useRef로 입력되는 text를 체크해서 높이값을 지정해 줄 수 있습니다.
그리고 submit 됐을 때 textarea의 value를 리셋시켜주기 위해 추가적으로 setState를 사용해서 값을 저장하고
submit handler에서 setState를 리셋 시켜주는 과정을 추가해줍니다.
이렇게하면 textarea의 내용을 submit하고 textarea를 리셋하는 것은 물론,
textarea의 길이가 늘어나고 줄어드는 것까지 작동하는 것을 볼 수 있습니다.
🚨붙여넣기한 텍스트 인식 오류 발생🚨
하지만 여전히 해결되지 않은 다른 문제가 있습니다.
위의 이미지를 보면 그냥 텍스트를 입력하는 것은 길이가 바로 변하지만 복사한 텍스트를 붙여넣기 할 경우는
바로 적용이 되지 않아 다시 한번 입력하는 동작을 해야만 높이가 변하는 문제가 있습니다.
그리고 이렇게 드레그를 해서 텍스트를 삭제하는 경우에도 마찬가지로 바로 반영되지 않고
한번 더 입력하는 동작을 해야만 높이가 제대로 반영되었습니다.
🚨 일정 범위 이상 작성해야 하단 여백이 적용되는 문제 🚨
그리고 마지막줄의 하단 여백에 차이가 있죠?
글자를 입력하는 과정에서 여백이 없다가 생겨나면 사용자 입장에서 시각적으로 불편함을 느낄 수 있습니다.
그렇기 때문에 사소한 부분이라고 생각될지라도 수정하는 것이 좋습니다.
이러한 특징은 useRef를 사용해 text의 길이를 계산하기 때문에 발생하는 문제였습니다.
다시 onChenge와 event.target.scrollHeight를 사용하는 방식으로 돌아왔습니다.
다시 onChange 이벤트 리스너를 이용해
scrollHeight를 textarea.style.height에 직접 적용하는 방법으로 돌아와서
useRef를 사용했을 때와 달리 이번에는 붙여넣기를 해도 바로 높이가 반영됩니다.
하지만 높이가 줄어드는것은 여전히 반영이 안됩니다.
이렇게 줄어드는 것이 반영이 안되는 이유를 찾아보았습니다.
이 문제를 해결하기 위해서는 우선 scrollHeight 와 clientHeight에 대해 알아야합니다.
이 둘의 차이점은 무엇일까?
scrollHeight은 scroll의 유무와 상관없이 컨텐츠 요소와 패딩을 포함한 전체 높이를 나타냅니다.
clientHeight은 scroll이 생긴 상태에서 컨텐츠가 보여지는 영역 내의 요소와 패딩의 높이를 나타냅니다.
scrollHeight은 보여지지 않는 부분까지 전체를 포함한다면,
clientHeight단에서 보여지는, 실제로 유저에게 보여지는 영역의 높이를 나타냅니다.
자 다시 돌아와서, 왜 높이가 줄어들지 않고 그대로 일까요?
현재 scrollHeight를 높이값으로 적용시키고 있습니다.
이때 이전의 컨텐츠 높이값이 그대로 적용되어 텍스트를 지워도 높이가 변하지 않는 것입니다.
그럼 줄어드는 높이가 반영 안되는 경우 어떻게 해야 할까요?
임의로 높이값을 리셋시켜주면 리셋한 상태에서 컨텐츠의 높이를 다시 측정할테니 계속해서 최신의 높이로 바뀌겠죠?
event.target.style.height = 'auto';
이렇게 기본 높이값을 auto로 지정해서 리셋시켜보겠습니다.
이렇게하면 이제 높이가 정상적으로 줄어드는 것이 보입니다.
자 이제 높이가 늘어나고 줄어드는 문제는 해결했습니다.
하지만 다른 문제가 하나 더 있습니다.
🚨 일정 범위 이상 작성해야 하단 여백이 적용되는 문제 🚨
글자 아래의 여백을 보시면 "글자 아래 여백"까지만 쳤을 때는 여백이 없다가 "을"까지 쳤을 때 갑자기 여백이 생깁니다.
현재 textarea에 padding bottom을 주었는데 이부분이 제대로 반영이 안되는 것 같습니다.
개발자 도구에서 element로 textarea를 찍어서 실제로 padding bottom이 잘 작동하는지 확인해 보겠습니다.
pb-2라고 된 부분이 보입니다.(tailwind css) padding은 잘 적용되어있습니다.
그런데 글자를 쓰고 지울 때마다 변하는 부분이 있었습니다.
글자가 변경될 때마다 높이가 깜빡이는 것을 확인할 수 있었습니다.
즉 글자가 일정범위를 넘어가지 않으면 줄이 바뀌어도 높이값이 바로 반영이 안되었던 것입니다.
그래서 padding이 적용이 되어도 높이 값이 잘못 적용되어 패딩이 안보였던거죠.
그럼 왜 높이가 바로 적용되지 않고 격차가 발생하는지 알아보겠습니다.
[ scrollHeight와 clientHeight 그리고 스크롤 ]
아까전 scrollHeight와 clientHeight에 대해 잠깐 얘기했었습니다.
지금 콘솔에 scrollHeight 그리고 clientHeight를 찍어보면
event.target.style.height가 scrollHeight 값이 아닌 clientHeight값과 일치하는 것을 볼 수 있습니다.
여기서 다시 글자를 추가로 입력하면 scrollHeight와 clientHeight의 값이 같아지면서 event.target.style.height가 반영 됩니다.
이러한 현상은 scrollHeight의 특성 때문에 발생합니다.
- clientHeight: 스크롤이 있는 경우, 스크롤바를 제외한 표시된 내용의 높이를 나타냅니다. 즉, 스크롤이 생긴 상태에서 보여지는 영역의 높이를 의미합니다.
- scrollHeight: 스크롤이 없는 경우, 텍스트 컨텐츠 전체의 높이를 나타냅니다. 스크롤이 없을 때에도 모든 내용의 높이를 포함합니다.
scrollHeight 값은 항상 clientHeight 값보다 크거나 같습니다.
그리고 clientHeight보다 scrollHeight 값이 클 경우 보이지 않는 영역이 발생하게 됩니다.
그래서 실제로 보여지는 영역이 clientHeight로 고정되어 style.height 값이 clientHeight의 높이로 반영됩니다.
그 후 scrollHeight과 clientHeight의 높이 값이 같아지며 스크롤이 사라지게되는데,
이때 scrollHeight의 값이 정상적으로 style.height에 적용되게됩니다.
따라서, 스크롤이 있는 경우에는 clientHeight가 적용되고, 스크롤이 없는 경우에는 scrollHeight가 적용되는 것 입니다.
스크롤이 생기는 시점에 따라 높이값이 달라지고, 그에 따라 여백이 보였다가 안보였다가 하는거죠.
요약하자면, 스크롤이 있는 경우에는 clientHeight가 적용되고, 스크롤이 없는 경우에는 scrollHeight가 적용됩니다.
따라서 스크롤 유무에 따라 event.target.style.height에 적용되는 값이 달라집니다.
[ 해결방법 ]
이러한 문제점을 해결하기 위해서 scrollHeight와 clientHeight의 값을 비교하여
scrollHeight값이 더 클 경우 style.height의 값을 무조건 scrollHeight값이 되도록 조건을 추가해줍니다.
그리고 스크롤이 없는 경우에도 scrollHeight이 적용되도록 한번 더 event.target.style.height에 scrollHeight값을 적용시켜줍니다.
아래와 같이 작성하면 중복되는 코드가 발생합니다.
하지만 둘 중 하나라도 지울 경우 clientHeight가 적용되는 현상이 발생합니다.
코드를 통해서 적용되는 원리를 다시 설명하겠습니다.
첫 번째 라인에서 textarea.style.height = 'auto' 을 사용하여 textarea의 높이를 콘텐츠에 맞게 자동으로 조절합니다.
그러나 이후에 if문을 통해 스크롤이 생기는 경우에만 scrollHeight 값을 다시 textarea의 높이로 설정하도록 하였습니다.
따라서 스크롤이 생기는 경우에 scrollHeight 값을 적용합니다.
그리고 두 번째 textarea.style.height = ${textarea.scrollHeight}px은 if문과 관계 없이 항상 실행되는 코드입니다.
따라서 스크롤이 생기던, 생기지 않던 항상 해당 라인이 실행되어 scrollHeight 값을 textarea의 높이로 설정하게 됩니다.
이로 인해 중복된 코드가 두 번 들어가는 상황이 발생합니다.
스크롤의 뮤우와 관계없이 모든 조건에서 scrollHeight를 최우선으로 적용하기 위해 부득이하게 중복되는 코드를 사용했습니다.
이렇게 하면 아래와 같이 clientHeight와 scrollHeight가 같은 값으로 적용되면서
글자수에 상관없이 scrollHeight가 계속 적용됩니다.
이렇게 해서 최종적으로 구현된 모습입니다.
복사한 텍스트를 붙여넣어도 바로 높이가 변경되고 반대로 삭제해도 높이가 바로 줄어듭니다.
텍스트의 길이와 상관없이 하단 여백이 일정하게 유지 되는 것도 볼 수 있습니다.
이번 글은 분량에 비해 텍스트가 많아 간단하게 다시 요약해 보겠습니다.
[ 체크 포인트 ]
1. textarea에서 content를 체크하는 방법
2. 스크롤 유무에 따른 content 높이 차이
1. textarea에서 content를 체크하는 방법
onChange와 useRef
onChange : 붙여넣기한 텍스트와 드레그로 삭제한 텍스트 바로 반영 됨
useRef : 붙여넣기하거나 드레그 삭제를 할 경우 바로 반영 안됨
2. 스크롤 유무에 따른 content 높이 차이
scrollHeight와 clientHeight
scrollHeight: 스크롤의 유무와 상관없이 컨텐츠 전체 영역의 높이 값
clientHeight: 스크롤이 생성되었을 때 보여지는 영역의 높이 값
참고 문서
배운점
익숙하게 사용하는 scrollHeight와 clientHeight이기 때문에 쉽게 생각하고 코드를 작성했습니다.
하지만 별거 아니라고 생각했던 차이가 기능에 영향을 주고 있었습니다.
이번에 기능을 구현하면서 html과 css에 대한 중요성을 다시한번 느꼈습니다.
각각의 특성에 따라 예상치 못한 결과가 발생할 수 있음을 배웠고,
구글링을 통해 찾은 방법으로 시도해보는 것도 도움이 되었지만
결국 문서들을 읽으며 직접 특성에 대해 분석하고 해결 방안을 모색했던 것이
정확하게 원하는 결과를 얻는 가장 빠른 방법이었음을 깨달았습니다.
다른 사람이 작성한 코드가 꼭 나에게 적합한 코드는 아니기에 기능이 작동하는지 그 결과에만 초점을 맞춰서 코드를 우겨넣기보다는 차분히 분석하고 판단하는 연습이 필요하다고 느꼈습니다.
혹시 더 좋은 방법이 있으시다면, 혹은 잘못된 부분을 발견 하셨다면 댓글로 알려주시면 반영하겠습니다.
'Language > CSS' 카테고리의 다른 글
[CSS] Tailwind CSS 분석 + 실제로 프로젝트에 적용해보며 느낀점 (0) | 2023.11.21 |
---|---|
CSS-in-JS Library | styled-components란? ( + 직접 사용해본 후 느낀점 ) (0) | 2023.11.16 |
CSS in CSS | CSS전처리기 Sass(SCSS) + 직접 사용해보고 느낀점 (1) | 2023.04.23 |
CSS3 flexible box layout (0) | 2022.05.16 |
CSS display 속성 (0) | 2022.05.08 |