Сделайте моноширинный текст максимально большим, не вызывая переполнения или переноса.

Я ищу способ сделать моноширинный текст максимально широким в своем контейнере без переполнения или разрыва. Я уже рассмотрел CSS3 Make Текст как можно больше, чтобы заполнить элемент без переполнения и попытался реализовать предложенное решение, но в моем случае оно не работает. Если я установлю размер шрифта на 3vw вместо 7vw, как предлагается в ответе на связанный вопрос, он кажется близким, но когда я изменяю длину строк или ширину страницы, он снова отключается.

Вот мой код:

https://jsfiddle.net/de7qbu19/ (код в скрипте тот же)

#song-container {
    text-align: center;
    margin: 20px;
}
#song {
    color: #000;
    font: normal 3vw Courier New,monospace,Courier;
    white-space: pre;
    word-break: break-all;
    text-align: left;
    display: inline-block;
}

#song > span { /* Chords*/
    color: #007fbf;
    cursor: pointer;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
            
<div class="container-fluid">
    <div id="song-container">
        <div class="panel panel-default">
            <div class="panel-body">
                <span id="song">
[Placeholder]

<span>Em</span>         <span>G</span>
Placeholder Placeholder Placeholder Placeholder
<span>D</span>          <span>C</span>
Placeholder Placeholder Placeholder Placeholder
                </span>
            </div>
        </div>
    </div>
</div>

Когда я запускаю фрагмент, кажется, что он занимает почти всю ширину: small Но когда я затем выбираю опцию Full page, становится ясно, что это не так и что это ненадежно, особенно когда я уменьшите размер окна: маленькая победа во весь экран

Таким образом, установка размера шрифта с использованием единиц vw не помогает мне.

Любые идеи, как я мог добиться этого правильно?


person Forivin    schedule 26.04.2020    source источник
comment
Похоже, вам нужен еще один класс? Нравится .text.full-page или .text.small-page и подбрасывайте под них свои стили. Таким образом, вы должны определить два отдельных font-sizes на основе текущей настройки. Может быть, также посмотреть медиа-запросы, если размер вашего экрана действительно уменьшается?   -  person Sean Mooney    schedule 28.04.2020
comment
Вы предлагаете создать сотни записей медиа-запросов и методом проб и ошибок выяснить, какая ширина экрана требует, какой размер шрифта покрывает каждое состояние разрешения / масштабирования? Звучит как много работы и не очень ремонтопригодно. Простое изменение типа шрифта сломает все, не так ли?   -  person Forivin    schedule 28.04.2020
comment
Нет, я бы не стал это отстаивать, похоже, у вас было только 2 или около того просмотров, которые нарушались, что было бы нормально для этого. Вы взглянули на этот css-tricks.com/fitting-text- в-контейнер Некоторые варианты достижения того, что вы ищете   -  person Sean Mooney    schedule 29.04.2020
comment
Ни один из них не работал для меня. Либо они работают только с одной строкой текста, либо вам нужно изменить какое-то значение при изменении длины текстовых строк, либо это просто не работает со всеми размерами окон.   -  person Forivin    schedule 29.04.2020
comment
Это margin: 20px; вызывает проблемы. Изменение значения на margin: 20px auto; может решить вашу проблему.   -  person 7cc    schedule 03.05.2020
comment
@7cc Я только что попробовал это, и это не решило проблему.   -  person Forivin    schedule 04.05.2020
comment
@Forivin, пожалуйста, попробуйте в fiddle.jshell.net/de7qbu19/show или в локальном html-файле, не в iframe здесь. Но если вы планируете использовать страницу в iframe, то добавьте #song-container { width: min-content }   -  person 7cc    schedule 04.05.2020
comment
@7cc У меня не работает. Когда я уменьшаю ширину окна и увеличиваю масштаб, он ломается, как на скриншоте моего вопроса.   -  person Forivin    schedule 04.05.2020
comment
@Forivin Я могу воспроизвести это только при открытии инструмента разработчика или путем увеличения заполнения .panel-body скриншотов (Я имею в виду, что я не могу так сильно уменьшить ширину окна без усилий). Кстати, имейте в виду, что ответы на основе css (и некоторые на основе js) работают только тогда, когда символы имеют одинаковую ширину. Обычно символы/смайлики CJK имеют разную ширину, хотя вы не можете использовать их для аккордов.   -  person 7cc    schedule 05.05.2020


