web-dev-qa-db-ja.com

HTMLテキストオーバーフローエリプシス検出

ページにブロック要素のコレクションがあります。これらはすべて、CSSルールのホワイトスペース、オーバーフロー、テキストオーバーフローが設定されているため、オーバーフローしたテキストはトリミングされ、省略記号が使用されます。

ただし、すべての要素がオーバーフローするわけではありません。

とにかくjavascriptを使用してオーバーフローしている要素を検出できますか?

ありがとう。

追加:作業中のHTML構造の例。

<td><span>Normal text</span></td>
<td><span>Long text that will be trimmed text</span></td>

SPAN要素は常にセルに収まり、省略規則が適用されます。省略記号がSPANのテキストコンテンツに適用されるタイミングを検出したい。

152
deanoj

むかしむかし、これを行う必要がありましたが、クロスブラウザーで信頼できる唯一の解決策は、ハックジョブでした。私はこのようなソリューションの最大のファンではありませんが、何度も何度も正しい結果を生み出します。

アイデアは、要素を複製し、境界幅を削除し、複製された要素が元の要素よりも広いかどうかをテストすることです。もしそうなら、あなたはそれが切り捨てられるだろうことを知っています。

たとえば、jQueryを使用する場合:

var $element = $('#element-to-test');
var $c = $element
           .clone()
           .css({display: 'inline', width: 'auto', visibility: 'hidden'})
           .appendTo('body');

if( $c.width() > $element.width() ) {
    // text was truncated. 
    // do what you need to do
}

$c.remove();

これを実証するためにjsFiddleを作成しました http://jsfiddle.net/cgzW8/2/

JQuery用の独自のカスタム擬似セレクターを作成することもできます。

$.expr[':'].truncated = function(obj) {
  var $this = $(obj);
  var $c = $this
             .clone()
             .css({display: 'inline', width: 'auto', visibility: 'hidden'})
             .appendTo('body');

  var c_width = $c.width();
  $c.remove();

  if ( c_width > $this.width() )
    return true;
  else
    return false;
};

次に、それを使用して要素を見つけます

$truncated_elements = $('.my-selector:truncated');

デモ: http://jsfiddle.net/cgzW8/293/

うまくいけば、これはそのままハッキーです。

105
Christian Varga

引数としてspan要素を渡して、このJS関数を試してください:

function isEllipsisActive(e) {
     return (e.offsetWidth < e.scrollWidth);
}
235
Italo Borssatto

Italoの答えに加えて、jQueryを使用してこれを行うこともできます。

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.width() < $jQueryObject[0].scrollWidth);
}

また、Smokyが指摘したように、width()の代わりにjQuery outerWidth()を使用することもできます。

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.outerWidth() < $jQueryObject[0].scrollWidth);
}
13
Alex K

Christian Vargaから受け入れられた回答を使用している(または使用を計画している)場合は、パフォーマンスの問題に注意してください。

このような方法でDOMを複製/操作すると、DOMリフローDOMリフローの説明 を参照)が非常にリソースになります集中的な。

ページ上の100個以上の要素でChristian Vargaのソリューションを使用すると、JSスレッドがロックされる4秒のリフロー遅延が発生しました。 JSがシングルスレッドであると考えると、これはエンドユーザーにとって大幅なUXの遅延を意味します。

Italo Borssattoの answer は受け入れられるはずです。プロファイリング中に約10倍速くなりました。

7
RyanGled

elem.offsetWdith VS ele.scrollWidthこれは私のために働きます! https://jsfiddle.net/gustavojuan/210to9p1/

$(function() {
  $('.endtext').each(function(index, elem) {
    debugger;
    if(elem.offsetWidth !== elem.scrollWidth){
      $(this).css({color: '#FF0000'})
    }
  });
});
5
Gustavo Juan

最も単純な(およびクロスブラウザー)ソリューションは、実際にscrollWidthとclientWidthを比較することです

