Многоточие в середине текста (стиль Mac) - PullRequest
39 голосов
/ 07 мая 2009

Мне нужно реализовать многоточие ("...") в середине текста внутри изменяемого размера элемента. Здесь - это то, на что это может быть похоже. Таким образом,

"Lorem ipsum dolor sit amet. Ut ornare dignissim ligula sed commodo."

становится

"Lorem ipsum dolor sit amet ... commodo."

Когда элемент растягивается на ширину текста, я хочу, чтобы многоточие исчезло. Как это можно сделать?

Ответы [ 13 ]

27 голосов
/ 07 мая 2009

В HTML поместите полное значение в пользовательский атрибут data- * наподобие

<span data-original="your string here"></span>

Затем назначьте прослушиватели событий load и resize для функции JavaScript, которая будет считывать исходный атрибут данных и помещать его в innerHTML вашего тега span. Вот пример функции многоточия:

function start_and_end(str) {
  if (str.length > 35) {
    return str.substr(0, 20) + '...' + str.substr(str.length-10, str.length);
  }
  return str;
}

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

Подсказка также заключается в том, чтобы на ярлыке ... или who было указано abbr-tag, чтобы пользователь мог получить всплывающую подсказку с полной строкой.

<abbr title="simple tool tip">something</abbr>
20 голосов
/ 07 апреля 2016

Я хотел бы предложить мой пример решения этой проблемы.

Основная идея состоит в том, чтобы разбить текст на две четные части (или первая больше, если длина нечетная), одна из которых имеет многоточие в конце, а другая выровнена по правому краю с text-overflow: clip.

Так что все, что вам нужно сделать с js, если вы хотите сделать его автоматическим / универсальным - это разбить строку и установить атрибуты.

Хотя у него есть некоторые недостатки.

  1. Нет приятного переноса словами или даже буквами (text-overflow: '' на данный момент работает только в FF)
  2. Если разделение происходит между словами - пробел должен быть в первой части. В противном случае оно будет свернуто.
  3. Конец строки не должен иметь восклицательных знаков, поскольку direction: rtl - они будут перемещены влево от строки. Я думаю, это можно исправить, поместив правильную часть слова в тег и восклицательный знак в псевдоэлементе ::after. Но я еще не сделал это должным образом.

Но, с учетом всего вышесказанного, это выглядит очень круто для меня, особенно когда вы перетаскиваете границу браузера, что вы можете легко сделать на странице jsfiddle: https://jsfiddle.net/extempl/93ymy3oL/. Или просто запустите фрагмент с фиксированной максимальной шириной ниже.

GIF под спойлером:

body {
  max-width: 400px;
}

span::before, span::after {
  display: inline-block;
  max-width: 50%;
  overflow: hidden;
  white-space: pre;
}

span::before {
  content: attr(data-content-start);
  text-overflow: ellipsis;
}

span::after {
  content: attr(data-content-end);
  text-overflow: '';
  direction: rtl;
}
<span data-content-start="Look deep into nature, and then you " 
      data-content-end=  "will understand everything better"></span>

<br>
<span data-content-start="https://www.google.com.ua/images/branding/g" 
      data-content-end=  "ooglelogo/2x/googlelogo_color_272x92dp.png"></span>
9 голосов
/ 05 июня 2014

Итак, мой коллега предложил решение, которое не использует никаких дополнительных элементов dom. Мы проверяем, переполняется ли div, и добавляем атрибут данных последних n символов. Остальное сделано в css.

Вот немного HTML:

<div class="box">
    <div class="ellipsis" data-tail="some">This is my text it is awesome</div>
</div>
<div class="box">
    <div class="ellipsis">This is my text</div>
</div>

и css:

.box {
    width: 200px;
}

.ellipsis:before {
    float: right;
    content: attr(data-tail);
}

