<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<title>TEST</title>
<style type="text/css">
.fifth-letter {
background: #aaf;
}
</style>
<p>1234<em>567</em>89</p>
<script type="text/javascript">
function getNthLetterPoint(root, nth) {
var node = root;
var count = nth - 1;
var tmp;
if (count < 0) {
return null;
}
while (node) {
switch (node.nodeType) {
case 3 :
case 4 :
if (node.length > count) {
return [node, count, nth];
}
count -= node.length;
}
if ((tmp = node.firstChild)) {
node = tmp;
continue;
}
do {
if (node === root) {
node = null;
break;
}
if ((tmp = node.nextSibling)) {
node = tmp;
break;
}
} while ((node = node.parentNode));
}
return null;
};
function surroundLetter(point) {
if (point) {
var text = point[0];
var offset = point[1];
var nth = point[2];
var doc = text.ownerDocument;
var span = doc.createElement('span');
try {
var range = text.ownerDocument.createRange();
range.setStart(text, offset);
range.setEnd(text, offset + 1);
range.surroundContents(span);
range.detach();
} catch (err) {
var newText = text.splitText(offset);
span.appendChild(doc.createTextNode(newText.substringData(0, 1)));
newText.deleteData(0, 1);
newText.parentNode.insertBefore(span, newText);
}
return span;
}
return null;
}
// p 要素の 5 番目の文字
var span = surroundLetter(getNthLetterPoint(document.getElementsByTagName('p')[0], 5));
if (span) {
span.className = 'fifth-letter';
}
</script>jQuery('p::-tagindex-nth-letter(5)')jQuery.expr.filters['-tagindex-nth-letter'] = function(node, position, args, nodeset) {
// args => ["::-tagindex-nth-letter(2n+1)", "-tagindex-nth-letter", "", "5"]
};querySelector('p')
.realizePseudoElement('-tagindex-nth-letter(5)')
.asElement('span')
.asClass('fifth-letter')var AsCSS_makeOffsetMapping = (function () {
var S = '\\u0000-\\u0020\\u0085\\u034F\\u2000-\\u200F\\u2060-\\u2063';
var W = new RegExp ('^[' + S + ']+');
var C = new RegExp ('^[^' + S + ']+');
return function (data, offset) {
var sourceCount = 0;
var mappedOffset = 0;
var s;
var r;
var o;
for (s = data; s.length > 0; s = s.slice (r)) {
if ((r = W.exec (s))) {
r = r[0].length;
sourceCount += r;
continue;
}
if ((r = C.exec (s))) {
r = r[0].length;
if (mappedOffset + r > offset) {
break;
}
sourceCount += r;
mappedOffset += r;
continue;
}
throw new Error ('something was wrong.');
}
o = offset - mappedOffset;
return [ o, o + sourceCount ];
};
})();
var DOMCSSNode_getNthLetterCaretPosition = function (root, count, mapper) {
var node = root;
var offset = count - 1;
var n;
var o;
if (offset < 0) {
return null;
}
while (node) {
switch (node.nodeType) {
case 3 :
case 4 :
o = mapper (node.data, offset);
if (o[1] < node.length) {
return [ node, o[1] ];
}
offset = o[0];
}
if ((n = node.firstChild)) {
node = n;
continue;
}
do {
if (node === root) {
node = null;
break;
}
if ((n = node.nextSibling)) {
node = n;
break;
}
} while ((node = node.parentNode));
}
return null;
};
var DOMCSSCaretPosition_surroundLetter = function (point, newParent) {
var text = point[0];
var offset = point[1];
var doc = text.ownerDocument;
if (doc.implementation.hasFeature ('Range', '2.0')) {
var range = text.ownerDocument.createRange ();
range.setStart (text, offset);
range.setEnd (text, offset + 1);
range.surroundContents (newParent);
range.detach ();
} else {
var newText = text.splitText (offset);
if (newParent.hasChildNodes ()) {
newParent.removeChild (newParent.firstChild);
}
newParent.appendChild (doc.createTextNode (newText.substringData (0, 1)));
newText.deleteData (0, 1);
newText.parentNode.insertBefore (newParent, newText);
}
return newParent;
};
var DOMCSSHTMLNode_surroundNthLetter = function (node, count, tagName) {
var point = DOMCSSNode_getNthLetterCaretPosition (node, count, AsCSS_makeOffsetMapping);
var newElt;
if (point) {
newElt = node.ownerDocument.createElement (tagName || 'span');
return DOMCSSCaretPosition_surroundLetter (point, newElt);
}
return null;
};
//______________________________________________________________________
var node = DOMCSSHTMLNode_surroundNthLetter (
document.getElementsByTagName ('p')[5],
5
);
if (node) {
node.className = 'fifth-letter';
}<p>「警部、事件です!」</p> p::first-letter => 「警
<p> <br> ところで、...... </p>