JSFiddle - React, Tailwind, and code Playground

HTML

<span class='distinct-accent'>pīng​pāng​qiú​pāi ô ê ố ổ ỡ é ở ã ả à á</span>

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;      
}

JavaScript

$(".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;
})//due to a new bug in Chrome, we need to remove nodes and re-insert back (replace) for the CSS content:attr(data-content) working correctly.
//As before the code here works perfectly without this suffixed script, it can also work well in such as Edge without this additional script.
.each(function(){
	$(this).replaceWith($(this).clone(true));
});