DOM 요소 내부의 텍스트 줄을 어떻게 세나요? 할 수 있습니까?


127

예를 들어 div 내부에 줄을 세는 방법이 있는지 궁금합니다. 다음과 같은 div가 있다고 가정합니다.

<div id="content">hello how are you?</div>

여러 요소에 따라 div에는 1, 2, 4 줄의 텍스트가 포함될 수 있습니다. 스크립트가 알 수있는 방법이 있습니까?

즉, 자동 중단이 DOM에 전혀 표시되지 않습니까?

답변:


89

div의 크기가 콘텐츠에 따라 달라지는 경우 (설명에서 가져온 것으로 가정) 다음을 사용하여 div의 높이를 검색 할 수 있습니다.

var divHeight = document.getElementById('content').offsetHeight;

그리고 글꼴 선 높이로 나눕니다.

document.getElementById('content').style.lineHeight;

또는 명시 적으로 설정되지 않은 경우 줄 높이를 얻으려면 :

var element = document.getElementById('content');
document.defaultView.getComputedStyle(element, null).getPropertyValue("lineHeight");

패딩과 줄간 간격도 고려해야합니다.

편집하다

완전 독립형 테스트, 명시 적으로 라인 높이 설정 :

function countLines() {
   var el = document.getElementById('content');
   var divHeight = el.offsetHeight
   var lineHeight = parseInt(el.style.lineHeight);
   var lines = divHeight / lineHeight;
   alert("Lines: " + lines);
}
<body onload="countLines();">
  <div id="content" style="width: 80px; line-height: 20px">
    hello how are you? hello how are you? hello how are you? hello how are you?
  </div>
</body>


7
줄 높이가 항상 설정되지 않았을 수 있다는 점을 제외하면 좋은 시작입니다. 요소의 계산 된 스타일에서 가져와야합니다.
Chetan S

다시 생각하면 라인 높이가 항상 숫자 (또는 픽셀) 일 필요는 없습니다. 따라서 코드가 이에 의존하고 CSS 규칙이이를 허용하는 경우 라인 높이를 픽셀 단위로 설정해야합니다.
Chetan S

6
@Chetan-텍스트 크기를 픽셀 단위로 설정하는 것은 일반적으로 나쁜 것으로 간주됩니다. astahost.com/Sizes-Webdesign-Em-Vs-Px-t8926.html
annakata

6
이것은 내 예와 같이 가장 간단한 경우에만 작동 할 수 있습니다. 내부에 범위, 인라인 블록 요소 등이 있으면 (부모) 글꼴 크기로 간단하게 나누는 것은 쓸모가 없습니다. 그래도 아무것도없는 것보다 낫습니다. 감사합니다.
buti-oxa

2
생각 얻기의 더 나은 방법 계산 된 line-height(명시 적으로 설정되지 않도록) 사용하는 것입니다window.getComputedStyle(element, null).getPropertyValue('line-height')
rnevius

20

한 가지 해결책은 스크립트를 사용하여 모든 단어를 span 태그로 묶는 것입니다. 그런 다음 주어진 스팬 태그의 Y 치수가 직전 태그의 Y 치수보다 작 으면 줄 바꿈이 발생합니다.


영리한! 어떻게하나요? 나는 당신이 (예제에서와 같이) 텍스트 전용 단락을 가정한다고 생각합니다. 이 제한을 염두에 두지 않았지만 단락 안에 다른 것이있을 때 스크립트가 충돌하지 않는 한 괜찮을 수 있습니다.
buti-oxa

1
다시 생각하면이 방법은 선에 세로로 정렬 된 범위가있는 경우 실패합니다. 따라서 텍스트 전용 단락도 잘못 계산 될 수 있습니다.
buti-oxa

내 div에는 텍스트와 이미지가 있습니다. 운 좋게도 이미지는 절대 위치에 있으므로 제외 될 것이라고 생각합니다. : D 어쨌든 나는 당신이 제안한 것과 같은 코드를 사용했지만 스팬이 아닌 div로 +1을 해주셔서 감사합니다!
Albert Renshaw 2013 년

20

요소의 줄 수를 계산하는 데 사용할 수있는 getClientRects () 함수를 확인하십시오 . 다음은 사용 방법의 예입니다.

