2009-05-06 3 views
34

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

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

становится

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

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

+4

мне было бы интересно увидеть окончательные реализации, если у вас есть. :) –

ответ

23

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

<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; 
} 

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

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

<abbr title="simple tool tip">something</abbr> 
+1

Это оказалось лучшей основой для моего окончательного решения. С несколькими дополнительными строками кода JavaScript он делает именно то, что я хотел сделать. Я решил использовать «title» вместо пользовательского тега, поэтому теперь он обеспечивает доступность естественным образом. Спасибо Stefan, John и Kgiannakakis! –

+3

@ user102465 Можете ли вы поделиться окончательным результатом? Благодаря! – seangates

+2

Есть ли только css? Исправить его в пользовательском интерфейсе, а не использовать javsacript? – Kailas

5

Следующая функция 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'); 
+1

Это замечательно и работает, как описано, однако мне нужно сделать строку вывода «растяжимой», чтобы усечение определялось на основе размера видового экрана. Огромный экран - без усечения, узкая строка экрана усекается с использованием динамически рассчитанного количества символов для наилучшего соответствия. –

+0

Вам нужно будет привязать обработчик события к своему контейнеру, который затем вычислит соответствующую максимальную длину в зависимости от свойства ширины контейнера. Если ваше семейство шрифтов моноширинное, это будет легко; если они пропорциональны, то вам нужно поэкспериментировать, чтобы получить правильную эвристику. – johnvey

+0

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

3

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

+0

Меня интересует ваше мнение об этом: http: // stackoverflow.com/a/36470401/506954 – extempl

3

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

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

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

Теперь у вас есть функция, которая будет принимать два Params: строка с меткой, и элемент 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, вычитая соответствующую долю от длины метки и разделение на два.

7

Итак, мой коллега придумал решение, в котором нет дополнительных элементов 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/

+2

это перерывы в FF – Stanley

+2

Действительно приятное решение, но, к сожалению, оно не работает в Firefox 34 (перекрытие текста) и IE <10 (неподдерживаемый метод querySelector) –

+1

Не работает и на хром. –

0

Я просто создал функцию, которая может подрезать на средний, nearEnd и End, но havent были проверены еще, потому что я, наконец, нуждался в этом на стороне сервера

//position acceptable values : middle, end, closeEnd 
function AddElipsis(input, maxChars, position) { 
    if (typeof input === 'undefined') { 
     return ""; 
    } 
    else if (input.length <= maxChars) { 
     return input; 
    } 
    else { 
     if (position == 'middle') { 
      var midPos = Math.floor(maxChars/2) - 2; 
      return input.substr(0, midPos) + '...' + input.substr(input.length - midPos, input.length); 
     } 
     else if (position == 'closeEnd') { 
      var firstPart = Math.floor(maxChars * 0.80) - 2; 
      var endPart = Math.floor(maxChars * 0.20) - 2; 
      return input.substr(0, firstPart) + '...' + input.substr(input.length - endPart, input.length); 
     } 
     else { 
      return input.substr(0, maxChars - 3) + '...'; 
     } 
    } 
} 
0

Другой удар:

function truncate(str, max, sep) { 
    max = max || 10; 
    var len = str.length; 
    if(len > max){ 
     sep = sep || "..."; 
     var seplen = sep.length; 
     if(seplen > max) { return str.substr(len - max) } 

     var n = -0.5 * (max - len - seplen); 
     var center = len/2; 
     return str.substr(0, center - n) + sep + str.substr(len - center + n); 
    } 
    return str; 
} 

console.log(truncate("123456789abcde")); // 123...bcde (using built-in defaults) 
console.log(truncate("123456789abcde", 8)); // 12...cde (max of 8 characters) 
console.log(truncate("123456789abcde", 12, "_")); // 12345_9abcde (customize the separator) 
0

Это даст вам немного больше контроля над положением многоточием и текст-заполнитель:

function ellipsis(str, maxLength, ellipsisLocationPercentage,placeholder) { 
    /* 
    ARGUMENTS: 
    str - the string you want to maninpulate 
    maxLength - max number of characters allowed in return string 
    ellipsisLocationPercentage (optional) - How far (percentage wise) into the return string you want the ellipses to be placed 
     Examples: 
     .85 : This is a very long string. This is a very long string. This is a very long string. This is a ver[...]very long string. 
     .25 : This is a very long string. [...]g. This is a very long string. This is a very long string. This is a very long string. 
    placeholder (optional) - this will be used to replace the removed substring. Suggestions : '...', '[..]', '[ ... ]', etc.... 
    */ 
    if(ellipsisLocationPercentage == null || isNaN(ellipsisLocationPercentage) || ellipsisLocationPercentage >= 1 || ellipsisLocationPercentage <= 0){ 
     //we've got null or bad data.. default to something fun, like 85% (that's fun, right??) 
     ellipsisLocationPercentage = .85; 
    } 
    if(placeholder == null || placeholder ==""){ 
     placeholder = "[...]"; 
    } 

    if (str.length > (maxLength-placeholder.length)) { 
     //get the end of the string 
     var beginning = str.substr(0, (maxLength - placeholder.length)*ellipsisLocationPercentage); 
     var end = str.substr(str.length-(maxLength - placeholder.length) * (1-ellipsisLocationPercentage)); 
     return beginning + placeholder + end; 
    } 
    return str; 
} 

Вы можете вызвать эту функцию с помощью вызова:

ellipsis("This is a very long string. Be Scared!!!!", 8);//uses default values 
ellipsis("This is a very long string. Be Scared!!!!", 8,.5);//puts ellipsis at half way point 
ellipsis("This is a very long string. Be Scared!!!!", 8,.75,'<..>');//puts ellipsis at 75% of the way into the string and uses '<..>' as the placeholder 
0

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

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>

12

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

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

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

У этого есть некоторые недостатки.

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

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

Gif под спойлер:

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: clip; 
 
    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>

1

После некоторых исследований на гибких коробках я нашел это чистое решение 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> 
+0

Не думайте, что это отвечает на вопрос. Это не решает проблему добавления многоточия в середине строки _1_. Это просто добавляет многоточие между двумя строками. I.e., В сценарии @ user102465 сначала нужно как-то разбить строку, чтобы ваше решение работало. –

0

Вот самое короткое бит я мог найти, который заменяет 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 
} 
Смежные вопросы