Detecting CSS text-overflow: ellipsis in Firefox
Asked Answered
T

2

10

I'm trying to detect (via javascript) when text-overflow is in effect. After much research, I have a working solution, except in any version of Firefox:

http://jsfiddle.net/tonydew/mjnvk/

If you adjust the browser so that the ellipsis is applied, Chrome, Safari, even IE8+ will alert that the ellipsis is active. In Firefox (every version I have tried, including 17 and 18) not so much. Firefox will always tell you ellipsis is NOT active.

The console.log() output shows why:

Firefox (OS X):
116/115 - false
347/346 - false

Chrome (OS X):
116/115 - false
347/851 - true 

In Firefox, scrollWidth is never greater than offsetWidth.

The closest thing I can find to a solution is "Why are IE and Firefox returning different overflow dimensions for a div?" but I am already using the proposed solution.

Can anyone shed some light on how to make this work in Firefox too please?


EDIT: In addition to @Cezary answer below, I found a method thay does not require changes to the markup. However, it is doing a little more work because it temporarily clones each element to do the measurement against:
$(function() {
    $('.overflow').each(function(i, el) {
        var element = $(this)
                      .clone()
                      .css({display: 'inline', width: 'auto', visibility: 'hidden'})
                      .appendTo('body');

        if( element.width() > $(this).width() ) {
            $(this).tooltip({
                title: $(this).text(),
                delay: { show: 250, hide: 100 },
            });
        }
        element.remove();
    });
});

http://jsfiddle.net/tonydew/gCnXh/

Anybody have a comment on the efficiency of this? If I have a page of many potential overflow elements, is this going to have negative effects? I'd like to avoid modifying existing markup if I can, but not at the expense of excessive JS processing on each page load.

Tsan answered 1/2, 2013 at 7:28 Comment(3)
Why did you create a new account for this question? Judging by your perfectly tagged and formatted post, you obviously have another account you use to answer questions.Tremaine
No other account that I know of! The tags and formatting are the way they are because I didn't want to be the guy that asks poorly prepared questions. I'm not up to no good; just trying to ask the best question I can so it gets answered!Tsan
Thank you, by the way... for the compliment and the +1 :)Tsan
S
6

you need to add div inside each td to make it work in firefox,

<td class="first"><div>Here is some text</div></td>
<td class="second">
     <div>Here is some more text. A lot more text than
     the first one. In fact there is so much text you'd think it was a 
     waste of time to type all ofit.
     </div>
</td>

CSS

td div {
   white-space: nowrap;
   text-overflow: ellipsis;
   overflow:hidden;
   width:100%;
}

Jsfiddle

http://jsfiddle.net/mjnvk/7/

Sombrous answered 1/2, 2013 at 9:22 Comment(2)
Hey! Thank you. That works pretty well, but I have to change markup everywhere.Tsan
If changing the markup is a problem, then I guess since you're doing the calculation in JS you could always have JS dynamically adjust the markup for you as well.Bolshevist
M
3

I actually wrote a jQuery plugin to do this. It simply sets the title of the target element to the entire text if truncated, but you can adapt it for your exact needs:

/**
 * @author ach
 *
 * Sets the CSS white-space, overflow, and text-overflow properties such that text in the selected block element will
 * be truncated and appended with an ellipsis (...) if overflowing.  If the text is truncated in such a way, the
 * selected element's 'title' will be set to its full text contents and the cursor will be set to 'default'.
 * For this plugin to work properly, it should be used on block elements (p, div, etc.).  If used on a th or td element,
 * the plugin will wrap the contents in a div -- in this case, the table's 'table-layout' CSS property should be set to 'fixed'.
 *
 * The default CSS property values set by this plugin are:
 *     white-space: nowrap;
 *     overflow: hidden;
 *     text-overflow: ellipsis
 *
 * @param cssMap A map of css properties that will be applied to the selected element.  The default white-space,
 * overflow, and text-overflow values set by this plugin can be overridden in this map.
 *
 * @return The selected elements, for chaining
 */

$.fn.truncateText = function(cssMap) {
    var css = $.extend({}, $.fn.truncateText.defaults, cssMap);

    return this.each(function() {
        var $this = $(this);
        //To detect overflow across all browsers, create an auto-width invisible element and compare its width to the actual element's
        var element = $this.clone().css({display: 'inline', width: 'auto', visibility: 'hidden'}).appendTo('body');
        if (element.width() > $this.width()) {
            //If a th or td was selected, wrap the content in a div and operate on that
            if ($this.is("th, td")) {
                $this = $this.wrapInner('<div></div>').find(":first");
            }
            $this.css(css);
            $this.attr("title", $.trim($this.text()));
            $this.css({"cursor": "default"});
        }
        element.remove();
    });
};
$.fn.truncateText.defaults = {
    "white-space"   : "nowrap",
    "overflow"      : "hidden",
    "text-overflow" : "ellipsis"
};

And to use, simply include the js and call:

$(".override").truncateText();

This has been used in production, and haven't noticed any ill effects with hundreds of target elements on a page.

Midnight answered 1/2, 2013 at 20:42 Comment(1)
This validates the method I put in my edited question. It's good to hear that you haven't noticed any ill effects with that many elements on the page.Tsan

© 2022 - 2024 — McMap. All rights reserved.