Найти в Дзене

Как переносить «висячие» слова на новую строку с помощью JavaScript

В типографике существует понятие «висячих слов» — это короткие слова (предлоги, союзы, местоимения), которые остаются в конце строки при переносе текста. Такие переносы нарушают удобочитаемость и эстетику текста. В русской типографике принято избегать переносов после коротких слов длиной 1-2 символа. Для автоматического предотвращения переносов после коротких слов можно использовать JavaScript, который заменяет обычные пробелы на неразрывные пробелы ( ) после определённых слов. // Перенос висячих слов
document.addEventListener('DOMContentLoaded', function () {
// 1. Находим все текстовые элементы, которые нужно обработать
const textElements = document.querySelectorAll('p, span, h1, h2, h3, h4, h5, h6,
li, dt, dd');
// 2. Список предлогов и союзов, которые нельзя переносить
const prepositions = ['в', 'без', 'до', 'из', 'к', 'на', 'по', 'о', 'от', 'перед', 'при',
'через', 'для', 'с', 'у', 'и', 'а', 'но', 'да', 'или', 'либо', 'что', 'чтобы', 'как', '
Оглавление
изображение сгенерировано в ChatGPT
изображение сгенерировано в ChatGPT

В типографике существует понятие «висячих слов» — это короткие слова (предлоги, союзы, местоимения), которые остаются в конце строки при переносе текста. Такие переносы нарушают удобочитаемость и эстетику текста. В русской типографике принято избегать переносов после коротких слов длиной 1-2 символа.

Решение проблемы с помощью JavaScript

Для автоматического предотвращения переносов после коротких слов можно использовать JavaScript, который заменяет обычные пробелы на неразрывные пробелы ( ) после определённых слов.

// Перенос висячих слов
document.addEventListener('DOMContentLoaded', function () {
// 1. Находим все текстовые элементы, которые нужно обработать
const textElements = document.querySelectorAll('p, span, h1, h2, h3, h4, h5, h6,
li, dt, dd');

// 2. Список предлогов и союзов, которые нельзя переносить
const prepositions = ['в', 'без', 'до', 'из', 'к', 'на', 'по', 'о', 'от', 'перед', 'при',
'через', 'для', 'с', 'у', 'и', 'а', 'но', 'да', 'или', 'либо', 'что', 'чтобы', 'как', 'когда',
'если', 'вы'];

// 3. Функция для обработки каждого элемента
textElements.forEach(element => {

// Получаем все текстовые узлы внутри элемента
const walker = document.createTreeWalker(element,
NodeFilter.SHOW_TEXT);
const textNodes = [];
while (walker.nextNode()) {
textNodes.push(walker.currentNode);
}

// Обрабатываем каждый текстовый узел
textNodes.forEach(textNode => {
let text = textNode.nodeValue;

// Заменяем пробелы после коротких слов на неразрывные
пробелы
text = text.replace(/(^|\s)([а-яё]{1,2})\s/gi, (match, prefix, word) => {

// Проверяем, есть ли слово в списке предлогов
if (prepositions.includes(word.toLowerCase())) {
return prefix + word + '\u00A0'; // \u00A0 - это неразрывный
пробел
}

return match;
});

// Обновляем содержимое текстового узла
textNode.nodeValue = text;
});
});
});


Разбор кода по частям

1. Инициализация скрипта

document.addEventListener('DOMContentLoaded', function () {

Код выполняется после полной загрузки DOM-дерева страницы. Это гарантирует, что все элементы будут доступны для обработки.

2. Поиск текстовых элементов

const textElements = document.querySelectorAll('p, span, h1, h2, h3, h4, h5, h6, li, dt, dd');

Скрипт находит все основные текстовые элементы на странице: параграфы, заголовки, элементы списков и другие. Вы можете расширить этот список, добавив другие селекторы.

3. Список коротких слов

const prepositions = ['в', 'без', 'до', 'из', 'к', 'на', 'по', 'о', 'от', 'перед', 'при', 'через', 'для', 'с', 'у', 'и', 'а', 'но', 'да', 'или', 'либо', 'что', 'чтобы', 'как', 'когда', 'если', 'вы'];

Массив содержит наиболее распространённые предлоги, союзы и другие служебные слова русского языка, после которых нежелательны переносы.

4. Обход текстовых узлов

const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);

TreeWalker позволяет пройти по всем текстовым узлам внутри элемента, включая вложенные теги. Это важно, так как текст может содержать форматирование («,» и т.д.).

5. Регулярное выражение для замены

text = text.replace(/(^|\s)([а-яё]{1,2})\s/gi, (match, prefix, word) => {

Регулярное выражение ищет:
· (^|\s) — начало строки или пробел (группа 1);
· ([а-яё]{1,2}) — слово из 1-2 русских букв (группа 2);
· \s — пробел после слова;
· Флаги gi означают глобальный поиск без учёта регистра.

6. Условная замена

if (prepositions.includes(word.toLowerCase())) {
return prefix + word + '\u00A0'; // \u00A0 - это неразрывный пробел
}

Если найденное короткое слово есть в списке предлогов, обычный пробел заменяется на неразрывный пробел (\u00A0). Это предотвращает разрыв строки между предлогом и следующим словом.

Результат работы

После выполнения скрипта текст «Я иду в магазин» не будет разорван на строки как «Я иду в» и «магазин». Предлог «в» всегда останется на одной строке со следующим словом благодаря неразрывному пробелу.

Настройка скрипта

Вы можете легко адаптировать скрипт под свои нужды:
· Добавить новые селекторы в querySelectorAll() для обработки других
элементов;
· Расширить список слов в массиве prepositions;
· Изменить длину слов в регулярном выражении с {1,2} на другое значение;
· Добавить обработку других языков, изменив диапазон символов в регулярном;
выражении.

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

P.S.: это JS решение иногда не во всех случаях срабатывает + бывают сложности с адаптивностью: на смартфонах может переносить совсем не так, как хотелось бы, текст может «уехать» за пределы контейнера, нужно будет «фиксить» эти моменты в CSS.

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

А как вы решаете вопрос переноса «висячих»?