ここでの作業コード: https://stackoverflow.com/a/19156627/1213445

5
NicolasBernier

このサンプルでは、​​テキストが切り捨てられたセルテーブルにツールチップが表示されます。テーブル幅に基づいて動的です:

$.expr[':'].truncated = function (obj) {
    var element = $(obj);

    return (element[0].scrollHeight > (element.innerHeight() + 1)) || (element[0].scrollWidth > (element.innerWidth() + 1));
};

$(document).ready(function () {
    $("td").mouseenter(function () {
        var cella = $(this);
        var isTruncated = cella.filter(":truncated").length > 0;
        if (isTruncated) 
            cella.attr("title", cella.text());
        else 
            cella.attr("title", null);
    });
});

デモ: https://jsfiddle.net/t4qs3tqs/

JQueryのすべてのバージョンで動作します

4
Red

italoからの回答はとても良いです!ただし、少し改良してみましょう。

function isEllipsisActive(e) {
   var tolerance = 2; // In px. Depends on the font you are using
   return e.offsetWidth + tolerance < e.scrollWidth;
}

クロスブラウザの互換性

実際、上記のコードを試してconsole.logを使用してe.offsetWidthおよびe.scrollWidthの値を出力すると、IEでは、テキストがなくても気付くでしょう。切り捨て、1pxまたは2pxの値の違いが発生します。

したがって、使用するフォントサイズに応じて、一定の許容値を許可してください。

3
Andry

それを検出するより良い方法はgetClientRects()を使用することだと思います。各rectの高さが同じであると思われるので、行番号を異なるtop値の数で計算できます。

getClientRectsthis のように動作します

function getRowRects(element) {
    var rects = [],
        clientRects = element.getClientRects(),
        len = clientRects.length,
        clientRect, top, rectsLen, rect, i;

    for(i=0; i<len; i++) {
        has = false;
        rectsLen = rects.length;
        clientRect = clientRects[i];
        top = clientRect.top;
        while(rectsLen--) {
            rect = rects[rectsLen];
            if (rect.top == top) {
                has = true;
                break;
            }
        }
        if(has) {
            rect.right = rect.right > clientRect.right ? rect.right : clientRect.right;
            rect.width = rect.right - rect.left;
        }
        else {
            rects.Push({
                top: clientRect.top,
                right: clientRect.right,
                bottom: clientRect.bottom,
                left: clientRect.left,
                width: clientRect.width,
                height: clientRect.height
            });
        }
    }
    return rects;
}

getRowRectsthis のように動作します

this のように検出できます

1
Defims

すべてのソリューションは実際には機能しませんでした。didの機能は、要素scrollWidthをその親のscrollWidthと比較することでした(または、トリガーを持つ要素に応じて子)。

子のscrollWidthがその親よりも高い場合、.text-Ellipsisがアクティブであることを意味します。


eventが親要素の場合

function isEllipsisActive(event) {
    let el          = event.currentTarget;
    let width       = el.offsetWidth;
    let widthChild  = el.firstChild.offsetWidth;
    return (widthChild >= width);
}

eventが子要素の場合

function isEllipsisActive(event) {
    let el          = event.currentTarget;
    let width       = el.offsetWidth;
    let widthParent = el.parentElement.scrollWidth;
    return (width >= widthParent);
}
1

e.offsetWidth < e.scrollWidthソリューションが常に機能するとは限りません。

また、純粋なJavaScriptを使用する場合は、これを使用することをお勧めします。

(TypeScript)

public isEllipsisActive(element: HTMLElement): boolean {
    element.style.overflow = 'initial';
    const noEllipsisWidth = element.offsetWidth;
    element.style.overflow = 'hidden';
    const ellipsisWidth = element.offsetWidth;

    if (ellipsisWidth < noEllipsisWidth) {
      return true;
    } else {
      return false;
    }
}
0
Sarel Zioni