Ответы (3)


Если вы хорошо разбираетесь в решении javascript, вот простое.

Он состоит в получении ширины div и размера шрифта, вычислении ширины одного символа и, наконец, вычислении нового максимального размера шрифта в соответствии с этой информацией.

Вы также должны указать в скрипте максимальное количество символов, которое может быть в самой длинной строке текста:

Placeholder Placeholder Placeholder Placeholder

В приведенном выше примере самая длинная строка текста содержит 47 символов;

var container = document.getElementById("container"),
  cs = getComputedStyle(container),
  containerPB = parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight) + parseFloat(cs.borderLeftWidth) + parseFloat(cs.borderRightWidth), //containerPadding + containerBorderWidth
  containerWidth = container.offsetWidth - containerPB,
  containerFontSize = parseFloat(cs.fontSize),
  containerFontFamily = cs.fontFamily,
  span = document.createElement("SPAN"),
  char = document.createTextNode("a"),
  charMax = 47, //max characters per line
  alpha = 1.00; //represent font scaling based on width
span.style.fontFamily = containerFontFamily;
span.appendChild(char);
span.style.visibility = "hidden";
document.body.appendChild(span);
//GETTING THE WIDTH OF A SINGLE CHAR
var charWidth = span.getBoundingClientRect().width;
document.body.removeChild(span);
container.style.fontSize =
  (containerWidth * containerFontSize * alpha) / (charWidth * charMax) + "px";
window.addEventListener("resize", function(e) {
  //update the width of container
  containerWidth = container.offsetWidth - containerPB;
  //update the font-size
  container.style.fontSize =
    (containerWidth * containerFontSize * alpha) / (charWidth * charMax) + "px";
});
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

#container {
  border: 1px solid #ddd;
  color: #000;
  font-family: Courier New, monospace, Courier;
  margin: 0 auto;
  padding: 0.375rem;
  width: 90%;
}

#container>span {
  /* Chords*/
  color: #007fbf;
  cursor: pointer;
}
<pre id="container">[Placeholder]

<span>Em</span>         <span>G</span>
Placeholder Placeholder Placeholder Placeholder
<span>D</span>          <span>C</span>
Placeholder Placeholder Placeholder Placeholder</pre>

person h3t1    schedule 28.04.2020

Давайте сначала посмотрим, почему размер текста такой, какой он есть сейчас. 3vw означает 3% ширины области просмотра. Важно отметить, что это значение используется для высоты символов. Мы можем рассчитать ширину всего текста в процентах от ширины области просмотра. Это работает только для монофонического шрифта.

Для начала нам нужно соотношение ширины и высоты шрифта. Ширина моноширинного символа зависит от шрифта. В этом примере я буду работать с Courier New. Я не уверен, где именно это найти, поэтому я буду использовать примерно 99/188.

изображение измерения символов

Если максимальное количество символов:

11 * 4 (Placeholder) + 3 (spaces) = 47

Тогда ширина 47 символов равна:

47 * 3vw * (99/188) = 74.25vw

Итак, около 75% ширины области просмотра. Это означает, что когда отступы, поля и границы занимают более 25% ширины (из-за изменения размера окна), содержимое текста больше не будет помещаться в его контейнер.

Так как же сделать контент подходящим? Мы можем использовать функцию CSS calc(), чтобы вычесть некоторые статические значение из динамического значения. Для этого нам сначала нужно знать ширину статических значений. В вашем примере это статические ширины:

  • 20px маржа для #song-container
  • 15px заполнение для .container-fluid
  • 1px граница для .panel
  • 15px заполнение для .panel-body

