Есть ли в CSS или JS возможность заставить односимвольные слова в конце строки переходить на следующую?

При создании адаптивного веб-дизайна часто случается, что однобуквенное слово остается последним словом в строке абзаца:

This is a
paragraph

Я хотел бы переместить такое однобуквенное слово следующим образом:

This is
a paragraph

Есть ли какое-либо встроенное свойство в CSS, позволяющее добиться такого эффекта? Если его нет, как это можно сделать в JavaScript?


person blondkarol    schedule 06.05.2020    source источник
comment
Интересный. Это сложно, потому что (насколько мне известно) не существует простого способа определить положение естественных разрывов строк. Вы можете посмотреть, как работает плагин балансировки текста от Adobe. это для решения этой другой, но в некотором роде похожей проблемы - кажется, что это связано с измерением ширина текста в обертке white-space: nowrap разбита в разных местах.   -  person user56reinstatemonica8    schedule 07.05.2020
comment
После того, как я ответил неправильно, не понимая, чего именно вы хотите, теперь я считаю, что для этого вам следует использовать холст. developer.mozilla.org/en-US/docs/Web/ API/   -  person StackSlave    schedule 07.05.2020
comment
Кстати, только что узнал, что это дубликат stackoverflow.com/questions/22984925/   -  person davidgiesemann    schedule 07.05.2020
comment
Отвечает ли это на ваш вопрос? Однобуквенное слово в конце строки (выравнивание по ширине)   -  person Rob    schedule 07.05.2020
comment
@ Роб, в какой-то степени, но не полностью. Ответ Терри - это именно то, что я искал.   -  person blondkarol    schedule 07.05.2020


Ответы (2)


Чтобы слова, состоящие из одной буквы (например, «a» или «I»), находились в той же строке, что и следующее слово, вы можете заменить символ пробела между ними неразрывным символом Unicode пробела \u00A0.

Это можно автоматизировать с помощью небольшого количества JavaScript. Например, этот код заменяет [space][letter][space] на [space][letter][non-breaking space]:

const modifySingleChars = str => str.replace(/ ([a-zA-Z]) /g,
    ' $1' + '\u00A0');

Чтобы изменить все экземпляры на странице, сначала соберите все текстовые узлы внутри тела (пропустив все внутри тега <script>.

Затем просто перебирайте текстовые узлы, делая соответствующие замены.

Рабочий пример:

// form array of all text nodes in parentNode
function allTextNodes(parentNode) {
  let arr = [];
  if (!parentNode) {
    return arr;
  }

  let nodes = parentNode.childNodes;
  nodes.forEach(node => {
    if (node.nodeName === 'SCRIPT') {
      return;
    }
    if (node.nodeType === Node.TEXT_NODE) {
      arr.push(node);
    } else {
      arr = arr.concat(allTextNodes(node));
    }
  });
  return arr;
}

// convert [space][letter][space] to [space][letter][non-breaking space];
const modifySingleCharWords = str => str.replace(/ ([a-zA-Z]) /g,
  ' $1' + '\u00A0');

function fixAllSingleCharWordsInBody() {
  let tNodes = allTextNodes(document.body);
  tNodes.forEach(tNode => {
    tNode.nodeValue = modifySingleCharWords(tNode.nodeValue);
  });
}
<body>
  <div id="wrapper" style="width:20rem">
    <h4>Prevent single character words at end of line</h4>
    <button type="button" onclick="fixAllSingleCharWordsInBody();">Fix All Words
  </button>
    <p>Lorem &nbsp;ipsum dolor i amet, consectetur a dipiscing elit, sed o eiusmod tempor incididunt u labore et dolore magna aliqua. <span>Nisl purus i mollis</span> nunc.
    </p>
    <p>In vitae turpis massa e elementum tempusus a sed. Eget mi proin e libero enim i faucibus. Quis lectus nulla a volutpat diam ut.
    </p>
    <p>Pharetra e ultrices neque ornare. Donec a tristique risus e feugiat in fermentum. Consectetur adipiscing e u aliquam purus sit amet.
    </p>
    <p>Vitae congue mauris rhoncus aenean e elit scelerisque mauris pellentesque. Mauris u eros i cursus turpis a tincidunt dui.
    </p>
    <p>At volutpat diam u venenatis tellus. Tellus integer feugiat scelerisque varius morbi i nunc faucibus at.</p>
    <script>
      const b = 'Do not modify anything inside a script tag';
    </script>
  </div>
</body>

person terrymorse    schedule 06.05.2020
comment
Хорошее начало, но почему бы не использовать подстановочный знак и группу захвата с заполнителем в замене регулярного выражения, например (не тестировалось, разговариваю по телефону) text.replace(/ (\S) /g, " $1&nbsp;") - person user56reinstatemonica8; 07.05.2020
comment
@ user56reinstatemonica8 Спасибо за идею, я заменил регулярное выражение на подстановочный знак. - person terrymorse; 07.05.2020
comment
@terrymorse, это именно то, что я искал. Спасибо от всего сердца! - person blondkarol; 07.05.2020
comment
Спасибо, я рад, что вам нравится решение. - person terrymorse; 07.05.2020

Если вы хотите ВСЕГДА хранить «a» и «абзац» вместе, добавьте между ними «неразрывный пробел»:

<div style="width:100px;border:1px solid #333;padding:5px">
<p>
This is a&nbsp;paragraph
</p>
</div>

person davidgiesemann    schedule 06.05.2020
comment
Поскольку на моем веб-сайте много текста, мне нужно что-то более автоматизированное, но это, кажется, хорошая отправная точка! - person blondkarol; 07.05.2020
comment
Это может работать с заменой регулярного выражения, заменяя все экземпляры пробела-один символ-пробел на пробел-один символ-. Это было бы гораздо более эффективно, чем что-либо, основанное на многократном измерении ширины. - person user56reinstatemonica8; 07.05.2020
comment
@blondkarol Я только что добавил фрагмент кода JavaScript, который автоматизирует этот процесс замены. - person terrymorse; 07.05.2020