고정 폭과 높이 내에 줄임표가 추가 된 브라우저 간 여러 줄 텍스트 오버플로


178

이해하기 쉽도록이 질문에 대한 이미지를 만들었습니다.

<div>고정 너비와 여러 줄로 줄임표를 만들 수 있습니까?

텍스트 오버플로

여기저기서 jQuery 플러그인을 시도했지만 원하는 플러그인을 찾을 수 없습니다. 어떤 추천? 아이디어?





2
2016 년 중반에 이것을 찾고있는 사람에게는 짧은 대답은 다음과 같습니다. 아니오 우아하고 크로스 브라우저, CSS만으로는 불가능합니다. 가장 근접한 것으로 제공된 솔루션 ( codepen.io/romanrudenko/pen/ymHFh )은 Goldbergian이므로 모든 신체가 아프고 여전히 추악합니다.
konrad

답변:


91

간단한 기본 아이디어입니다.

다음 마크 업으로 테스트하고있었습니다.

<div id="fos">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nisi ligula, dapibus a volutpat sit amet, mattis et dui. Nunc porttitor accumsan orci id luctus. Phasellus ipsum metus, tincidunt non rhoncus id, dictum a lectus. Nam sed ipsum a lacus sodales eleifend. Vestibulum lorem felis, rhoncus elementum vestibulum eget, dictum ut velit. Nullam venenatis, elit in suscipit imperdiet, orci purus posuere mauris, quis adipiscing ipsum urna ac quam.</p>  
</div>

그리고 CSS :

#fos { width: 300px; height: 190px; overflow: hidden; }
#fos p { padding: 10px; margin: 0; }

이 jQuery를 적용하면 원하는 결과를 얻을 수 있습니다.

var $p = $('#fos p');
var divh = $('#fos').height();
while ($p.outerHeight() > divh) {
    $p.text(function (index, text) {
        return text.replace(/\W*\s(\S)*$/, '...');
    });
}

원하는 크기에 도달 할 때까지 텍스트의 마지막 단어를 반복적으로 제거하려고 시도합니다. 오버플로로 인해 : hidden; 프로세스는 보이지 않으며 JS가 꺼져도 결과는 "시각적으로 정확"합니다 (물론 "..."없이).

이것을 서버 측에서 적절한 잘림과 결합하면 (작은 오버 헤드 만 남음) 빨리 실행됩니다. :).

다시 말하지만 이것은 완벽한 솔루션이 아니라 아이디어 일뿐입니다.

업데이트 : jsFiddle 데모가 추가되었습니다 .


1
훌륭한 솔루션 @bazmegakapa ...하지만 내 사건에 맞게 조정하는 데 문제가 있습니다. 나는 여러 가지고 li각각의에 내부가있는 .block.block h2와 나는 이것을 적용 할 필요가 h2내부 .block하지만 작업에 가져올 수 없습니다. 둘 이상 있으면 다른 것이 .block h2있습니까?
Alex

1
내 경우는 떠난다 단지 3. 분명히 내 컨테이너 선에 비해 작았가 있었어야 할 때 텍스트의 2 라인을 height*3몇 픽셀. 쉬운 수정 은 간단히 몇 픽셀을 추가하는 것입니다divh
Lukas LT

3
텍스트에 매우 긴 단어가 하나만 포함되어 있기 때문에이 스크립트 에서 무한 루프에 대한 나쁜 경험이 있었 으므로 대체 정규 표현식이 일치하지 않았습니다. 이를 방지하려면 다음 코드를 while줄 바로 뒤에 추가하십시오 .if(!$p.text().match(/\W*\s(\S)*$/)) break;
KrisWebDev

1
이 경우 문제가되지는 않지만 DOM을 업데이트하고 레이아웃을 반복적으로 확인하는 것은 속도가 느려질 수 있으므로 나쁜 생각입니다. 이를 완화하기 위해 이진 검색과 비슷한 방법을 사용할 수 있습니다. 텍스트 블록이 이미 맞는지 테스트하고, 그렇지 않으면 텍스트를 단어 나 문자로 나누고 범위를 정의합니다 (낮은 = 1 단어 / 문자, 상위 = 모든 단어 / 문자) , while ((upper-lower)>1) {let middle=((lower+upper)/2)|0 /*|0 is quick floor*/; if (test(words.slice(0,middle)+'...')) {lower=middle;} else {upper=middle;}}. @KrisWebDev에서 알 수 있듯이 거대한 단어 하나를 확인하고 싶을 것입니다.
Chinoto Vokro 2019 년

1
이 솔루션은 훌륭합니다. 필자의 경우 전체 텍스트 값을 반응 적으로자를 수 있도록 원본 텍스트를 추적해야합니다. 따라서 페이지가로드되면 원본 텍스트를 변수에 저장 하고이 논리를 실행하기 전에 원래 텍스트 값으로 요소를 '새로 고침'해야합니다. 디 바운스를 추가하면 훌륭하게 작동합니다.
besseddrest

68

jQuery.dotdotdot 플러그인을 사용해보십시오 .

$(".ellipsis").dotdotdot();

11
그걸 어떻게 발음하겠습니까? 도트 도트 도트 도트?
JackAce

58
CSS로 해결해야 할 문제를 해결하기 위해 600 줄 이상의 js를 사용하는 것이 정말 짜증납니다
Jethro Larson

나는 그것을 시도했고 잘 작동하고있다. 수락 된 답변이어야합니다
AbdelHady

1
글꼴이나 다른 외부 리소스가 HTML 레이아웃에 영향을 줄 수 있으므로 $ (document) .ready ()가 아닌 window.loaded 이벤트를 사용해야합니다. 이러한 리소스가로드되기 전에 dotdotdot가 실행되면 텍스트가 올바른 위치에서 잘리지 않습니다.
sboisse

10
이 도구는 상용 도구이며 단일 사이트의 경우 5 달러, 여러 사이트의 경우 35 달러입니다. 라이센싱은 고통입니다. 나는 그것이 자유롭고 즉시 통합 가능하다고 생각했다.
유전자 b.

29

"라인 클램핑"을위한 자바 스크립트 라이브러리

"라인 클램핑"은 "다중 라인 블록의 줄임표"또는 "수직 줄임표"라고도합니다.


github.com/BeSite/jQuery.dotdotdot


github.com/josephschmitt/Clamp.js


내가 아직 조사하지 않은 몇 가지 더 있습니다 :


라인 클램핑을위한 CSS 솔루션

CSS 솔루션이 있지만 -webkit-line-clamp브라우저 지원이 좋지 않은 가장 간단한 용도 가 있습니다 . jsfiddle.net/AdrienBe/jthu55v7/에서 라이브 데모보기

많은 사람들이 CSS 만 사용하여 이런 일을하기 위해 많은 노력을 기울였습니다. 그것에 관한 기사와 질문을보십시오 :


내가 추천하는 것

간단하게 유지하십시오. 이 기능에 많은 시간을 할애하지 않는 한 가장 단순하고 테스트 된 솔루션 : 간단한 CSS 또는 잘 테스트 된 자바 스크립트 라이브러리로 이동하십시오.

공상 / 복잡한 / 높은 주문을 받아서 무언가를 위해 가십시오 & 당신은 도로의 아래에 이것을위한 가격을 지불 할 것입니다.


다른 사람들이하는 일

에어 비앤비처럼 희미 해지는 것이 좋은 해결책 일 수 있습니다. 아마도 기본 jQuery와 결합 된 기본 CSS 일 것입니다. 실제로 CSSTricks 의이 솔루션 과 매우 유사합니다.

AirBnb "더 읽기"솔루션

아, 그리고 당신이 디자인 영감을 찾으면 :


6

HTML에는 그러한 기능이 없으므로 매우 실망 스럽습니다.

이 문제를 해결하기 위해 라이브러리 를 개발했습니다 .

  • 여러 줄로 된 텍스트 오버플로 : 줄임표
  • 이를 지원하지 않는 기술이 포함 된 여러 줄 텍스트 : SVG, Canvas 등
  • 예를 들어 SVG 텍스트, HTML 렌더링 및 PDF 내보내기에서 정확히 동일한 줄 바꿈이 있어야합니다.

스크린 샷, 튜토리얼 및 dowload 링크는 내 사이트 를 확인하십시오 .


"DB 연결 설정 오류"... Github에서 다른 모든 사람들과 마찬가지로 프로젝트를 호스팅하고 싶을 수도 있습니다. 아마도 여러분과 지역 사회를 위해 더 좋을 것입니다 :)
Adrien Be

@AdrienGithub에 있습니다 : github.com/rossille/jstext 그리고 당신은 맞습니다. github가 내 웹 사이트보다 더 안정적입니다. github 페이지를 주요 링크로 설정했습니다
Samuel Rossille

@SamuelRossille 좋은 소식, 빠른 업데이트에 감사드립니다!
Adrien Be

4

bažmegakapa의 솔루션을 기반으로 한 순수 JS 솔루션 및 요소의 행보다 작은 높이 / 최대 높이를 제공하려는 사람들을 설명하기 위해 일부 정리.

  var truncationEl = document.getElementById('truncation-test');
  function calculateTruncation(el) {
    var text;
    while(el.clientHeight < el.scrollHeight) {
      text = el.innerHTML.trim();
      if(text.split(' ').length <= 1) {
        break;
      }
      el.innerHTML = text.replace(/\W*\s(\S)*$/, '...');
    }
  }

  calculateTruncation(truncationEl);

이것은 매우 비효율적 인 코드입니다. 그런데 "while"모양을 사용하면 무한 루프의 잠재적 인 버그가 발생합니다.
WebBrother

4

잘 작동하는 솔루션이 있지만 대신 타원을 사용하여 그라디언트를 사용합니다. 장점은 JavaScript 계산을 수행 할 필요가 없으며 테이블 셀을 포함하여 가변 너비 컨테이너에서 작동한다는 것입니다. 두 개의 추가 div를 사용하지만 구현하기가 매우 쉽습니다.

http://salzerdesign.com/blog/?p=453

편집 : 죄송합니다. 링크가 충분하지 않다는 것을 몰랐습니다. 해결책은 텍스트 주위에 div를 배치하고 div 스타일을 지정하여 오버플로를 제어하는 ​​것입니다. div 안에 CSS 또는 이미지 (이전 IE의 경우)를 사용하여 만들 수있는 "페이드"그라디언트로 다른 div를 넣으십시오. 그라디언트는 표 셀의 투명에서 배경색으로 진행되며 줄임표보다 약간 넓습니다. 텍스트가 길고 넘치면 "fade"div 아래로 이동하여 "faded out"으로 보입니다. 텍스트가 짧으면 페이드가 보이지 않으므로 아무런 문제가 없습니다. 두 컨테이너는 컨테이너의 높이를 텍스트 선 높이의 배수로 설정하여 하나 이상의 선이 보이도록 조정할 수 있습니다. "fade"div는 마지막 줄만 덮을 수 있습니다.


SO 링크 전용 답변은 허용되지 않으므로 솔루션의 중요한 부분을 공유하십시오.
kapa

이것의 훌륭한 측면은 텍스트 자체가 잘리지 않기 때문에 사용자가 테이블을 복사하여 붙여 넣을 경우 전체 내용이 나타납니다.
프로토 타입

아주 좋은 개념. 또한 내가 믿는 (방법을 "페이드 아웃")이 문서에서 설명하는 css-tricks.com/line-clampin
아드는 수

4

이를 달성하는 순수한 CSS 방법은 다음과 같습니다. http://www.mobify.com/blog/multiline-ellipsis-in-pure-css/

요약은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

<html>
<head>
<style>
    html, body, p { margin: 0; padding: 0; font-family: sans-serif;}

    .ellipsis {
        overflow: hidden;
        height: 200px;
        line-height: 25px;
        margin: 20px;
        border: 5px solid #AAA; }

    .ellipsis:before {
        content:"";
        float: left;
        width: 5px; height: 200px; }

    .ellipsis > *:first-child {
        float: right;
        width: 100%;
        margin-left: -5px; }        

    .ellipsis:after {
        content: "\02026";  

        box-sizing: content-box;
        -webkit-box-sizing: content-box;
        -moz-box-sizing: content-box;

        float: right; position: relative;
        top: -25px; left: 100%; 
        width: 3em; margin-left: -3em;
        padding-right: 5px;

        text-align: right;

        background: -webkit-gradient(linear, left top, right top,
            from(rgba(255, 255, 255, 0)), to(white), color-stop(50%, white));
        background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);           
        background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
        background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
        background: linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); }
</style>
</head>
<body>
    <div class="ellipsis">
        <div>
            <p>Call me Ishmael.....</p> 
        </div>
    </div>
</body>
</html>

4

-webkit-line-clamp속성을 사용할 수 있습니다 div.

-webkit-line-clamp: <integer>즉, 내용을 자르기 전에 최대 줄 수를 설정 한 다음 (…)마지막 줄 끝에 줄임표를 표시합니다 .

div {
  width: 205px;
  height: 40px;
  background-color: gainsboro;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  
  /* <integer> values */
  -webkit-line-clamp: 2;
}
<div>This is a multi-lines text block, some lines inside the div, while some outside</div>


2
왜 누군가가이 대답을 하향 조정했는지 확실하지 않습니다. 2020 년 3 월 현재 브라우저 지원은 꽤 괜찮습니다-95 % caniuse.com/#search=line-clamp
Yulian

2

핀치에 사용할 수있는 바닐라 JavaScript 솔루션은 다음과 같습니다.

// @param 1 = element containing text to truncate
// @param 2 = the maximum number of lines to show
function limitLines(el, nLines) {
  var nHeight,
    el2 = el.cloneNode(true);
  // Create clone to determine line height
  el2.style.position = 'absolute';
  el2.style.top = '0';
  el2.style.width = '10%';
  el2.style.overflow = 'hidden';
  el2.style.visibility = 'hidden';
  el2.style.whiteSpace = 'nowrap';
  el.parentNode.appendChild(el2);
  nHeight = (el2.clientHeight+2)*nLines; // Add 2 pixels of slack
  // Clean up
  el.parentNode.removeChild(el2);
  el2 = null;
  // Truncate until desired nLines reached
  if (el.clientHeight > nHeight) {
    var i = 0,
      imax = nLines * 35;
    while (el.clientHeight > nHeight) {
      el.innerHTML = el.textContent.slice(0, -2) + '&hellip;';
      ++i;
      // Prevent infinite loop in "print" media query caused by
      // Bootstrap 3 CSS: a[href]:after { content:" (" attr(href) ")"; }
      if (i===imax) break;
    }
  }
}

limitLines(document.getElementById('target'), 7);
#test {
  width: 320px;
  font-size: 18px;
}
<div id="test">
  <p>Paragraph 1</p>
  <p id="target">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Paragraph 3</p>
</div>

아래의 코드 펜에서 놀 수 있습니다. CSS 패널에서 글꼴 크기를 변경하고 HTML 패널에서 약간의 수정 (예 : 공간을 추가)하여 결과를 업데이트하십시오. 글꼴 크기에 관계없이 가운데 단락은 항상 limitLines ()에 전달 된 두 번째 매개 변수의 줄 수로 잘 려야합니다.

코드 펜 : http://codepen.io/thdoan/pen/BoXbEK


2

편집 : Shave 를 가로 질러 주어진 최대 높이를 기반으로 여러 줄 텍스트 잘림을 수행하는 JS 플러그인입니다. 이진 검색을 사용하여 최적의 중단 점을 찾습니다. 조사 할만한 가치가 있습니다.


원래 답변 :

이 문제에 대한 바닐라 JS 솔루션을 생각해 내야했습니다. 내가 작업 한 경우에는 긴 제품 이름을 제한된 너비와 두 줄로 맞추어야했습니다. 필요한 경우 줄임표로 잘립니다.

나는 다양한 SO 게시물의 답변을 사용하여 내 요구에 맞는 것을 요리했습니다. 전략은 다음과 같습니다.

  1. 원하는 글꼴 크기에 대한 글꼴 변형의 평균 문자 너비를 계산하십시오.
  2. 컨테이너의 너비를 계산
  3. 컨테이너의 한 줄에 맞는 문자 수를 계산하십시오.
  4. 줄에 맞는 문자 수와 텍스트를 줄 바꿈해야하는 줄 수를 기준으로 문자열을자를 문자 수를 계산하십시오.
  5. 이전 계산을 기반으로 입력 텍스트를 자르고 (줄임표로 추가 된 추가 문자를 고려하여) 끝에 "..."를 추가하십시오.

코드 샘플 :

/**
 * Helper to get the average width of a character in px
 * NOTE: Ensure this is used only AFTER font files are loaded (after page load)
 * @param {DOM element} parentElement 
 * @param {string} fontSize 
 */
function getAverageCharacterWidth(parentElement, fontSize) {
    var textSample = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()";
    parentElement = parentElement || document.body;
    fontSize = fontSize || "1rem";
    var div = document.createElement('div');
    div.style.width = "auto";
    div.style.height = "auto";
    div.style.fontSize = fontSize;
    div.style.whiteSpace = "nowrap";
    div.style.position = "absolute";
    div.innerHTML = textSample;
    parentElement.appendChild(div);

    var pixels = Math.ceil((div.clientWidth + 1) / textSample.length);
    parentElement.removeChild(div);
    return pixels;
}

/**
 * Helper to truncate text to fit into a given width over a specified number of lines
 * @param {string} text Text to truncate
 * @param {string} oneChar Average width of one character in px
 * @param {number} pxWidth Width of the container (adjusted for padding)
 * @param {number} lineCount Number of lines to span over
 * @param {number} pad Adjust this to ensure optimum fit in containers. Use a negative value to Increase length of truncation, positive values to decrease it.
 */
function truncateTextForDisplay(text, oneChar, pxWidth, lineCount, pad) {
    var ellipsisPadding = isNaN(pad) ? 0 : pad;
    var charsPerLine = Math.floor(pxWidth / oneChar);
    var allowedCount = (charsPerLine * (lineCount)) - ellipsisPadding;
    return text.substr(0, allowedCount) + "...";
}


//SAMPLE USAGE:
var rawContainer = document.getElementById("raw");
var clipContainer1 = document.getElementById("clip-container-1");
var clipContainer2 = document.getElementById("clip-container-2");

//Get the text to be truncated
var text=rawContainer.innerHTML;

//Find the average width of a character
//Note: Ideally, call getAverageCharacterWidth only once and reuse the value for the same font and font size as this is an expensive DOM operation
var oneChar = getAverageCharacterWidth();

//Get the container width
var pxWidth = clipContainer1.clientWidth;

//Number of lines to span over
var lineCount = 2;

//Truncate without padding
clipContainer1.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount);

//Truncate with negative padding value to adjust for particular font and font size
clipContainer2.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount,-10);
.container{
  display: inline-block;
  width: 200px;
  overflow: hidden;
  height: auto;
  border: 1px dotted black;
  padding: 10px;
  }
<h4>Untruncated</h4>
<div id="raw" class="container">
This is super long text which needs to be clipped to the correct length with ellipsis spanning over two lines
</div>
<h4>Truncated</h4>
<div id="clip-container-1" class="container">
</div>
<h4>Truncated with Padding Tweak</h4>
<div id="clip-container-2" class="container">
</div>

추신:

  1. 잘림이 한 줄에 있어야하는 경우 텍스트 오버플로를 사용하는 순수한 CSS 방법 : 줄임표가 더 깔끔합니다.
  2. 너비가 고정되지 않은 글꼴은 다른 문자의 너비가 다르기 때문에 잘림이 너무 일찍 또는 너무 늦게 발생할 수 있습니다. pad 매개 변수를 사용하면 경우에 따라이를 완화하는 데 도움이되지만 바보는 아닙니다. :)
  3. 노트북을 가져온 후 원래 게시물에 대한 링크 및 참조를 추가합니다 (이력 필요).

PPS : 이것이 @DanMan 및 @ st.never가 제안한 접근 방식과 매우 유사하다는 것을 깨달았습니다. 구현 예제는 코드 스 니펫을 확인하십시오.


2

매우 간단한 자바 스크립트 솔루션. div는 fe로 스타일을 지정해야합니다.

.croppedTexts { 
  max-height: 32px;
  overflow: hidden;
}

그리고 JS :

var list = document.body.getElementsByClassName("croppedTexts");
for (var i = 0; i < list.length; i++) {
  cropTextToFit(list[i]);
}

function cropTextToFit (o) {
  var lastIndex;
  var txt = o.innerHTML;
  if (!o.title) o.title = txt;

  while (o.scrollHeight > o.clientHeight) {
    lastIndex = txt.lastIndexOf(" ");
    if (lastIndex == -1) return;
    txt = txt.substring(0, lastIndex);
    o.innerHTML = txt + "…";
  }
}

1

질문에 대한 정확한 대답은 아니지만 매우 유사한 작업을 시도 할 때이 페이지를 보았지만 간단한 생략 대신 "더보기"에 대한 링크를 추가하려고합니다. 컨테이너에 넘친 텍스트에 "추가"링크를 추가하는 jQuery 함수입니다. 개인적으로 나는 이것을 Bootstrap과 함께 사용하고 있지만 물론 작동하지 않습니다.

더 많은 스크린 샷 예

사용하려면 다음과 같이 텍스트를 컨테이너에 넣으십시오.

<div class="more-less">
    <div class="more-block">
        <p>The long text goes in here</p>
    </div>
</div>

다음 jQuery 함수가 추가되면 adjustheight 값보다 큰 div가 잘리고 "More"링크가 추가됩니다.

$(function(){
    var adjustheight = 60;
    var moreText = '+ More';
    var lessText = '- Less';
    $(".more-less .more-block").each(function(){
        if ($(this).height() > adjustheight){
            $(this).css('height', adjustheight).css('overflow', 'hidden');
            $(this).parent(".more-less").append
                ('<a style="cursor:pointer" class="adjust">' + moreText + '</a>');
        }
    });
    $(".adjust").click(function() {
        if ($(this).prev().css('overflow') == 'hidden')
        {
            $(this).prev().css('height', 'auto').css('overflow', 'visible');
            $(this).text(lessText);
        }
        else {
            $(this).prev().css('height', adjustheight).css('overflow', 'hidden');
            $(this).text(moreText);
        }
    });
});

이를 기반으로하지만 업데이트 됨 : http://shakenandstirredweb.com/240/jquery-moreless-text


<sigh> 아마이 질문에 대한 정확한 답변이 아니기 때문에 누군가가 이것을 줄인다고 생각했습니다. 그럼에도 불구하고, 나는 다른 곳에서는이 정보를 얻을 수 없었기 때문에 누군가가 유용하게 사용할 수 있기를 바랍니다.
Andy Beverley

1

언급 된 dotdotdot jQuery 플러그인 은 각도와 잘 작동합니다.

(function (angular) {
angular.module('app')
    .directive('appEllipsis', [
        "$log", "$timeout", function ($log, $timeout) {
            return {
                restrict: 'A',
                scope: false,
                link: function (scope, element, attrs) {

                    // let the angular data binding run first
                    $timeout(function() {
                        element.dotdotdot({
                            watch: "window"
                        });
                    });
                }
            }

        }
    ]);
})(window.angular);

해당 마크 업은 다음과 같습니다.

<p app-ellipsis>{{ selectedItem.Description }}</p>

1

순수 JS 데모 (jQuery 및 'while'루프 없음)

여러 줄 줄임표 문제의 해결책을 검색했을 때 jQuery가 없으면 좋은 것이 없다는 것에 놀랐습니다. 또한 'while'루프를 기반으로 한 몇 가지 솔루션이 있지만 무한 루프에 들어갈 가능성으로 인해 효과적이고 위험하지 않다고 생각합니다. 그래서 나는이 코드를 썼다 :

function ellipsizeTextBox(el) {
  if (el.scrollHeight <= el.offsetHeight) {
    return;
  }

  let wordArray = el.innerHTML.split(' ');
  const wordsLength = wordArray.length;
  let activeWord;
  let activePhrase;
  let isEllipsed = false;

  for (let i = 0; i < wordsLength; i++) {
    if (el.scrollHeight > el.offsetHeight) {
      activeWord = wordArray.pop();
      el.innerHTML = activePhrase = wordArray.join(' ');
    } else {
      break;
    }
  }

  let charsArray = activeWord.split('');
  const charsLength = charsArray.length;

  for (let i = 0; i < charsLength; i++) {
    if (el.scrollHeight > el.offsetHeight) {
      charsArray.pop();
      el.innerHTML = activePhrase + ' ' + charsArray.join('')  + '...';
      isEllipsed = true;
    } else {
      break;
    }
  }

  if (!isEllipsed) {
    activePhrase = el.innerHTML;

    let phraseArr = activePhrase.split('');
    phraseArr = phraseArr.slice(0, phraseArr.length - 3)
    el.innerHTML = phraseArr.join('') + '...';
  }
}

let el = document.getElementById('ellipsed');

ellipsizeTextBox(el);

1

아마도 늦었지만 SCSS를 사용하면 다음과 같은 함수를 선언 할 수 있습니다.

@mixin clamp-text($lines, $line-height) {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: $lines;
  line-height: $line-height;
  max-height: unquote('#{$line-height*$lines}em');

  @-moz-document url-prefix() {
    position: relative;
    height: unquote('#{$line-height*$lines}em');

    &::after {
      content: '';
      text-align: right;
      position: absolute;
      bottom: 0;
      right: 0;
      width: 30%;
      height: unquote('#{$line-height}em');
      background: linear-gradient(
        to right,
        rgba(255, 255, 255, 0),
        rgba(255, 255, 255, 1) 50%
      );
    }
  }
}

그리고 그것을 다음과 같이 사용하십시오 :

.foo {
    @include clamp-text(1, 1.4);
}

텍스트를 한 줄로 자르고 텍스트가 1.4 줄임을 알 수 있습니다. 예상되는 결과물은 크롬 ...은 끝에서 렌더링 하고 FF는 끝에서 시원한 페이드 로 렌더링됩니다 .

Firefox

여기에 이미지 설명을 입력하십시오

크롬

여기에 이미지 설명을 입력하십시오


1

Adrien Be의 답변 에서이 짧은 CSS 전용 솔루션을 찾았습니다 .

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

2020 년 3 월 현재 브라우저 지원95.3 % 이며 IE 및 Opera Mini에서는 지원되지 않습니다. Chrome, Safari, Firefox 및 Edge에서 작동합니다.


0

Courier와 같은 고정 너비 글꼴이 없으면 (현재?) 할 수 없습니다. 고정 폭 글꼴을 사용하면 모든 문자가 동일한 가로 공간을 차지하므로 문자 수를 세고 결과를 ems 또는 exs의 현재 글꼴 크기와 곱할 수 있습니다. 그런 다음 한 줄에 몇 개의 문자가 들어가는 지 테스트 한 다음 구분해야합니다.

또는 고정되지 않은 글꼴의 경우 가능한 모든 문자 (예 : i = 2px, m = 5px)에 대한 매핑을 만든 다음 수학을 수행 할 수 있습니다. 그래도 많은 추악한 작업.


0

@DanMan의 솔루션을 확장하려면 가변 너비 글꼴을 사용하는 경우 평균 글꼴 너비를 사용할 수 있습니다. 여기에는 두 가지 문제가 있습니다. 1) W가 너무 많은 텍스트가 오버플로되고 2) 너무 많은 텍스트가 잘릴 수 있습니다.

또는 최악의 접근 방식을 취하고 문자 "W"의 너비를 사용할 수 있습니다 (가장 넓습니다). 이렇게하면 위의 문제 1은 제거되지만 문제 2는 강화됩니다.

다른 접근 방식은 다음과 같습니다 .div overflow: clip에 그대로두고 줄임표 섹션 (다른 div 또는 이미지)을 추가하십시오.float: right; position: relative; bottom: 0px; (unested)로 추가하십시오. 트릭은 이미지를 텍스트 끝 위에 표시하는 것입니다.

오버플로가 발생한다는 것을 알고있을 때만 이미지를 표시 할 수도 있습니다 (예 : 약 100 자).


무엇입니까 overflow: clip? 그리고 그 CSS로 무엇을 기대할 float것입니까?
kapa

0

이 코드를 사용하면 요소의 높이가 최대 높이 스타일로 제한되는 경우 추가 래퍼 div가 필요하지 않습니다.

// Shorten texts in overflowed paragraphs to emulate Operas text-overflow: -o-ellipsis-lastline
$('.ellipsis-lastline').each(function(i, e) {
    var $e = $(e), original_content = $e.text();
    while (e.scrollHeight > e.clientHeight)
        $e.text($e.text().replace(/\W*\w+\W*$/, '…'));
    $e.attr('data-original-content', original_content);
});

또한 예를 들어 스타일 만 사용하여 표시 할 수있는 데이터 속성에 원본 텍스트를 저장합니다. 마우스 오버시 :

.ellipsis-lastline {
    max-height: 5em;
}
.ellipsis-lastline:before {
    content: attr(data-original-content);
    position: absolute;
    display: none;
}
.ellipsis-lastline:hover:before {
    display: block;
}

1
그것은 종종 무한 루프입니다.
Atadj

0

내 시나리오에서는 위에서 언급 한 기능을 사용할 수 없었으며 글꼴 크기 또는 컨테이너 크기에 관계없이 표시 할 행 수를 함수에 알려 주어야했습니다.

나는의 사용에 대한 내 솔루션을 기반으로 Canvas.measureText의 (AN입니다 whic 방법 HTML5의 설명에 따라 기능) 여기 에서 도미 완전히 크로스 브라우저되지 않도록를.

이 바이올린 에서 어떻게 작동하는지 볼 수 있습니다 .

이것은 코드입니다.

var processTexts = function processTexts($dom) {
    var canvas = processTexts .canvas || (processTexts .canvas = document.createElement("canvas"));

    $dom.find('.block-with-ellipsis').each(function (idx, ctrl) {
        var currentLineAdded = false;
        var $this = $(ctrl);

        var font = $this.css('font-family').split(",")[0]; //This worked for me so far, but it is not always so easy.
        var fontWeight = $(this).css('font-weight');
        var fontSize = $(this).css('font-size');
        var fullFont = fontWeight + " " + fontSize + " " + font;
        // re-use canvas object for better performance
        var context = canvas.getContext("2d");
        context.font = fullFont;

        var widthOfContainer = $this.width();
        var text = $.trim(ctrl.innerHTML);
        var words = text.split(" ");
        var lines = [];
        //Number of lines to span over, this could be calculated/obtained some other way.
        var lineCount = $this.data('line-count');

        var currentLine = words[0];
        var processing = "";

        var isProcessing = true;
        var metrics = context.measureText(text);
        var processingWidth = metrics.width;
        if (processingWidth > widthOfContainer) {
            for (var i = 1; i < words.length && isProcessing; i++) {
                currentLineAdded = false;
                processing = currentLine + " " + words[i];
                metrics = context.measureText(processing);
                processingWidth = metrics.width;
                if (processingWidth <= widthOfContainer) {
                    currentLine = processing;
                } else {
                    if (lines.length < lineCount - 1) {
                        lines.push(currentLine);
                        currentLine = words[i];
                        currentLineAdded = true;
                    } else {
                        processing = currentLine + "...";
                        metrics = context.measureText(processing);
                        processingWidth = metrics.width;
                        if (processingWidth <= widthOfContainer) {
                            currentLine = processing;
                        } else {
                            currentLine = currentLine.slice(0, -3) + "...";
                        }
                        lines.push(currentLine);
                        isProcessing = false;
                        currentLineAdded = true;
                    }
                }
            }
            if (!currentLineAdded)
                lines.push(currentLine);
            ctrl.innerHTML = lines.join(" ");
        }
    });
};

(function () {
    $(document).ready(function () {
        processTexts($(document));
    });
})();

그리고 그것을 사용하는 HTML은 다음과 같습니다.

<div class="block-with-ellipsis" data-line-count="2">
    VERY LONG TEXT THAT I WANT TO BREAK IN LINES. VERY LONG TEXT THAT I WANT TO BREAK IN LINES.
</div>

글꼴 모음을 가져 오는 코드는 다소 간단하며 제 경우에는 효과가 있지만 더 복잡한 시나리오의 경우이 줄을 따라 무언가를 사용해야 할 수도 있습니다 .

또한 필자의 경우 함수에 사용할 줄 수를 알려주고 있지만 컨테이너 크기와 글꼴에 따라 표시 할 줄 수를 계산할 수 있습니다.


0

HTML을 그대로 유지하는 버전을 만들었습니다. jsfiddle 예제

jQuery

function shorten_text_to_parent_size(text_elem) {
  textContainerHeight = text_elem.parent().height();


  while (text_elem.outerHeight(true) > textContainerHeight) {
    text_elem.html(function (index, text) {
      return text.replace(/(?!(<[^>]*>))\W*\s(\S)*$/, '...');
    });

  }
}

$('.ellipsis_multiline').each(function () {
  shorten_text_to_parent_size($(this))
});

CSS

.ellipsis_multiline_box {
  position: relative;
  overflow-y: hidden;
  text-overflow: ellipsis;
}

jsfiddle 예제


0

문제를 해결하는 각도 구성 요소를 작성했습니다. 주어진 텍스트를 범위 요소로 분할합니다. 렌더링 후에는 넘친 모든 요소를 ​​제거하고 마지막으로 보이는 요소 바로 뒤에 줄임표를 배치합니다.

사용 예 :

<app-text-overflow-ellipsis [text]="someText" style="max-height: 50px"></app-text-overflow-ellipsis>

Stackblitz 데모 : https://stackblitz.com/edit/angular-wfdqtd

구성 요소 :

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef, HostListener,
  Input,
  OnChanges,
  ViewChild
} from '@angular/core';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-text-overflow-ellipsis',
  template: `
    <span *ngFor="let word of words; let i = index" [innerHTML]="word + (!endsWithHyphen(i) ? ' ' : '')"></span>
    <span #ellipsis [hidden]="!showEllipsis && !initializing" [class.initializing]="initializing" [innerHTML]="'...' + (initializing ? '&nbsp;' : '')"></span>
  `,
  styles: [`
    :host {
      display: block; 
      position: relative;
    }
    .initializing {
      opacity: 0;
    }
  `
  ]
})

export class TextOverflowEllipsisComponent implements OnChanges {
  @Input()
  text: string;

  showEllipsis: boolean;
  initializing: boolean;

  words: string[];

  @ViewChild('ellipsis')
  ellipsisElement: ElementRef;

  constructor(private element: ElementRef, private cdRef: ChangeDetectorRef) {}

  ngOnChanges(){
    this.init();
  }