var message_lines = $("#message_container")[0].getClientRects();

자바 스크립트 DOM 객체를 반환합니다. 줄 수는 다음과 같이 알 수 있습니다.

var amount_of_lines = message_lines.length;

각 줄의 높이 등을 반환 할 수 있습니다. 이것을 스크립트에 추가 한 다음 콘솔 로그를 확인하여 수행 할 수있는 모든 작업을 확인하십시오.

console.log("");
console.log("message_lines");
console.log(".............................................");
console.dir(message_lines);
console.log("");

몇 가지 유의해야 할 점은 포함하는 요소가 인라인 인 경우에만 작동하지만 포함하는 인라인 요소를 블록 요소로 둘러 싸서 다음과 같이 너비를 제어 할 수 있습니다.

<div style="width:300px;" id="block_message_container">
<div style="display:inline;" id="message_container">
..Text of the post..
</div>
</div>

그런 스타일을 하드 코딩하는 것은 권장하지 않지만. 단지 예를 들기위한 것입니다.


3
이 답변과 다른 getClientRects 기반 답변은 허용 된 답변보다 훨씬 낫습니다
matteo

2
이것은 받아 들여진 대답이어야합니다. 디지털 크리스티 @ 주셔서 감사합니다
Antuan

12

나는 여기와 다른 질문에 대한 답변에 만족하지 않았습니다. 가장 높은 평점 대답은하지 않습니다 padding또는 border계정에, 따라서 분명히 무시 box-sizing뿐만 아니라. 내 대답은 여기와 다른 스레드에서 몇 가지 기술을 결합하여 만족스럽게 작동하는 솔루션을 얻습니다.

완벽하지 않습니다. line-height(예 : normal또는 inherit)에 대해 검색 할 수있는 숫자 값이 없으면 font-size곱하기를 사용합니다 1.2. 다른 사람이 이러한 경우 픽셀 값을 감지하는 신뢰할 수있는 방법을 제안 할 수 있습니다.

그 외에는 내가 던진 대부분의 스타일과 케이스를 올바르게 처리 할 수있었습니다.

놀고 테스트하기위한 jsFiddle . 또한 아래 인라인.

function countLines(target) {
  var style = window.getComputedStyle(target, null);
  var height = parseInt(style.getPropertyValue("height"));
  var font_size = parseInt(style.getPropertyValue("font-size"));
  var line_height = parseInt(style.getPropertyValue("line-height"));
  var box_sizing = style.getPropertyValue("box-sizing");
  
  if(isNaN(line_height)) line_height = font_size * 1.2;
 
  if(box_sizing=='border-box')
  {
    var padding_top = parseInt(style.getPropertyValue("padding-top"));
    var padding_bottom = parseInt(style.getPropertyValue("padding-bottom"));
    var border_top = parseInt(style.getPropertyValue("border-top-width"));
    var border_bottom = parseInt(style.getPropertyValue("border-bottom-width"));
    height = height - padding_top - padding_bottom - border_top - border_bottom
  }
  var lines = Math.ceil(height / line_height);
  alert("Lines: " + lines);
  return lines;
}
countLines(document.getElementById("foo"));
div
{
  padding:100px 0 10% 0;
  background: pink;
  box-sizing: border-box;
  border:30px solid red;
}
<div id="foo">
x<br>
x<br>
x<br>
x<br>
</div>


helpfull 후 ... 여러분 감사
Sinto

좋은 고려 사항이지만 제 경우에는 한 줄 div의 높이가 패딩과 테두리없이 줄 높이보다 1px 이상입니다. 당신의 대답과 @ 전자 info128의 대답 (cloneNode 방법)을 빗질하여 행 높이를 받고 그래서 더 나은 선택이 될 수있다
에릭

8

컨테이너 개체를 복제하고 두 글자를 쓰고 높이를 계산합니다. 이렇게하면 모든 스타일이 적용된 실제 높이, 줄 높이 등이 반환됩니다. 이제 높이 개체 / 문자 크기를 계산합니다. Jquery에서 높이는 패딩, 여백 및 테두리를 능가하며 각 줄의 실제 높이를 계산하는 것이 좋습니다.

other = obj.clone();
other.html('a<br>b').hide().appendTo('body');
size = other.height() / 2;
other.remove();
lines = obj.height() /  size;

각 글자의 높이가 다른 희귀 글꼴을 사용하면 작동하지 않습니다. 그러나 Arial, mono, comics, Verdana 등과 같은 모든 일반 글꼴에서 작동합니다. 글꼴로 테스트하십시오.

예:

<div id="content" style="width: 100px">hello how are you? hello how are you? hello how are you?</div>
<script type="text/javascript">
$(document).ready(function(){

  calculate = function(obj){
    other = obj.clone();
    other.html('a<br>b').hide().appendTo('body');
    size = other.height() / 2;
    other.remove();
    return obj.height() /  size;
  }

  n = calculate($('#content'));
  alert(n + ' lines');
});
</script>

결과: 6 Lines

표준을 벗어나는 드문 기능없이 모든 브라우저에서 작동합니다.

확인 : https://jsfiddle.net/gzceamtr/


우선 제가 찾고 있던 것에 대해 대단히 감사합니다. 계산 기능의 각 줄을 설명해 주시겠습니까? 많은 감사드립니다. SYA :)
LebCit

1
비의 jQuery 대답을 필요로하는 사람들을 위해 : clonecloneNode, hidestyle.visibility = "hidden", html('a<br>b')textContent='a\r\nb', appendTo('body')document.documentElement.appendChild, height()getBoundingClientRect().height
에릭

줄 높이와 div 높이 사이에 1px의 오류가 발생 하므로이 답변을 권장합니다. 이 제프의 대답 @를 결합하면 더 나은 것
에릭

6

jQuery http://jsfiddle.net/EppA2/3/ 를 사용하는 사람들을 위해

function getRows(selector) {
    var height = $(selector).height();
    var line_height = $(selector).css('line-height');
    line_height = parseFloat(line_height)
    var rows = height / line_height;
    return Math.round(rows);
}

jsfiddle.net/EppA2/9은 덜 정확하지만에 따라 더 다양한 브라우저에서 지원 할 수있다
penkovsky

8
jQuery가에서 "normal"을 반환하면 $(selector).css('line-height');해당 함수에서 숫자를 얻지 못합니다.
bafromca 2014

5

지금은 불가능하다고 확신합니다. 그래도 그렇습니다.

IE7의 getClientRects 구현은 내가 원하는 것을 정확히 수행했습니다. IE8 에서이 페이지 를 열고 창 너비를 변경하여 새로 고친 다음 첫 번째 요소의 줄 수가 그에 따라 어떻게 변경되는지 확인하십시오. 해당 페이지의 자바 스크립트 주요 행은 다음과 같습니다.

var rects = elementList[i].getClientRects();
var p = document.createElement('p');
p.appendChild(document.createTextNode('\'' + elementList[i].tagName + '\' element has ' + rects.length + ' line(s).'));

불행히도 Firefox는 항상 요소 당 하나의 클라이언트 사각형을 반환하며 IE8은 이제 동일합니다. (Martin Honnen의 페이지는 IE가 IE 호환보기에서 렌더링하기 때문에 현재 작동합니다. 다른 모드로 플레이하려면 IE8에서 F12를 누르세요.)

이거 슬프네. 다시 한 번 Firefox의 문자 그대로이지만 쓸모없는 사양 구현이 Microsoft의 유용한 사양을 능가하는 것처럼 보입니다. 아니면 새로운 getClientRects가 개발자에게 도움이 될 수있는 상황을 놓치고 있습니까?


2
Mozilla의 element.getClientRects 문서에서 지적했듯이 , 적어도 인라인 요소의 경우 W3C 사양 각 텍스트 줄에 대한 사각형을 생성합니다. 이상적이지는 않지만 적어도 뭔가입니다.
natevw

getClientRects (). length가 올바른 방법입니다. getComputedStyle ()은 "inherit", "normal"및 "auto"와 같은 값을 반환 할 수 있습니다.
Binyamin 2016 년

4

위에서 GuyPaddock의 답변에 따르면 이것은 나를 위해 작동하는 것 같습니다.

function getLinesCount(element) {
  var prevLH = element.style.lineHeight;
  var factor = 1000;
  element.style.lineHeight = factor + 'px';

  var height = element.getBoundingClientRect().height;
  element.style.lineHeight = prevLH;

  return Math.floor(height / factor);
}

여기서 비결은 글꼴을 렌더링하는 방식의 브라우저 / OS 차이를 "삼킬"정도로 줄 높이를 높이는 것입니다.

다양한 스타일과 다른 글꼴 크기 / 패밀리로 확인했습니다. (내 경우에는 중요하지 않았기 때문에) 고려하지 않은 유일한 것은 패딩입니다.


2

아니요, 신뢰할 수 없습니다. 알 수없는 변수가 너무 많습니다.

  1. 어떤 OS (다른 DPI, 글꼴 변형 등)입니까?
  2. 실제로 눈이 멀기 때문에 글꼴 크기가 확대 되었습니까?
  3. 웹킷 브라우저에서는 실제로 텍스트 상자의 크기를 원하는대로 조정할 수 있습니다.

목록은 계속됩니다. 언젠가는 JavaScript로이를 안정적으로 수행 할 수있는 방법이 있기를 바랍니다.하지만 그날이 올 때까지 운이 좋지 않습니다.

나는 이런 종류의 대답을 싫어하고 누군가가 나를 틀렸다는 것을 증명할 수 있기를 바랍니다.


3
렌더링 후 선을 세면 모든 알려지지 않은 것은 관련이 없습니다. 물론 텍스트를 렌더링 할 때 브라우저가 사용하는 줄 수를 "추측"하려고하면 요점이 적용됩니다.
사이먼

확대 및 / 또는 텍스트 크기를 변경하는 사용자 변수는 무시할 수 있습니다. 창 크기 조정 (페이지가로드 된 후) 또는 브라우저에서 텍스트 크기 변경에 맞게 최적화 된 디자인을 가진 사이트를 본 적이 없기 때문에이 특정 질문에서 중요한 요소라고 생각하지 않습니다. 그러나 다른 사람들이 지적한 것처럼 픽셀을 기반으로 한 "추측"에 불과한 신뢰할 수있는 솔루션이 없다는 데 동의합니다.
Kalko 2016 년

2

split ( '\ n'). length 및 줄 바꿈을 얻을 수 있어야합니다.

업데이트 : 이것은 FF / Chrome에서 작동하지만 IE에서는 작동하지 않습니다.

<html>
<head>
<script src="jquery-1.3.2.min.js"></script>
<script>
    $(document).ready(function() {
        var arr = $("div").text().split('\n');
        for (var i = 0; i < arr.length; i++)
            $("div").after(i + '=' + arr[i] + '<br/>');
    });
</script>
</head>
<body>
<div>One
Two
Three</div>
</body>
</html>

1
그것을 시도하고 어떻게 진행되는지 알려주십시오. 나는 냉소적이지 않고 진지하다. 바로이 페이지의 FireBug 콘솔에서이 코드를 사용할 수 있습니다. var the_text = $ ( '. welovestackoverflow p'). text (); var numlines = the_text.split ( "\ n"). length; alert (numlines);
KyleFarris 2009

3
이 놀라움을 주셔서 감사합니다. 가능한지 몰랐지만 이것이 내가 원하는 것은 아닙니다. Jquery는 소스에서 하드 줄 바꿈을 계산하는 것으로 보이며 결과에서 자동 줄 바꿈에 관심이 있습니다. "One Two Three"div의 경우 브라우저가 모든 텍스트를 한 줄에 입력하므로 결과는 1이어야합니다.
buti-oxa

그럼 나는 당신의 질문을 오해했습니다. 그런 다음 계산 된 선 높이를 찾고 싶습니다.
Chad Grant

1

getClientRects같은 클라이언트의 구형을 돌려 당신이 선을 얻으려면, 같은 추적 기능 사용

