Вставьте многоточие (...) в тег HTML, если содержимое слишком широкое - PullRequest
144 голосов
/ 11 февраля 2009

У меня есть веб-страница с эластичным макетом, которая меняет свою ширину при изменении размера окна браузера.

В этом макете есть заголовки (h2), которые будут иметь переменную длину (на самом деле заголовки из постов блога, которые я не могу контролировать). В настоящее время - если они шире окна - они разбиты на две строки.

Существует ли элегантное, протестированное (кросс-браузерное) решение - например, с jQuery - которое сокращает innerHTML этого тега заголовка и добавляет «...», если текст будет слишком широким, чтобы поместиться в одну строку текущий экран / ширина контейнера?

Ответы [ 24 ]

179 голосов
/ 09 июля 2009

Следующее CSS-решение для усечения текста в одну строку работает со всеми браузерами, перечисленными на http://www.caniuse.com на момент написания, за исключением Firefox 6.0. Обратите внимание, что JavaScript совершенно не нужен, если вам не требуется поддержка переноса многострочного текста или более ранних версий Firefox.

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

Если вам нужна поддержка более ранних версий Firefox, проверьте мой ответ на этот другой вопрос .

118 голосов
/ 21 июня 2009

У меня есть решение, работающее в FF3, Safari и IE6 + с однострочным и многострочным текстом

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

.ellipsis.multiline {
    white-space: normal;
}

<div class="ellipsis" style="width: 100px; border: 1px solid black;">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>
<div class="ellipsis multiline" style="width: 100px; height: 40px; border: 1px solid black; margin-bottom: 100px">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>

<script type="text/javascript" src="/js/jquery.ellipsis.js"></script>
<script type="text/javascript">
$(".ellipsis").ellipsis();
</script>

jquery.ellipsis.js

(function($) {
    $.fn.ellipsis = function()
    {
        return this.each(function()
        {
            var el = $(this);

            if(el.css("overflow") == "hidden")
            {
                var text = el.html();
                var multiline = el.hasClass('multiline');
                var t = $(this.cloneNode(true))
                    .hide()
                    .css('position', 'absolute')
                    .css('overflow', 'visible')
                    .width(multiline ? el.width() : 'auto')
                    .height(multiline ? 'auto' : el.height())
                    ;

                el.after(t);

                function height() { return t.height() > el.height(); };
                function width() { return t.width() > el.width(); };

                var func = multiline ? height : width;

                while (text.length > 0 && func())
                {
                    text = text.substr(0, text.length - 1);
                    t.html(text + "...");
                }

                el.html(t.html());
                t.remove();
            }
        });
    };
})(jQuery);
39 голосов
/ 31 января 2012

Я создал этот код, используя ряд других постов, со следующими улучшениями:

  1. Он использует двоичный поиск, чтобы найти правильную длину текста.
  2. Он обрабатывает случаи, когда элементы (элементы) эллипса изначально скрыты, путем настройки события показа одного кадра, который повторно запускает код многоточия при первом отображении элемента. Это удобно для представлений основной детали или древовидных представлений, где некоторые элементы изначально не отображаются.
  3. Опционально добавляет атрибут заголовка с исходным текстом для эффекта наведения.
  4. Добавлен display: block к стилю, поэтому пролет работает
  5. Используется символ многоточия вместо 3 периодов.
  6. Он автоматически запускает скрипт для всего с классом .ellipsis

CSS:

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

.ellipsis.multiline {
        white-space: normal;
}

jquery.ellipsis.js