Не забывайте, что все эти значения присутствуют с обеих сторон, поэтому они занимают:

(20px + 15px + 1px + 15px) * 2 = 102px

Мы не можем вычесть это из 3vw, потому что 3vw — это высота одного символа, а 102px — это ширина статических элементов. Итак, теперь нам нужно преобразовать 102px в высоту одного символа. Это делается путем распределения ширины по всем символам, а затем применения коэффициента для преобразования ширины символа в высоту.

102px / 47 / (99/188) ≈ 4.121212121

Теперь мы сравниваем яблоки с яблоками и можем использовать calc(3vw - 102px / 47 / (99/188)) для размера шрифта. Теперь вы можете свободно играть со значением 3vw. В примере я увеличил это значение до 3.5vw.

Обратите внимание, что это не на 100% точно, я не учитывал расстояние между символами, а соотношение ширины и высоты шрифта основано на измерении, а не на заданном.

#song-container {
    text-align: center;
    margin: 20px;
}
#song {
    color: #000;
    font-size: calc(3.5vw - 102px / 47 / (99/188));
    font-family: "Courier New",monospace,Courier;
    white-space: pre;
    word-break: break-all;
    text-align: left;
    display: inline-block;
}

#song > span { /* Chords*/
    color: #007fbf;
    cursor: pointer;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
            
<div class="container-fluid">
    <div id="song-container">
        <div class="panel panel-default">
            <div class="panel-body">
                <span id="song">
[Placeholder]

<span>Em</span>         <span>G</span>
Placeholder Placeholder Placeholder Placeholder
<span>D</span>          <span>C</span>
Placeholder Placeholder Placeholder Placeholder
                </span>
            </div>
        </div>
    </div>
</div>

Это работает, но когда изменяется статическая ширина, максимальное количество символов или соотношение ширины и высоты шрифта, вам необходимо пересчитать значение компенсации. По этой причине библиотека JavaScript может подойти лучше. Вы можете найти некоторые из них, описанные в сообщении CSS-Trics Подгонка текста к Контейнер.

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

person 3limin4t0r    schedule 04.05.2020

Вот несколько вещей, которые улучшат отзывчивость:

#song-container{
 text-align: center;
 margin:0;
overflow: hidden;
}

.panel-body{
 margin: 0;
}

Если вы хотите, чтобы переполнение было прокручиваемым, вы можете просто добавить overflow-x: scroll; Кроме того, если вы используете медиа-запросы, это также сделает его более отзывчивым, потому что даже с моим подходом доходит до того, что если экран составляет всего 220 пикселей, он будет обрезать некоторые слов из-за того, что шрифты не масштабируются достаточно быстро, и вы можете изменить свой медиа-запрос, чтобы масштабировать шрифт быстрее после достижения этой точки, чтобы сохранить его в своем контейнере. Надеюсь это поможет!

РЕДАКТИРОВАТЬ:

  #song-container {
    text-align: center;
    /*margin: 20px;*/
    padding: 1%;
}
#song {
    color: #000;
    font: normal 3vw Courier New,monospace,Courier;
    white-space: pre;
    word-break: break-all;
    text-align: left;
    display: inline-block;
}

#song > span { /* Chords*/
    color: #007fbf;
    cursor: pointer;
}
.panel-body{
  padding:0;
}

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

person Mixael Contreras    schedule 04.05.2020
comment
JSFiddle разветвляет проект, когда вы не являетесь его владельцем, создавая новый URL-адрес. Таким образом, вам нужно либо указать ссылку на новый URL-адрес из своего ответа, либо нажать большую кнопку «Копировать фрагмент для ответа» под фрагментом и внести изменения здесь, в Stack Overflow. - person 3limin4t0r; 05.05.2020
comment
Попался, я не знал, что Спасибо! Однако, когда я имею в виду, что я редактирую скрипку, я имел в виду, что я протестировал ее там и просто скопировал код, мои извинения, если это вводит в заблуждение. - person Mixael Contreras; 05.05.2020