Skip to content Skip to sidebar Skip to footer

How To Display Accents Over Words With Different Colors In HTML/CSS?

I have some text like this, displayed in HTML: pīng​pāng​qiú​pāi How can I change the text color, such that the text is blue while the accents above are red?

Solution 1:

CSS treats the letter as a whole and therefore it can only be 1 colour.

Here is a hacky version:

This will only work if the content will stay the same.

span{
  font-size:48px;
  color:blue;
  position:relative;
}
span:after{
  content:'pīng​pāng​qiú​pāi';
  position:absolute;
  left:0;
  height:18px;
  overflow:hidden;
  z-index:9999;
  color:red;
  top:-5px;
}
<span>pīng​pāng​qiú​pāi</span>

Personally, I wouldn't use this. It's a horrible way of doing it.


Solution 2:

I think you don't have any clean solution using pure CSS. As given by BeatAlex, it's a good idea for you to implement some script solving your problem beautifully. In fact I thought of using 2 overlays to create the effect you want, however the difference from the BeatAlex's idea is the top overlay will be the non-accented versions of accented letters. It requires us to convert accented letters to the corresponding non-accented letters. However I found that the idea of using overflow:hidden applied in this case is really good. I would like to borrow this idea and implement a script fulfilling the solution (which is completely usable). The idea is you just need to find all the accented letters (in the original text), wrap each one with a span element and then apply the style to these span elemnents. I would like to mention that I've not implemented the right code to be able to filter/detect all the possible accented letters, finally this is still a start for you to complete it. Code details:

CSS:

.distinct-accent {
  font-size:30px;
  color:blue;
}
.with-accent {
  position:relative;     
  display:inline-block;    
}
.with-accent:before {
  content:attr(data-content);
  position:absolute;
  left:0;
  top:0;
  height:0.4em;
  width:100%;
  padding-right:0.1em;
  color:red;
  overflow:hidden;      
}    

JS:

$(".distinct-accent").html(function(i, oldhtml){
   var newhtml = "";
   for(var i = 0; i < oldhtml.length; i++){
     var nextChar = "";
     var code = oldhtml.charCodeAt(i);
     if((code > 64 && code < 90) ||
        (code > 96 && code < 123) || code == 32) nextChar = oldhtml[i];
     else {
        nextChar = "<span class='with-accent' data-content='" + oldhtml[i] + "'>" + oldhtml[i] + "</span>";
     }
     newhtml += nextChar;
   }
   return newhtml;
});

Demo.

Update: NOTE the above code did work well before in all webkit-based browsers (such as Chrome) but now it does not work for unknown reason (the content:attr does not apply correctly with dynamically updated content via setting innerHtml). It must be some change (which can be considered as bug) to Chrome causing that non-working. Especially you will see that the HTML output will render correctly after opening and closing the inspector pane).

To fix that issue I just added a simple hack (by removing the element and re-inserting back to force applying the CSS rule correctly). Almost the code above is kept unchanged.

Just append this script:

.each(function(){
   $(this).replaceWith($(this).clone(true));
});

Updated Demo


Solution 3:

Expanding the other solutions here, you can actually achieve a solution that doesn’t rely on diacritics to be placed only on the top part of the letter.

You can do this by simply overlapping the two versions (with and without diacritics) and using text-shadow to cover the anti-alias bleed that obviously occurs in these situations.

Example of antialias color bleeding on the edges of text. Pay attention to the soft red halo / glow around black characters.

Enlarged crop of the example below with antialiasing bleeding exposed

You can also just set the text with diacritics to a different opacity if you want them “greyed out”, therefore limiting the bleeding effect.

Some caveats apply:

  1. If you want to color the dot of i you need the U+0131 LATIN SMALL LETTER DOTLESS I character (see «Spinal Tap» example)

  2. All the solutions currently on this question rely on the fact that characters don’t change their metrics when diacritics are added or removed. This is not always true, for example with i and ï (see the last example).

  3. Sometimes diacritics are attached to the main shape of the letter, such as ç. This breaks our text-shadow trick very badly.

  4. Using text-shadow is not a perfect solution. It requires the background to be at the same time a solid color and known at design time.

In the following snippet I also use CSS custom properties (aka CSS Variables) in order to not having to repeat the background color inside text-shadow, and on hover you can see what happens when the text-shadow is removed.

:root {
  --body-bg: white;
}

body {
  display: flex;
  min-height: 100vh;
  justify-content: center;
  align-items: center;
  font-family: sans-serif;
  font-size: 30px;
  flex-direction: column;
  background: var(--body-bg);
}

.setting {
  font-size: 14px;
  display: flex;
  align-items: baseline;
}

body>* {
  padding: 10px;
}

[data-with-diacritics] {
  display: inline-block;
  position: relative;
  text-shadow: -1px -1px 0px var(--body-bg), 1px -1px 0px var(--body-bg), -1px 1px 0px var(--body-bg), 1px 1px 0px var(--body-bg);
}

[data-with-diacritics]::before {
  content: attr(data-with-diacritics);
  position: absolute;
  color: red;
}

[data-with-diacritics]>span {
  position: relative;
}

[data-with-diacritics]:hover {
  text-shadow: none;
  outline: 1px solid red;
}
<span data-with-diacritics="Spın̈al Tap">
  <span>Spınal Tap</span>
</span>

<span data-with-diacritics="España">
  <span>Espana</span>
</span>

<span data-with-diacritics="Français">
  <span>Francais</span>
</span>

<span data-with-diacritics="äëïiöü ãõ">
  <span>aeııou ao</span>
</span>

Post a Comment for "How To Display Accents Over Words With Different Colors In HTML/CSS?"