(function ($) {

    // this is a binary search that operates via a function
    // func should return < 0 if it should search smaller values
    // func should return > 0 if it should search larger values
    // func should return = 0 if the exact value is found
    // Note: this function handles multiple matches and will return the last match
    // this returns -1 if no match is found
    function binarySearch(length, func) {
        var low = 0;
        var high = length - 1;
        var best = -1;
        var mid;

        while (low <= high) {
            mid = ~ ~((low + high) / 2); //~~ is a fast way to convert something to an int
            var result = func(mid);
            if (result < 0) {
                high = mid - 1;
            } else if (result > 0) {
                low = mid + 1;
            } else {
                best = mid;
                low = mid + 1;
            }
        }

        return best;
    }

    // setup handlers for events for show/hide
    $.each(["show", "toggleClass", "addClass", "removeClass"], function () {

        //get the old function, e.g. $.fn.show   or $.fn.hide
        var oldFn = $.fn[this];
        $.fn[this] = function () {

            // get the items that are currently hidden
            var hidden = this.find(":hidden").add(this.filter(":hidden"));

            // run the original function
            var result = oldFn.apply(this, arguments);

            // for all of the hidden elements that are now visible
            hidden.filter(":visible").each(function () {
                // trigger the show msg
                $(this).triggerHandler("show");
            });

            return result;
        };
    });

    // create the ellipsis function
    // when addTooltip = true, add a title attribute with the original text
    $.fn.ellipsis = function (addTooltip) {

        return this.each(function () {
            var el = $(this);

            if (el.is(":visible")) {

                if (el.css("overflow") === "hidden") {
                    var content = el.html();
                    var multiline = el.hasClass('multiline');
                    var tempElement = $(this.cloneNode(true))
                        .hide()
                        .css('position', 'absolute')
                        .css('overflow', 'visible')
                        .width(multiline ? el.width() : 'auto')
                        .height(multiline ? 'auto' : el.height())
                    ;

                    el.after(tempElement);

                    var tooTallFunc = function () {
                        return tempElement.height() > el.height();
                    };

                    var tooWideFunc = function () {
                        return tempElement.width() > el.width();
                    };

                    var tooLongFunc = multiline ? tooTallFunc : tooWideFunc;

                    // if the element is too long...
                    if (tooLongFunc()) {

                        var tooltipText = null;
                        // if a tooltip was requested...
                        if (addTooltip) {
                            // trim leading/trailing whitespace
                            // and consolidate internal whitespace to a single space
                            tooltipText = $.trim(el.text()).replace(/\s\s+/g, ' ');
                        }

                        var originalContent = content;

                        var createContentFunc = function (i) {
                            content = originalContent.substr(0, i);
                            tempElement.html(content + "…");
                        };

                        var searchFunc = function (i) {
                            createContentFunc(i);
                            if (tooLongFunc()) {
                                return -1;
                            }
                            return 0;
                        };

                        var len = binarySearch(content.length - 1, searchFunc);

                        createContentFunc(len);

                        el.html(tempElement.html());

                        // add the tooltip if appropriate
                        if (tooltipText !== null) {
                            el.attr('title', tooltipText);
                        }
                    }

                    tempElement.remove();
                }
            }
            else {
                // if this isn't visible, then hook up the show event
                el.one('show', function () {
                    $(this).ellipsis(addTooltip);
                });
            }
        });
    };

    // ellipsification for items with an ellipsis
    $(document).ready(function () {
        $('.ellipsis').ellipsis(true);
    });

} (jQuery));
20 голосов
/ 24 февраля 2012

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

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

Сначала он находит «примерную» длину текста, а затем добавляет или удаляет символ, пока ширина не станет правильной.

Используемая логика показана ниже:

enter image description here

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

Я уверен, что нужно немного доработать, но вот код:

