Highlighting Combining Characters

Problem

I'm trying to build a little system which highlights combining characters in a different color than regular characters. Take the following example:

* { font-size: 72px }
b { font-weight: normal; color: red }
Te&#x301;st A&#x334; B&#x353; <br/>
Te<b>&#x301;</b>st A<b>&#x334;</b> B<b>&#x353;</b>

I'd like the three combining characters (acute accent, tilde overlay, and x below) to be highlighted in red, but remain precisely where they were if in the original text. The problem is, when I wrap a combining character in an HTML element, it is no longer 'attached' to the base character and instead inline with the rest of the text.

Is there any way to accomplish this with HTML / CSS?

Note: I have reviewed the answers here and here, but they all seem to only attack the problem 'geometrically'—that is they highlight the part of a character within a certain region. This question is specifically about highlight the 'typographical' aspects of the combining characters.

Problem courtesy of: p.s.w.g

Solution

I'm revisting this question almost a year later, and I've figured out a more satisfactory (though far more verbose) solution using SVG. Basically, this is the similar to my previous HTML/CSS-based version, but SVG gives you the power to do clip / mask out the anti-aliased edges of the underlying base character.

The only really problem remaining is how to handle overlay characters (where the combining character is rendered directly on top of the underlying character). In this case you'd either need to render the base character on top of the overlay (not preferable in my use case) or render the overlay on an placeholder white space character which will not necessarily perfectly match the width of the base character. Here's a demonstration:

svg text {
  x: 50px;
  y: 50px;
  alignment-baseline: middle;
  text-anchor: middle;
  font-size: 55px;
}
svg .backdrop {
  x: 1px;
  y: 1px;
  rx: 15px;
  ry: 15px;
  width: 98px;
  height: 98px;
  fill: url(#grad);
}
svg .cc-above { fill: #F00; }
svg .cc-below { fill: #00F; }
svg .cc-overlay { fill: #0FF; }
svg .cc-base { fill: #000; }
svg .cc-mask { stroke: #000; stroke-width: 3px; }
.sample { float: left; }
.caption { display: block; text-align: center; }
<div class="sample">
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100px" height="100px" viewBox="0 0 100 100">
    <defs>
      <text id="base" x="50" y="50">e</text>
      <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:#DDD;stop-opacity:1" />
        <stop offset="100%" style="stop-color:#888;stop-opacity:1" />
      </linearGradient>
    </defs>
    <rect class="backdrop" />
    <mask id="mask1">
      <rect x="0" y="0" width="100%" height="100%" fill="#fff" />
      <use xlink:href="#base" class="cc-mask" />
    </mask>
    <text class="cc-above" x="50%" y="50%" mask="url(#mask1)">e&#x0300;</text>
    <use xlink:href="#base" class="cc-base" />
  </svg>
  <div class="caption">Above</div>
</div>

<div class="sample">
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100px" height="100px" viewBox="0 0 100 100">
    <defs>
      <text id="base" x="50" y="50">e</text>
      <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:#DDD;stop-opacity:1" />
        <stop offset="100%" style="stop-color:#888;stop-opacity:1" />
      </linearGradient>
    </defs>
    <rect class="backdrop" />
    <mask id="mask1">
      <rect x="0" y="0" width="100%" height="100%" fill="#fff" />
      <use xlink:href="#base" class="cc-mask" />
    </mask>
    <text class="cc-below" x="50%" y="50%" mask="url(#mask1)">e&#x031F;</text>
    <use xlink:href="#base" class="cc-base" />
  </svg>
  <div class="caption">Below</div>
</div>

<div class="sample">
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100px" height="100px" viewBox="0 0 100 100">
    <defs>
      <text id="base" x="50" y="50">e</text>
      <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:#DDD;stop-opacity:1" />
        <stop offset="100%" style="stop-color:#888;stop-opacity:1" />
      </linearGradient>
    </defs>
    <rect class="backdrop" />
    <mask id="mask1">
      <rect x="0" y="0" width="100%" height="100%" fill="#fff" />
      <use xlink:href="#base" class="cc-mask" />
    </mask>
    <use xlink:href="#base" class="cc-base" />
    <text class="cc-overlay" x="50%" y="50%">&#x2002;&#x0334;</text>
  </svg>
  <div class="caption">Overlay</div>
</div>

<div class="sample">
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100px" height="100px" viewBox="0 0 100 100">
    <defs>
      <text id="base" x="50" y="50">e</text>
      <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:#DDD;stop-opacity:1" />
        <stop offset="100%" style="stop-color:#888;stop-opacity:1" />
      </linearGradient>
    </defs>
    <rect class="backdrop" />
    <mask id="mask1">
      <rect x="0" y="0" width="100%" height="100%" fill="#fff" />
      <use xlink:href="#base" class="cc-mask" />
    </mask>
    <text class="cc-above" x="50%" y="50%" mask="url(#mask1)">e&#x0300;</text>
    <text class="cc-below" x="50%" y="50%" mask="url(#mask1)">e&#x031F;</text>
    <use xlink:href="#base" class="cc-base" />
    <text class="cc-overlay" x="50%" y="50%">&#x2002;&#x0334;</text>
  </svg>
  <div class="caption">All</div>
</div>

I don't have all that much experience with SVG, and someone that does may be able to find a way to improve upon this solution further.

Solution courtesy of: p.s.w.g

Discussion

This is a hack but what about using text-indent:-1ex to move the accent back 1 character width. http://jsfiddle.net/1tm1Lrrp/4/

In any case none of these suggestions would work with an i because the dot would still be there.

Discussion courtesy of: mdf

Okay I think I've found a partial solution, but it's a bit tricky. Basically, I have to render the entire character, with combining characters, then hide it with another character on top of it without any combining characters:

* { font-size: 72px }
b { font-weight: normal; color: red; width: 0px; overflow: visible; display: inline-block; }
i { font-style: normal; color: black; }
Te&#x0301;st <br/>
T<b>e&#x0301;</b><i>e</i>st

Unfortunately, this gives a very slight red outline to the base character when anti-aliased.

enter image description here

And it won't work for certain overlay characters. In this example, the red bar should be on black d:

* { font-size: 72px }
b { font-weight: normal; color: red; width: 0px; overflow: visible; display: inline-block; }
i { font-style: normal; color: black; }
d&#x336; <br/>
<b>d&#x336;</b><i>d</i>

Discussion courtesy of: p.s.w.g

I am not confident I have completely understood your issue, but here goes. If you simply need the accent to return to the correct position now it is styled separately, you could apply the something similar to:

* { font-size: 72px }
b { font-weight: normal; color: red; position: absolute; top: 52%;}
Te&#x0301;st <br/>
Te<b>&#x0301;</b>st

Discussion courtesy of: Martyn0627

This recipe can be found in it's original form on Stack Over Flow.