Calculation of number of lines
It is possible to calculate how many lines an element has by dividing its scrollHeight
for his line-height
and rounded up (if the result is 3.1
lines, actually the element needs to 4
lines to be displayed).
scrollHeight
is a measure of the height of the element’s content, including content not visible on the screen due to the overflow.
line-height
is a property that defines the height of a line box, i.e., the height of the line text including line spacing.
Algorithm for the calculation
To obtain the scrollHeight
, just access the property directly from the HTML element elemento.scrollHeight
.
To the line-height
we have a little more complexity:
line-height
is a CSS value calculated by the browser. We use enntão window.getComputedStyle(elemento)
to obtain all calculated style values of the element in question.
As the above function returns a list of values of different properties, we search for the desired value with listaDeValoresCalculados.getPropertyValue('line-height')
.
In the CSS, the line-height
can hold values such as inherit
, normal
, 15px
, 3rem
etc. By obtaining the calculated value with the above function, we can receive or normal
or the value in px
.
We convert the calculated value to integer with parseInt()
.
4.1. If the value was 15px
, now will be 15
, all right.
4.2. If the value was normal
, now will be NaN
. If it is NaN
, we need to calculate the line-height
otherwise.
4.2.1. We clone the element with cloneNode()
to have an element with all the same style properties.
4.2.2. We take the height of the element with offSetHeight
when he has a single line (<br>
) and when it has two lines (<br><br>
).
4.2.3. Subtract the height of two lines by the height of one line (alturaDuasLinhas - alturaUmaLinha
), that’s the line-height
we will use. This is necessary as the height of a single line includes the padding, for example, it may be worth 40
when in fact the line-height
is of 15px
, and then the height of two lines would be worth 55
, and 55 - 40 = 15
.
Now we have the values of scrollHeight
and line-height
. We do the splitting and the bumping up: Math.ceil(scrollHeight / lineHeight)
.
Example
In the example below I apply the algorithm described above. Also, I decided to obtain the lineHeight
only once, when the page loads with DOMContentLoaded
, because it is a more complex process, I do it only once.
If your CSS changes dynamically, it may be line-height
change, for example. In this case, adapt the code to your needs.
let lineHeightParagrafo;
document.addEventListener("DOMContentLoaded", function() {
lineHeightParagrafo = getLineHeight(document.querySelector("p"))
});
document.querySelector("input").addEventListener("click", function() {
const paragrafo = document.querySelector("p");
const quant = Math.ceil(paragrafo.scrollHeight / lineHeightParagrafo);
let addS = "";
if (quant > 1) {
addS = "s";
}
alert("Há " + quant + " linha" + addS + " no texto!");
});
function getLineHeight(elemento) {
const estiloComputado = window.getComputedStyle(elemento);
/* A propriedade pode ter valor 'normal' ou em 'px',
mesmo que você tenha atribuído em 'rem' */
const stringLineHeight = estiloComputado.getPropertyValue('line-height');
let lineHeight = parseInt(stringLineHeight, 10);
/* Caso o valor seja 'normal', então lineHeight não será um número,
então criamos um elemento novo para calcular o lineHeight */
if (isNaN(lineHeight)) {
/* <br> fará com que o clone tenha apenas uma linha,
para descobrir o lineHeight é necessário calcular a
diferença de tamanho entre duas linhas, porque
a existência de padding influenciará o retorno de offSetHeight */
const clone = elemento.cloneNode();
clone.innerHTML = '<br>';
elemento.appendChild(clone);
const alturaComUmaLinha = clone.offsetHeight;
clone.innerHTML = '<br><br>';
const alturaComDuasLinhas = clone.offsetHeight;
elemento.removeChild(clone);
lineHeight = alturaComDuasLinhas - alturaComUmaLinha;
}
return lineHeight;
}
<input type=button value="Quantas linhas possui o texto abaixo?">
<p style="width: 300px">
<!--Texto genérico abaixo -->
Lorem ipsum porta consectetur sollicitudin arcu sodales elit nunc, morbi varius aliquam ultricies augue cras dui fringilla, auctor amet ac mattis praesent suspendisse nunc. arcu mi faucibus aliquam erat sagittis pharetra egestas, scelerisque nostra ligula
aliquam rhoncus placerat nec, mattis at nullam morbi sapien magna. curae imperdiet senectus accumsan hendrerit pretium accumsan lorem curae fringilla, imperdiet sapien turpis curabitur dictum urna interdum leo inceptos tellus, fusce malesuada quisque
venenatis platea neque euismod porta. fames ut donec hendrerit primis placerat integer amet sollicitudin interdum nisl, etiam posuere dictum dui semper netus orci arcu ad erat, vehicula nisl netus conubia arcu neque felis augue neca.
</p>
The algorithm to obtain the line-height
in the event of normal
was adapted of a reply from Soen.
It got a little confusing to what you refer to when you say "natural" line breaks. Do you say in relation to when the browser itself divides the text, for example to fit everything on the screen? Or does it refer to "enter" when someone types something? In the case of the Lorem ipsum example you put, it would have how many line breaks?
– Lucius
First answer: Yes, the "natural" breaks I quoted are the ones that the browser itself divides. Second answer: No. In the case of the text Lorem ipsum I put of example and considering the amount of "enter", it would have 0 line breaks.
– Ricardo Augusto