I'm trying to describe a chord, B♭, but it is showing up weird in an <option>
HTML tag. Instead of "B♭", it shows up with an apparent space between the "B" and the "♭".
I tried applying a CSS style, letter-spacing
, to this chord in a <span>
tag, but apparently, this doesn't control kerning.
Interestingly, when I select the chord from the dropdown, my OS renders the kerning correctly, but after it is selected, the flat symbol shows up by itself, set aside by a space, like the following.
The JS literal that I'm trying to render is,
'B\u266D'
Using the literal 'B♭'
just renders as 'B♭'
in the dropdown.
FWIW, I'm doing this from within Vue3, and looking at the output in Chrome, on a Mac.
CodePudding user response:
This seems to be a rendering issue in Chrome 96 on macOS (and possibly other Chromium-based browsers and other operating systems). Firefox 91 on macOS renders it correctly. The problem also only affects the flat (\u266d
) and natural (\u266e
) signs. The sharp, double sharp, and double flat signs are unaffected in my tests.
You could workaround the issue by adjusting the <select>
's letter-spacing
with a negative value (to bring the characters closer together, thus reducing the gap), and compensating for the reduced width with padding
on the right. You'd only want to do this conditionally for the affected signs, so use a computed prop that returns the necessary letter-spacing
and padding
:
Use a
v-model
on the<select>
to capture the selected note.Use a computed prop that returns the styles needed to adjust
letter-spacing
andpadding
. When the selected note contains the problematic signs, return the adjusted spacing/padding.Bind the computed style to the
<select>
's styles.
<script setup>
const notes = [
'B\u266d', // flat
'B\u266e', // natural
'B\u266f', // sharp
'B\u{1D12B}', // double flat
'B\u{1D12A}', // double sharp
]
1️⃣
let selectedNote = $ref(notes[0])
2️⃣
let styles = $computed(() => {
if (selectedNote.includes('\u266d') || selectedNote.includes('\u266e')) {
return {
'letter-spacing': '-20px',
'padding-right': '40px',
}
}
})
</script>
<template>
<select 1️⃣ v-model="selectedNote" :style="styles" 3️⃣>
<option v-for="note in notes">{{ note }}</option>
</select>
</template>
Note: The <script setup>
above uses the new/experimental Reactivity Transform, which supports globally defined reactivity APIs ($ref
, $computed
, etc.) and removes the need to unwrap ref
s.
Result on Chrome 96 on macOS: