回答編集履歴
1
TreeWalkerでの例を追加。
    
        answer	
    CHANGED
    
    | @@ -1,3 +1,53 @@ | |
| 1 1 | 
             
            この手のものをまともに処理しようとするとかなり複雑になるし、全角/半角は言うのは簡単ですが判別は大変です。
         | 
| 2 2 | 
             
            そこで、幅を固定し、text-overflow: ellipsis を使うのはどうでしょうか?
         | 
| 3 | 
            -
            [https://developer.mozilla.org/ja/docs/Web/CSS/text-overflow](https://developer.mozilla.org/ja/docs/Web/CSS/text-overflow)
         | 
| 3 | 
            +
            [https://developer.mozilla.org/ja/docs/Web/CSS/text-overflow](https://developer.mozilla.org/ja/docs/Web/CSS/text-overflow)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            -- 追記。
         | 
| 6 | 
            +
            ノード操作をした一例です。ちょっとうんざりしてくるのではないでしょうか?
         | 
| 7 | 
            +
            ```JavaScript
         | 
| 8 | 
            +
            function isHalf(code) {
         | 
| 9 | 
            +
              return (code >= 0x0 && code < 0x81) || (code == 0xf8f0) || (code >= 0xff61 && code < 0xffa0) || (code >= 0xf8f1 && code < 0xf8f4);
         | 
| 10 | 
            +
            }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            function truncateTextNode(textNode) {
         | 
| 13 | 
            +
              var text = textNode.nodeValue;
         | 
| 14 | 
            +
              var newText = '';
         | 
| 15 | 
            +
              for (var i = 0; i < text.length; i++) {
         | 
| 16 | 
            +
                var c = text.charCodeAt(i);
         | 
| 17 | 
            +
                var cost = isHalf(c) ? 0.5 : 1;
         | 
| 18 | 
            +
                if (cost > remain) {
         | 
| 19 | 
            +
                  remain = -1;
         | 
| 20 | 
            +
                  textNode.nodeValue = newText;
         | 
| 21 | 
            +
                  return;
         | 
| 22 | 
            +
                }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                newText += text.charAt(i);
         | 
| 25 | 
            +
                remain -= cost;
         | 
| 26 | 
            +
              }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              textNode.nodeValue = newText;
         | 
| 29 | 
            +
            }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            var remain = 50;
         | 
| 32 | 
            +
            var root = document.querySelector('p.txt');
         | 
| 33 | 
            +
            var tw = document.createTreeWalker(root);
         | 
| 34 | 
            +
            var node;
         | 
| 35 | 
            +
            while (node = tw.nextNode()) {
         | 
| 36 | 
            +
              switch (node.nodeType) {
         | 
| 37 | 
            +
                case document.ELEMENT_NODE:
         | 
| 38 | 
            +
                  if (remain < 0) {
         | 
| 39 | 
            +
                    node.setAttribute('data-remove', '1');
         | 
| 40 | 
            +
                  }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  break;
         | 
| 43 | 
            +
                case document.TEXT_NODE:
         | 
| 44 | 
            +
                  truncateTextNode(node);
         | 
| 45 | 
            +
                  break;
         | 
| 46 | 
            +
              }
         | 
| 47 | 
            +
            }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            if (remain < 0) {
         | 
| 50 | 
            +
              $(root.querySelectorAll('[data-remove]')).remove();
         | 
| 51 | 
            +
              root.appendChild(document.createTextNode('…'));
         | 
| 52 | 
            +
            }
         | 
| 53 | 
            +
            ```
         | 