function getRowRects(element) {
    var rects = [],
        clientRects = element.getClientRects(),
        len = clientRects.length,
        clientRect, top, rectsLen, rect, i;

    for(i=0; i<len; i++) {
        has = false;
        rectsLen = rects.length;
        clientRect = clientRects[i];
        top = clientRect.top;
        while(rectsLen--) {
            rect = rects[rectsLen];
            if (rect.top == top) {
                has = true;
                break;
            }
        }
        if(has) {
            rect.right = rect.right > clientRect.right ? rect.right : clientRect.right;
            rect.width = rect.right - rect.left;
        }
        else {
            rects.push({
                top: clientRect.top,
                right: clientRect.right,
                bottom: clientRect.bottom,
                left: clientRect.left,
                width: clientRect.width,
                height: clientRect.height
            });
        }
    }
    return rects;
}

1

html 편집기를 개발할 때 줄 번호를 계산하는 방법을 찾았습니다. 주요 방법은 다음과 같습니다.

  1. IE에서는 getBoundingClientRects를 호출 할 수 있으며 각 줄을 사각형으로 반환합니다.

  2. 웹킷 또는 새로운 표준 html 엔진에서 각 요소 또는 노드의 클라이언트 사각형을 반환합니다.이 경우 각 사각형을 비교할 수 있습니다. 즉, 각 사각형이 있어야하므로 높이가 더 작은 사각형은 무시할 수 있습니다. 직사각형의 상단이 그것보다 작고 하단이 그것보다 크면 조건이 참입니다.)

그래서 테스트 결과를 봅시다 :

여기에 이미지 설명 입력

녹색 직사각형은 각 행에서 가장 큰 직사각형입니다.

빨간색 직사각형은 선택 경계입니다.

파란색 직사각형은 확장 후 시작부터 선택까지의 경계입니다. 빨간색 직사각형보다 클 수 있으므로 각 직사각형의 하단을 확인하여 빨간색 직사각형의 하단보다 작아야합니다.

        var lineCount = "?";
        var rects;
        if (window.getSelection) {
            //Get all client rectangles from body start to selection, count those rectangles that has the max bottom and min top
            var bounding = {};
            var range = window.getSelection().getRangeAt(0);//As this is the demo code, I dont check the range count
            bounding = range.getBoundingClientRect();//!!!GET BOUNDING BEFORE SET START!!!

            //Get bounding and fix it , when the cursor is in the last character of lineCount, it may expand to the next lineCount.
            var boundingTop = bounding.top;
            var boundingBottom = bounding.bottom;
            var node = range.startContainer;
            if (node.nodeType !== 1) {
                node = node.parentNode;
            }
            var style = window.getComputedStyle(node);
            var lineHeight = parseInt(style.lineHeight);
            if (!isNaN(lineHeight)) {
                boundingBottom = boundingTop + lineHeight;
            }
            else {
                var fontSize = parseInt(style.fontSize);
                if (!isNaN(fontSize)) {
                    boundingBottom = boundingTop + fontSize;
                }
            }
            range = range.cloneRange();

            //Now we have enougn datas to compare

            range.setStart(body, 0);
            rects = range.getClientRects();
            lineCount = 0;
            var flags = {};//Mark a flags to avoid of check some repeat lines again
            for (var i = 0; i < rects.length; i++) {
                var rect = rects[i];
                if (rect.width === 0 && rect.height === 0) {//Ignore zero rectangles
                    continue;
                }
                if (rect.bottom > boundingBottom) {//Check if current rectangle out of the real bounding of selection
                    break;
                }
                var top = rect.top;
                var bottom = rect.bottom;
                if (flags[top]) {
                    continue;
                }
                flags[top] = 1;

                //Check if there is no rectangle contains this rectangle in vertical direction.
                var succ = true;
                for (var j = 0; j < rects.length; j++) {
                    var rect2 = rects[j];
                    if (j !== i && rect2.top < top && rect2.bottom > bottom) {
                        succ = false;
                        break;
                    }
                }
                //If succ, add lineCount 1
                if (succ) {
                    lineCount++;
                }
            }
        }
        else if (editor.document.selection) {//IN IE8 getClientRects returns each single lineCount as a rectangle
            var range = body.createTextRange();
            range.setEndPoint("EndToEnd", range);
            rects = range.getClientRects();
            lineCount = rects.length;
        }
        //Now we get lineCount here

1

이 솔루션을 시도하십시오.