.ellipsis {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

Вот обязательное jsfiddle для этого: http://jsfiddle.net/r96vB/1/

6 голосов
/ 07 мая 2009

Следующая функция Javascript сделает усечение посередине, как OS X:

function smartTrim(string, maxLength) {
    if (!string) return string;
    if (maxLength < 1) return string;
    if (string.length <= maxLength) return string;
    if (maxLength == 1) return string.substring(0,1) + '...';

    var midpoint = Math.ceil(string.length / 2);
    var toremove = string.length - maxLength;
    var lstrip = Math.ceil(toremove/2);
    var rstrip = toremove - lstrip;
    return string.substring(0, midpoint-lstrip) + '...' 
    + string.substring(midpoint+rstrip);
}       

Он заменит символы посередине на многоточие. Мои юнит-тесты показывают:

var s = '1234567890';
assertEquals(smartTrim(s, -1), '1234567890');
assertEquals(smartTrim(s, 0), '1234567890');
assertEquals(smartTrim(s, 1), '1...');
assertEquals(smartTrim(s, 2), '1...0');
assertEquals(smartTrim(s, 3), '1...90');
assertEquals(smartTrim(s, 4), '12...90');
assertEquals(smartTrim(s, 5), '12...890');
assertEquals(smartTrim(s, 6), '123...890');
assertEquals(smartTrim(s, 7), '123...7890');
assertEquals(smartTrim(s, 8), '1234...7890');
assertEquals(smartTrim(s, 9), '1234...67890');
assertEquals(smartTrim(s, 10), '1234567890');
assertEquals(smartTrim(s, 11), '1234567890');
3 голосов
/ 19 мая 2012

Это может быть немного поздно в игре, но я искал решение для этого, и коллега предложил очень элегантный вариант, которым я поделюсь. Требуется немного JS, но не много.

Представьте, что у вас есть div размера, в который нужно поместить свою этикетку:

<div style="width: 200px; overflow: hidden"></div>

Теперь у вас есть функция, которая будет принимать два параметра: строку с меткой и элемент DOM (это div), чтобы соответствовать ей:

function setEllipsisLabel(div, label) 

Первое, что вы делаете, это создаете span с этим ярлыком и помещаете его в div:

var span = document.createElement('span');
span.appendChild(document.createTextNode(label));
span.style.textOverflow = 'ellipsis';
span.style.display = 'inline-block';
div.appendChild(span);

Мы установили для свойства text-overflow значение «многоточие», чтобы по мере того, как текст обрезался, в конце добавлялось «...», чтобы проиллюстрировать это. Мы также устанавливаем display как «встроенный блок», чтобы эти элементы имели реальные размеры в пикселях, которыми мы можем манипулировать позже. Пока что мы ничего не могли бы сделать с чистым CSS.

Но мы хотим, чтобы многоточие было посередине. Во-первых, мы должны выяснить, нужно ли нам это вообще ... Это можно сделать, сравнив div.clientWidth с span.clientWidth - многоточие необходимо, только если span шире, чем div.

Если нам нужен многоточие, давайте начнем с того, что нам нужно, чтобы в конце слова было указано фиксированное количество символов - скажем, 10. Итак, давайте создадим диапазон, содержащий только последние 10 символов метки, и вставим это в div:

var endSpan = document.createElement('span');
endSpan.style.display = 'inline-block';
endspan.appendChild(document.createTextNode(label.substring(label.length - 10)));
div.appendChild(endSpan);

Теперь давайте переопределим ширину исходного span, чтобы приспособить новый:

span.style.width = (div.clientWidth - endSpan.clientWidth) + 'px';

В результате теперь у нас есть структура DOM, которая выглядит примерно так:

<div style="width: 200px; overflow: hidden">
   <span style="display: inline-block; text-overflow: ellipsis; width: 100px">
      A really long label is shown in this span
   </span>
   <span style="display: inline-block"> this span</span>
</div>

Поскольку первый span имеет text-overflow, установленный на «многоточие», в конце будет отображаться «...», за которым следуют 10 символов второго интервала, в результате чего многоточие отображается приблизительно посередине div.

Вам также не нужно жестко задавать 10-символьную длину для endSpan: это может быть аппроксимировано путем вычисления отношения начальной ширины span к ширине div, вычитая соответствующую пропорцию из длины этикетки и деления на два.

3 голосов
/ 07 мая 2009

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

2 голосов
/ 09 июня 2016

После некоторых исследований flex-боксов я нашел это чистое CSS-решение, которое, на мой взгляд, довольно круто.

<div style="width:100%;border:1px solid green;display:inline-flex;flex-wrap:nowrap;">
   <div style="flex: 0 1 content;text-overflow: ellipsis;overflow:hidden;white-space:nowrap;"> Her comes very very very very very very very very very very very very very very very very very very very long </div>
   <div style="flex: 1 0 content;white-space:nowrap;"> &nbsp;but flexible line</div>
</div>
1 голос
/ 17 мая 2019

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

function truncate(text, textLimit) {
    if (!text) return text;
    if (textLimit < 1) return string;
    if (text.length < textLimit) return text;
    if (textLimit === 1) return text.substring(0,1) + '...';
    /* extract the last word */
    var lastPart = text.slice( string.lastIndexOf(' ')+1 );
    /* if last word is longer then a third of the max available space
       cut it from the left */
    var lastPartLimit = Math.ceil(textLimit / 3);
    if(lastPart.length > lastPartLimit) {
        var truncatedLastPart = lastPart;
        /* Try to find a dash and cut the last word there */
        var lastDashPart = text.slice( text.lastIndexOf('-')+1 );
        if(lastDashPart.length < lastPartLimit){
            truncatedLastPart = lastDashPart;
        }
        /* If the last part is still to long or not available cut it anyway */
        if(truncatedLastPart.length > lastPartLimit) {
            var lastIndex = lastPart.length - lastPartLimit;
            truncatedLastPart = lastPart.substring( lastIndex );
        }
        lastPart = truncatedLastPart;
    }
    var dots = '... ';
    var firsPartLength = textLimit - lastPart.length - dots.length;
    return text.substring(0, firstPartLength) + dots + lastPart;
}

console.log( truncate("New York City", 10) ); // Ne... City (max of 10 characters)
console.log( truncate("New York Kindergarden", 14) ); // Ne...ergarden (max of 14 characters, last word gets cut from the left by a third)
console.log( truncate("New York Kinder-garden", 14) ); // Ne...garden (max of 14 characters, last word gets cut by the dash from the left)
1 голос
/ 06 октября 2017

Вот самый короткий бит, который я могу найти, который заменяет 3 символа в середине ....

function shorten(s, max) {
  return s.length > max ? s.substring(0, (max / 2) - 1) + '...' + s.substring(s.length - (max / 2) + 2, s.length) : s
}
0 голосов
/ 30 марта 2016

Чтобы сделать чистый вырез и иметь целое слово в конце сокращенного текста, я использовал следующую функцию.

function prepareText(text){
  var returnString = text;
  var textLimit = 35;
  if(text.length > textLimit){
    var lastWord = text.slice( text.lastIndexOf(' ')+1 );
    var indexFromEnd = lastWord.length;
    var ellipsis = '... ';

    returnString = text.slice(0, textLimit - indexFromEnd - ellipsis.length);
    returnString = returnString + ellipsis + lastWord;
  }
  return returnString;
}

$('#ex1Modified').html( prepareText( $('#ex1').html() ) );

$('#ex2Modified').html( prepareText( $('#ex2').html() ) );

$('#ex3Modified').html( prepareText( $('#ex3').html() ) );
body{color:#777; font-family: sans-serif;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<h2>Shortened Quotes from Albert Einstein</h2>

<div id="ex1">"The true sign of intelligence is not knowledge but imagination."</div>
<div id="ex1Modified"></div>
<br>
<div id="ex2">"Look deep into nature, and then you will understand everything better."</div>
<div id="ex2Modified"></div>
<br>
<div id="ex3">"You can't blame gravity for falling in love."</div>
<div id="ex3Modified"></div>
...