(function ($) {
    $.fn.ellipsis = function () {
        return this.each(function () {
            var el = $(this);

            if (el.css("overflow") == "hidden") {
                var text = el.html().trim();
                var t = $(this.cloneNode(true))
                                        .hide()
                                        .css('position', 'absolute')
                                        .css('overflow', 'visible')
                                        .width('auto')
                                        .height(el.height())
                                        ;
                el.after(t);

                function width() { return t.width() > el.width(); };

                if (width()) {

                    var myElipse = "....";

                    t.html(text);

                    var suggestedCharLength = (text.length * el.width() / t.width()) - myElipse.length;

                    t.html(text.substr(0, suggestedCharLength) + myElipse);

                    var x = 1;
                    if (width()) {
                        while (width()) {
                            t.html(text.substr(0, suggestedCharLength - x) + myElipse);
                            x++;
                        }
                    }
                    else {
                        while (!width()) {
                            t.html(text.substr(0, suggestedCharLength + x) + myElipse);
                            x++;
                        }
                        x--;
                        t.html(text.substr(0, suggestedCharLength + x) + myElipse);
                    }

                    el.html(t.html());
                    t.remove();
                }
            }
        });
    };
})(jQuery);
18 голосов
/ 26 декабря 2009

Я сделал действительно классный плагин jQuery для обработки всех разновидностей многоточия текста, который называется ThreeDots @ http://tpgblog.com/threedots

Он гораздо более гибкий, чем подходы CSS, и поддерживает гораздо более сложные, настраиваемые способы поведения и взаимодействия.

Наслаждайтесь.

18 голосов
/ 24 октября 2013

На всякий случай, если вы окажетесь здесь в 2013 году - вот простой подход CSS, который я нашел здесь: http://css -tricks.com / snippets / css / truncate-string-with-ellipsis /

.truncate {
  width: 250px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

Работает хорошо.

8 голосов
/ 11 октября 2011

Более гибкий плагин jQuery, позволяющий вам сохранять элемент после многоточия (например, кнопку «Читать далее») и обновлять onWindowResize. Он также работает с текстом с разметкой:

http://dotdotdot.frebsite.nl

8 голосов
/ 24 августа 2012

trunk8 Плагин jQuery поддерживает несколько строк и может использовать любой html, а не только символы многоточия, для суффикса усечения: https://github.com/rviscomi/trunk8

Демо здесь: http://jrvis.com/trunk8/

5 голосов
/ 11 февраля 2009

На самом деле довольно простой способ сделать это в CSS , используя тот факт, что IE расширяет это с нестандартными, а FF поддерживает :after

Вы также можете сделать это в JS , если хотите, проверив scrollWidth цели и сравнив ее с шириной родительских элементов, но, на мой взгляд, это менее надежно.

Редактировать: это явно более развито, чем я думал. Поддержка CSS3 может скоро появиться, и вам доступны некоторые несовершенные расширения.

Последний хорошо читается.

3 голосов
/ 11 февраля 2009

Я недавно сделал что-то подобное для клиента. Вот версия того, что я для них сделал (пример протестирован во всех последних версиях браузера на Win Vista). Не идеален по всей доске, но может быть легко подправлен.

Демо: http://enobrev.info/ellipsis/

Код:

<html>
    <head>
        <script src="http://www.google.com/jsapi"></script>
        <script>            
            google.load("jquery", "1.2.6");
            google.setOnLoadCallback(function() {
                $('.longtext').each(function() {
                    if ($(this).attr('scrollWidth') > $(this).width()) {
                        $more = $('<b class="more">&hellip;</b>');

                        // add it to the dom first, so it will have dimensions
                        $(this).append($more);

                        // now set the position
                        $more.css({
                            top: '-' + $(this).height() + 'px',
                            left: ($(this).attr('offsetWidth') - $more.attr('offsetWidth')) + 'px'
                        });
                    }
                });
            });
        </script>

        <style>
            .longtext {
                height: 20px;
                width: 300px;
                overflow: hidden;
                white-space: nowrap;
                border: 1px solid #f00;
            }

            .more {
                z-index: 10;
                position: relative;
                display: block;
                background-color: #fff;
                width: 18px;
                padding: 0 2px;
            }
        </style>
    </head>
    <body>
        <p class="longtext">This is some really long text.  This is some really long text.  This is some really long text.  This is some really long text.</p>
    </body>
</html>
...