Выделение сочетания персонажей

Я пытаюсь создать небольшую систему, которая выделяет комбинирование символов другим цветом, чем обычные символы. Возьмите следующий пример:

* { 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>

Мне бы хотелось, чтобы три комбинирующих символа (острый акцент, наложение тильды и х ниже) были выделены красным, но остались точно такими же, как в исходном тексте. Проблема заключается в том, что когда я заключаю комбинированный символ в элемент HTML, он больше не "привязывается" к базовому символу и вместо этого встроен в остальную часть текста.

Есть ли способ сделать это с помощью HTML / CSS?

Примечание: я рассмотрел ответы здесь и здесь, но все они, кажется, только атакуют проблему "геометрически", то есть они выделяют часть персонажа в определенном регионе. Этот вопрос конкретно о выделении "типографских" аспектов сочетания символов.

4 ответа

Решение

Я пересматриваю этот вопрос почти год спустя, и я нашел более удовлетворительное (хотя и более подробное) решение с использованием SVG. По сути, это похоже на мою предыдущую версию на основе HTML/CSS, но SVG дает вам возможность вырезать / маскировать сглаженные края базового базового символа.

Единственная действительно остающаяся проблема заключается в том, как обрабатывать наложенные символы (где комбинирующий символ отображается непосредственно поверх основного символа). В этом случае вам нужно будет либо визуализировать базовый символ поверх наложения (не желательно в моем случае использования), либо визуализировать наложение на символ пробела-заполнителя, который не обязательно будет полностью соответствовать ширине базового символа. Вот демонстрация:

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>

У меня нет такого большого опыта работы с SVG, и кто-то может найти способ улучшить это решение дальше.

Я не уверен, что полностью понял вашу проблему, но здесь идет. Если вам просто нужен акцент, чтобы вернуться в правильную позицию, теперь он оформлен отдельно, вы можете применить что-то похожее на:

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

Хорошо, я думаю, что нашел частичное решение, но это немного сложно. По сути, мне нужно визуализировать весь символ с помощью комбинированных символов, а затем скрыть его с другим символом поверх него без каких-либо комбинирующих символов:

* { 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

К сожалению, это дает очень легкий красный контур базовому символу при сглаживании.

введите описание изображения здесь

И это не будет работать для определенных наложенных символов. В этом примере красная полоса должна быть на черном 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>

Это взломать, но как насчет использования text-indent:-1ex переместить акцент обратно на 1 символ шириной. http://jsfiddle.net/1tm1Lrrp/4/

В любом случае ни одно из этих предложений не будет работать с i, потому что точка все еще будет там.

Другие вопросы по тегам