I'm doing a hobby project for fun recently, it's a GitHub webpage using Jekyll.
One of the main component of my site is displaying Chinese characters with their Sino-Vietnamese pronunciation. I use <ruby>
elements to render these texts, for those who don't know, you can read its MDN docs
The problem with that is word spacing is broken when a <rt>
element is longer than its associated <rb>
element. So I created a jQuery function to dynamically adjust spacing.
A minimal example here:
const stdSpace = "1em"; // for ruby annotation spacing
$(function () {
$("rb").each(rubyAdjust);
});
function rubyAdjust(i, el) { // for each ruby base
const rbW = $(el).width(), // take its width
rtW = $(el).next("rt").width(), // its associated ruby text width
diff = (rtW - rbW).toFixed(0), // excess amount
addSpace = diff > 0
? `calc(${stdSpace} + ${diff.toString()}px)`
: stdSpace;
$(el).css("margin-right", addSpace);
}
rb {
display: inline-block /* fluid word spacing with margin using JS */
}
rt {
text-align: left /* to work together with rb margin */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ruby>
<rb>是</rb><rt>Thị</rt>
<rb>故</rb><rt>cố</rt>
<rb>空</rb><rt>không</rt>
<rb>中</rb><rt>trung</rt>
</ruby>
My function rubyAdjust
works as expected, but becomes a UI blocking point when I have a very long text. For a full fledged example, you can visit a page of my project which shows the Diamond Sutra.
So what I want is to improve the rendering speed:
- Is there a better way to adjust word spacing of
<ruby>
? The official docs of<ruby>
doesn't have much, maybe because the feature is still uncomplete and fews people are using it? - I've also searched for a multi thread execution of jQuery, but it seems like DOM manipulation isn't possible. Do you guys have any idea?
Many thanks,
1 Answer 1
Some improvements:
- completely remove the JS function and replace with CSS (thanks to this SO answer); this greatly reduces loading time
- wrap one
ruby
for each pairrb
&rt
withruby
, instead of having multiple pairs of them insideruby
- use
flex
to render rather than the defaultdisplay: block
The improved code:
ruby {
display: inline-flex;
flex-direction: column-reverse;
margin-right: 0.5em; /* additional spacing */
}
rb, rt {
display: inline;
line-height: 1; /* spacing between rb & rt can be changed */
text-align: left; /* my personal preference */
}
<ruby><rb>是</rb><rt>Thị</rt></ruby>
<ruby><rb>故</rb><rt>cố</rt></ruby>
<ruby><rb>空</rb><rt>không</rt></ruby>
<ruby><rb>中</rb><rt>trung</rt></ruby>