Как определить ширину текстовой строки в JS

Раздел: Веб-разработка -> Измерение и установка размеров элементов

Измерение ширины текста с помощью Canvas API

Как измерить ширину текста без добавления элементов в DOM?

Canvas предоставляет метод measureText, который возвращает объект с шириной в пикселях. Это быстрый и точный способ, не требующий изменении вёрстки.


const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.font = '16px Arial';
const width = ctx.measureText('Пример текста').width;
console.log(width);

Js text width (измерение ширины текста в javascript)

Перед измерением необходимо установить шрифт и его размер, иначе результат будет для шрифта по умолчанию. Также следует учитывать загрузку веб-шрифтов.

Проблема: при использовании веб-шрифтов, если шрифт ещё не загружен, измерение будет неверным. Решение: дождаться события document.fonts.ready или использовать шрифты, уже загруженные на странице.

Как измерить ширину текста с учётом стилей элемента?

Если текст должен отображаться с определёнными стилями (жирность, межбуквенное расстояние и т.д.), можно создать временный элемент, применить стили и измерить его ширину после добавления в DOM.


const span = document.createElement('span');
span.textContent = 'Текст с нестандартными стилями';
span.style.font = 'bold 18px Times New Roman';
span.style.letterSpacing = '2px';
span.style.position = 'absolute';
span.style.visibility = 'hidden';
document.body.appendChild(span);
const width = span.getBoundingClientRect().width;
document.body.removeChild(span);
console.log(width);

Border width js (стиль border-width в javascript)

Проблема: offsetWidth включает padding, border, scrollbar, если они есть. Лучше использовать getBoundingClientRect().width, который возвращает ширину содержимого с учётом паддингов, но без margin. Также добавление элемента влияет на layout; использование position:absolute и visibility:hidden минимизирует это влияние.

Как измерить ширину текста в уже существующем элементе?

Если элемент уже есть на странице и содержит текст, можно напрямую получить его ширину через offsetWidth или getBoundingClientRect.


const element = document.getElementById('myText');
const width = element.offsetWidth;
console.log(width);

Js style width (стиль width в javascript)

Этот способ не подходит, если текст ещё не отрендерен.

Как измерить ширину текста с помощью Range?

Объект Range позволяет измерять ширину выделенного фрагмента текста. Это может быть полезно для динамических текстов.


const range = document.createRange();
const textNode = document.createTextNode('Измеряемый текст');
range.selectNodeContents(textNode); // нужно сначала добавить textNode в DOM
// для измерения без DOM можно создать временный элемент как выше

Js width height (ширина и высота в javascript)

Range измеряет ширину в координатах документа, но требует, чтобы текст был в DOM.

Как измерить ширину текста в SVG?

Элемент SVG text имеет метод getComputedTextLength, возвращающий длину текста в пользовательских единицах.


const svgNS = 'http://www.w3.org/2000/svg';
const text = document.createElementNS(svgNS, 'text');
text.textContent = 'SVG текст';
text.setAttribute('font-size', '20');
document.getElementById('svgContainer').appendChild(text);
const length = text.getComputedTextLength();
console.log(length);

Js device width (ширина экрана устройства в javascript)

Как выполнить приблизительное измерение без точного шрифта?

Если точность не критична, можно использовать среднюю ширину символа (например, 0.6 от font-size) и умножить на длину строки.


const fontsize = 16;
const approximateWidth = text.length * fontsize * 0.6;

Этот метод даёт лишь грубую оценку и не учитывает кернинг, разные шрифты и специфические символы.

Расширенные примеры измерения ширины текста

Измерение многострочного текста

Для текста, занимающего несколько строк, ширина обычно определяется самой длинной строкой. Можно разбить текст на строки и измерить каждую.

Пример

const multiline = 'Первая строка\nВторая, более длинная строка\nТретья';
const lines = multiline.split('\n');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.font = '14px Arial';
const widths = lines.map(line => ctx.measureText(line).width);
const maxWidth = Math.max(...widths);
console.log('Максимальная ширина:', maxWidth);
Максимальная ширина: 156.5

Измерение текста с разными шрифтами

Необходимо учитывать, что шрифт может быть разным для разных частей текста. В таком случае измерение проводится для каждого фрагмента отдельно.

Пример

const parts = [
  { text: 'Жирный', font: 'bold 16px Arial' },
  { text: ' Курсив', font: 'italic 16px Times' }
];
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let totalWidth = 0;
parts.forEach(part => {
  ctx.font = part.font;
  totalWidth += ctx.measureText(part.text).width;
});
console.log('Общая ширина:', totalWidth);
Общая ширина: 87.2

Кэширование измерений для повышения производительности

Если требуется многократно измерять один и тот же текст, результат можно сохранять в переменной или Map.

Пример

const cache = new Map();
function getTextWidth(text, font) {
  const key = text + '|' + font;
  if (cache.has(key)) return cache.get(key);
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  ctx.font = font;
  const width = ctx.measureText(text).width;
  cache.set(key, width);
  return width;
}
console.log(getTextWidth('Привет', '14px Arial'));
console.log(getTextWidth('Привет', '14px Arial')); // из кэша
35.2 (дважды выведется одно и то же)

Измерение с учётом letter-spacing и word-spacing

Canvas API не учитывает CSS-свойства letter-spacing и word-spacing, поэтому при необходимости их нужно добавлять вручную.

Пример

function measureTextWithSpacing(text, font, letterSpacing = 0, wordSpacing = 0) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  ctx.font = font;
  let width = 0;
  for (let i = 0; i < text.length; i++) {
    width += ctx.measureText(text[i]).width;
    if (text[i] === ' ') width += wordSpacing;
    if (i < text.length - 1) width += letterSpacing;
  }
  return width;
}
console.log(measureTextWithSpacing('Hello World', '16px Arial', 1, 4));
95.2

Сравнение точности canvas и DOM-элемента

Оба метода дают близкие результаты, но canvas может отличаться из-за округления. Проверка:

Пример

const text = 'Тест';
const font = '20px Arial';
// Canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.font = font;
const cWidth = ctx.measureText(text).width;
// DOM
const span = document.createElement('span');
span.textContent = text;
span.style.font = font;
span.style.position = 'absolute';
span.style.visibility = 'hidden';
document.body.appendChild(span);
const dWidth = span.getBoundingClientRect().width;
document.body.removeChild(span);
console.log('Canvas:', cWidth, 'DOM:', dWidth);
Canvas: 36.3 DOM: 36.3 (обычно совпадают)

Измерение ширины текста до его рендеринга в браузере

Это полезно для адаптивной верстки, когда нужно определить, поместится ли текст в контейнер.

Пример

function canFit(text, maxWidth, font) {
  const width = getTextWidth(text, font); // функция из предыдущих примеров
  return width <= maxWidth;
}
console.log(canFit('Длинный текст, который не поместится', 100, '12px Arial'));
false

Измерение ширины текста в JavaScript - comments

En
Js text width (javascript)