개발지식

[HTML/CSS] 긴 글 말줄임 + 더보기 버튼 만들기

재리재히 2022. 12. 10. 14:36

가끔 이런 더보기 디자인이 오면 구현의 어려움이 있었습니다.

일단 내가 원하는 곳에서 텍스트를 자르는 방법이 없었고 줄 단위로만 가능했던 터라

디자이너와 협의 후 더보기 버튼을 아래로 내리거나 아예 없애는 방식을 제안했을 거예요.

오늘은 위와 같은 디자인을 개발하는 방법을 알아보도록 하겠습니다.

 

 

더보기 UI 구현하기

ui는 다음 사이트를 참고했습니다.

https://jsbin.com/bebuwuhibe/1/edit?html,css,output

 

JS Bin

Sample of the bin:

jsbin.com

 

일단 간단하게 html과 scss를 다음과 같이 적어주면.

아래와 같은 UI가 나올 것입니다.

<div class="more-article">
   <div class="more-article__wrapper">
      <p class="more-article__text">
        끓는 방황하여도, 그들의 밥을 힘차게 원대하고, 가치를 같이, 것이다. 전인
        방황하였으며, 열락의 생생하며, 하여도 사막이다. 사랑의 풍부하게 천고에
        어디 만물은 피는 그러므로 소금이라 있다.
      </p>
   </div>
</div>
.more-article {
  width: 200px;
  border: 1px solid #000;
  padding: 15px;

  &__wrapper {
    display: flex;
    width: 100%;
  }

  &__text {
    width: 100%;
    text-overflow: ellipsis;
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    white-space: unset;
    -webkit-line-clamp: 2;

    &::before {
      content: "더보기";
      float: right;
      display: flex;
      align-items: flex-end;
      height: 100%;
      shape-outside: inset(calc(100% - 10px) 0 0 0);
      color: #999999;
    }
  }
}

 

위의 css를 보시면

-webkit-line-clampd에 따라 한 줄부터 여러 줄까지 설정이 가능해요

근데 3줄 이상 시에만 더보기가 나와야 한다면 기능을 추가해줘야 합니다

 

더보기 추가 기능 구현하기 (with Vue)

글자 수를 세는 방법 등의 다양한 방법이 있지만 정확도를 위해 말줄임이 된 컨테이너 높이와

말줄임을 적용하지 않은 컨테이너 높이를 비교해주도록 할게요

 

편의성을 위해 vue 컴포넌트로 제작했습니다.

<div class="more-article">
    <div class="more-article__wrapper">
        <p
            class="more-article__text"
            ref="more_article"
            v-html="text"
            :class="{ 'not-more': !isMore }"
            :style="{ '-webkit-line-clamp': line }"
        ></p>
    </div>
    <!--원본 텍스트 비교-->
    <p class="more-article__origin" ref="origin_article">{{ text }}</p>
</div>

더보기 버튼이 없는 UI는 not-more이라는 클래스가 있을 거예요.

-webkit-line-clampd는 UI마다 다 다를 태니 변수로 지정해줍니다.

 

export default {
    props: {
        text: {
            type: String,
            default: null,
        },
        line: {
            type: Number,
            default: 1,
        },
    },
    watch: {
        text() {
            this.compareHeight();
        },
    },
    data() {
        return {
            isMore: false,
        };
    },
    methods: {
        compareHeight() {
            let moreText = this.$refs.more_article.clientHeight;
            let originText = this.$refs.origin_article.clientHeight;

            this.isMore = moreText !== originText;
        },
    },
    mounted() {
        this.compareHeight();
    },
};

말줄임 컨테이너와 원본 컨테이너 높이 값이 같을 때 not-more이라는 클래스가 활성화됩니다.

text 도 부모에게서 받아옵니다.

 

.more-article {
   width: 100%;
   position: relative;
   overflow: hidden;
    
    &__text {
       ...
        &.not-more {
            &:before {
                display: none;
            }
        }
    }

    &__origin {
        visibility: hidden;
        opacity: 0;
        position: absolute;
        right: -99990px;
        height: fit-content;
        width: 100%;
    }
}

원본 컨테이너는 display:none 하면 돔을 선택할 수 없기 때문에 띄워서 화면 밖으로 보내버리는 방법을 사용합니다.

그래서 부모 클래스에게 position값과 overflow값을 설정하고 임시로 넓이를 줬던 값을 100%로 변경해줍니다.

 

 

아쉬운 점

이런저런 방법을 사용해봤으나 반응형이 지원되지 않았습니다 ㅜㅜ