1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
---
title: The GraphicalEmoji hack
date: 2023-03-08
tags:
- cursed
- JavaScript
- JSX
- fontRendering
- dearGodHelpMe
---
Today, I tried to write a JSX component that included an emoji in it.
Specifically this emoji: <span style="font-family: Papyrus">⚠️</span>.
This emoji is special because there's actually two forms of it:
- ⚠︎ (the textual form)
- <span style="font-family: Papyrus">⚠️</span> (the graphical form)
EDIT: Apparently this difference isn't showing up on every browser
engine the same way. Please trust me that there is a difference, one
of them on my MacBook running Microsoft Edge is a text-only emoji that
has no color in it. This is why I was so confused, scared, and on the
verge of tears after being gaslit by my browser. God is dead because
font rendering killed him.
When I was making this component, I wanted the graphical form of it.
The following things did not work:
- Adding the explicit "make this graphical" Unicode instruction:
`\u{FE0F}`
- Declaring the emoji as the string `"\u{26A0}\u{FE0F}"` and then
using it as a variable: `<span>{warningEmoji}</span>`
- Using the variable in a format string:
```
`<span>{${warningEmoji}}</span>`
```
Turns out, this is actually a fairly widespread problem with fonts
that have the _textual_ form of emoji defined but not the _graphical_
form of it defined. The font my blog uses is one of them, so to get
the graphical <span style="font-family: Papyrus">⚠️</span> I've
been using above, I had to paste this HTML snippet:
```html
<span style="font-family: Papyrus">⚠️</span>
```
<XeblogConv name="Aoi" mood="facepalm">
Oh god. Really? That is so, so cursed.
</XeblogConv>
Yes, really. In order to make the emoji render correctly, I had to
instruct the browser to render it in
<span style="font-family: Papyrus">Papyrus</span>
because that _does not_ have the emoji defined. It will then fall back to the system
font, giving us the
<span style="font-family: Papyrus">⚠️</span>
that we truly desire.
Here is the JSX component I had to write:
```jsx
export interface GraphicalEmojiProps {
emoji: string;
}
/** Listen to me for my tale of woe:
* Fonts are complicated. Fun fact: fonts are actually Turing-complete programs
* that run in browsers. Yes, font rendering is really that complicated. This
* component is a dirty, ugly, disgusting HACK that works around font
* rendering in order to forcibly display the graphical form of an emoji.
*
* This works because Papyrus always displays the graphical forms of
* emoji. No, I don't know why either. It slightly scares me.
*
* Either way, this works and I'm not brave enough to question why.
*/
export default function GraphicalEmoji({ emoji }: GraphicalEmojiProps) {
return <span style={{ fontFamily: "Papyrus" }}>{emoji}</span>;
}
```
This code is free as in mattress. If you decide to use it, it's your
problem.
<XeblogConv name="Cadey" mood="coffee">
I hate fonts.
</XeblogConv>
|