function calculateLineCount(element) {
  var lineHeightBefore = element.css("line-height"),
      boxSizing        = element.css("box-sizing"),
      height,
      lineCount;

  // Force the line height to a known value
  element.css("line-height", "1px");

  // Take a snapshot of the height
  height = parseFloat(element.css("height"));

  // Reset the line height
  element.css("line-height", lineHeightBefore);

  if (boxSizing == "border-box") {
    // With "border-box", padding cuts into the content, so we have to subtract
    // it out
    var paddingTop    = parseFloat(element.css("padding-top")),
        paddingBottom = parseFloat(element.css("padding-bottom"));

    height -= (paddingTop + paddingBottom);
  }

  // The height is the line count
  lineCount = height;

  return lineCount;
}

https://jsfiddle.net/u0r6avnt/ 에서 실제 동작을 볼 수 있습니다.

페이지의 패널 크기를 조정하여 (페이지의 오른쪽을 더 넓게 또는 더 짧게 만들기 위해) 다시 실행하여 몇 줄이 있는지 확실하게 알 수 있는지 확인합니다.

이 문제는보기보다 어렵지만 대부분의 어려움은 두 가지 원인에서 비롯됩니다.

  1. 텍스트 렌더링은 JavaScript에서 직접 쿼리하기에는 브라우저에서 너무 낮은 수준입니다. 심지어 CSS :: first-line 가상 선택은 매우 다른 선택기처럼 행동하지 않습니다는 (당신이 그것을 반전, 예를 들어, 모든 스타일을 적용 할 수 없다 할 수 있지만 첫 번째 줄).

  2. 문맥은 줄 수를 계산하는 방법에 큰 역할을합니다. 예를 들어 라인 높이가 대상 요소의 계층 구조에 명시 적으로 설정되지 않은 경우 라인 높이로 "보통"을 되돌릴 수 있습니다. 또한 요소가 사용 중일 수 box-sizing: border-box있으므로 패딩이 적용될 수 있습니다 .

내 접근 방식은 선 높이를 직접 제어하고 상자 크기 조정 방법을 고려하여 2 번을 최소화하여보다 결정적인 결과를 얻습니다.


1

정렬되지 않은 텍스트의 여러 행에 걸쳐있는 링크와 같이 특정 경우에 다음을 사용하면 행 수와 각 행의 모든 ​​좌표를 얻을 수 있습니다.

var rectCollection = object.getClientRects();

https://developer.mozilla.org/en-US/docs/Web/API/Element/getClientRects

이것은 각 줄이 아주 조금이라도 다를 것이기 때문에 작동합니다. 그들이있는 한 렌더러에 의해 다른 "사각형"으로 그려집니다.


0

@BobBrunius 2010 제안에 따라 jQuery로 이것을 만들었습니다. 확실히 개선 될 수 있지만 일부는 도움이 될 수 있습니다.

$(document).ready(function() {

  alert("Number of lines: " + getTextLinesNum($("#textbox")));

});

function getTextLinesNum($element) {

  var originalHtml = $element.html();
  var words = originalHtml.split(" ");
  var linePositions = [];
        
  // Wrap words in spans
  for (var i in words) {
    words[i] = "<span>" + words[i] + "</span>";
  }
        
  // Temporarily replace element content with spans. Layout should be identical.
  $element.html(words.join(" "));
        
  // Iterate through words and collect positions of text lines
  $element.children("span").each(function () {
    var lp = $(this).position().top;
    if (linePositions.indexOf(lp) == -1) linePositions.push(lp);
  });
        
  // Revert to original html content
  $element.html(originalHtml);
        
  // Return number of text lines
  return linePositions.length;

}
#textbox {
  width: 200px;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="textbox">Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
  <br>sed diam nonummy</div>


0

요소 높이와 요소 높이를 비교할 수 있습니다. line-height: 0

function lineCount(elm) {
  const style = elm.getAttribute('style')
  elm.style.marginTop = 0
  elm.style.marginBottom = 0
  elm.style.paddingTop = 0
  elm.style.paddingBottom = 0
  const heightAllLine = elm.offsetHeight
  elm.style.lineHeight = 0
  const height1line = elm.offsetHeight
  const lineCount = Math.round(heightAllLine / height1line)
  elm.setAttribute('style', style)
  if (isNaN(lineCount)) return 0
  return lineCount
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.