  @HostListener('window:resize')
  init(){
    // add space after hyphens
    let text = this.text.replace(/-/g, '- ') ;

    this.words = text.split(' ');
    this.initializing = true;
    this.showEllipsis = false;
    this.cdRef.detectChanges();

    setTimeout(() => {
      this.initializing = false;
      let containerElement = this.element.nativeElement;
      let containerWidth = containerElement.clientWidth;
      let wordElements = (<HTMLElement[]>Array.from(containerElement.childNodes)).filter((element) =>
        element.getBoundingClientRect && element !== this.ellipsisElement.nativeElement
      );
      let lines = this.getLines(wordElements, containerWidth);
      let indexOfLastLine = lines.length - 1;
      let lineHeight = this.deductLineHeight(lines);
      if (!lineHeight) {
        return;
      }
      let indexOfLastVisibleLine = Math.floor(containerElement.clientHeight / lineHeight) - 1;

      if (indexOfLastVisibleLine < indexOfLastLine) {

        // remove overflowing lines
        for (let i = indexOfLastLine; i > indexOfLastVisibleLine; i--) {
          for (let j = 0; j < lines[i].length; j++) {
            this.words.splice(-1, 1);
          }
        }

        // make ellipsis fit into last visible line
        let lastVisibleLine = lines[indexOfLastVisibleLine];
        let indexOfLastWord = lastVisibleLine.length - 1;
        let lastVisibleLineWidth = lastVisibleLine.map(
          (element) => element.getBoundingClientRect().width
        ).reduce(
          (width, sum) => width + sum, 0
        );
        let ellipsisWidth = this.ellipsisElement.nativeElement.getBoundingClientRect().width;
        for (let i = indexOfLastWord; lastVisibleLineWidth + ellipsisWidth >= containerWidth; i--) {
          let wordWidth = lastVisibleLine[i].getBoundingClientRect().width;
          lastVisibleLineWidth -= wordWidth;
          this.words.splice(-1, 1);
        }


        this.showEllipsis = true;
      }
      this.cdRef.detectChanges();

      // delay is to prevent from font loading issues
    }, 1000);

  }

  deductLineHeight(lines: HTMLElement[][]): number {
    try {
      let rect0 = lines[0][0].getBoundingClientRect();
      let y0 = rect0['y'] || rect0['top'] || 0;
      let rect1 = lines[1][0].getBoundingClientRect();
      let y1 = rect1['y'] || rect1['top'] || 0;
      let lineHeight = y1 - y0;
      if (lineHeight > 0){
        return lineHeight;
      }
    } catch (e) {}

    return null;
  }

  getLines(nodes: HTMLElement[], clientWidth: number): HTMLElement[][] {
    let lines = [];
    let currentLine = [];
    let currentLineWidth = 0;

    nodes.forEach((node) => {
      if (!node.getBoundingClientRect){
        return;
      }

      let nodeWidth = node.getBoundingClientRect().width;
      if (currentLineWidth + nodeWidth > clientWidth){
        lines.push(currentLine);
        currentLine = [];
        currentLineWidth = 0;
      }
      currentLine.push(node);
      currentLineWidth += nodeWidth;
    });
    lines.push(currentLine);

    return lines;
  }

  endsWithHyphen(index: number): boolean {
    let length = this.words[index].length;
    return this.words[index][length - 1] === '-' && this.words[index + 1] && this.words[index + 1][0];
  }
}

0

더 빠른 알고리즘으로 다른 라이브러리를 만들었습니다. 확인해주십시오:

https://github.com/i-ahmed-biz/fast-ellipsis

바우어를 사용하여 설치하려면 :

bower install fast-ellipsis

npm을 사용하여 설치하려면 다음을 수행하십시오.

npm install fast-ellipsis 

당신이 즐기시기 바랍니다!


-2

이것이 당신이 찾고있는 것인지 확실하지 않으면 높이 대신 최소 높이를 사용합니다.

    <div id="content" style="min-height:10px;width:190px;background:lightblue;">
    <?php 
        function truncate($text,$numb) {
            // source: www.kigoobe.com, please keep this if you are using the function
            $text = html_entity_decode($text, ENT_QUOTES);
            if (strlen($text) > $numb) {
                $text = substr($text, 0, $numb);
                $etc = "..."; 
                $text = $text.$etc;
            } 
            $text = htmlentities($text, ENT_QUOTES);
            return $text;
        }
        echo truncate("this is a multi-lines text block, some lines inside the div, while some outside", 63);
    ?>
    </div>

4
문제는 코드에서 숫자 63입니다. 숫자를 알면 모든 것이 쉬워집니다. 자르기 기능만이 코드 로이 작업을 수행합니다. 그러나 숫자를 아는 방법은 무엇입니까? 즉, 텍스트가 줄 바꿈되는 위치를 아는 방법은 무엇입니까? 이 질문에 대답 할 수 있다면, 문제는 "1, 숫자 계산; 2, 잘라 내기"의 논리로 간단히 해결할 수 있습니다
Edward

-3

매우 간단한 기능이 가능합니다.

지령:

  $scope.truncateAlbumName = function (name) {
    if (name.length > 36) {
      return name.slice(0, 34) + "..";
    } else {
      return name;
    }
  };

전망:

<#p>{{truncateAlbumName(album.name)}}<#/p>

3
다른 답변에서 이미 논의했듯이 코드의 문제는 숫자 36입니다. 코드를 특정 컨테이너 너비에 맞게 지정하는 것 외에는 정확하지 않습니다. 고정 너비 글꼴이 아닌 경우 문자 사이에 큰 차이가있을 수 있습니다 . iiiiiiiiiivs를 참조하십시오 MMMMMMMMMM(현재 글꼴은 보이지 않지만 : D).
kapa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.