{"id":112,"date":"2026-04-10T04:37:26","date_gmt":"2026-04-10T04:37:26","guid":{"rendered":"https:\/\/www.charactercodes.net\/blog\/?p=112"},"modified":"2026-04-10T04:37:26","modified_gmt":"2026-04-10T04:37:26","slug":"why-some-characters-dont-display-in-your-browser-or-font","status":"publish","type":"post","link":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/","title":{"rendered":"Why Some Characters Don&#8217;t Display in Your Browser or Font"},"content":{"rendered":"<style>\n:root { --bg: #ffffff; --surface: #f5f7fa; --surface2: #eceef3; --border: #dde1ea; --accent: #3b5bdb; --accent2: #7048e8; --text: #1a1d2e; --text-muted: #4a5068; --text-dim: #8891aa; --green: #2f9e44; --yellow: #e67700; --red: #c92a2a; --orange: #d9480f; --code-bg: #f0f2f7; --radius: 10px; }\n.container { margin: 0 auto; }\n.toc { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px 28px; margin-bottom: 48px; }\n.toc h3 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-dim); margin-bottom: 14px; }\n.toc ol { padding-left: 20px; color: var(--text-muted); font-size: 0.9rem; }\n.toc ol li { margin-bottom: 6px; }\n.toc a { color: var(--accent); text-decoration: none; }\n.toc a:hover { text-decoration: underline; }\n.section-label { font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.15em; color: var(--text-dim); margin-bottom: 10px; }\n.container h2 { font-size: 1.6rem; font-weight: 700; letter-spacing: -0.02em; color: var(--text); margin-bottom: 20px; margin-top: 8px; }\n.container h3 { font-size: 1.15rem; font-weight: 600; color: var(--text); margin: 28px 0 12px; }\n.container p { margin-bottom: 20px; color: var(--text); }\n.container a { color: var(--accent); }\nsection.post-section { margin-bottom: 64px; padding-top: 8px; border-top: 1px solid var(--border); }\nsection.post-section:first-of-type { border-top: none; }\n.callout { border-radius: var(--radius); padding: 18px 22px; margin: 24px 0; border-left: 3px solid; font-size: 0.93rem; }\n.callout .callout-title { font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 6px; }\n.callout p { margin: 0; }\n.callout.warning { background: rgba(251,191,36,0.07); border-color: var(--yellow); }\n.callout.warning .callout-title { color: var(--yellow); }\n.callout.info { background: rgba(108,142,255,0.07); border-color: var(--accent); }\n.callout.info .callout-title { color: var(--accent); }\n.callout.tip { background: rgba(74,222,128,0.07); border-color: var(--green); }\n.callout.tip .callout-title { color: var(--green); }\n.callout.danger { background: rgba(248,113,113,0.07); border-color: var(--red); }\n.callout.danger .callout-title { color: var(--red); }\n.container pre, .container code { font-family: 'JetBrains Mono', monospace; font-size: 0.82rem; }\n.container pre { background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px 24px; overflow-x: auto; margin: 20px 0; line-height: 1.7; color: var(--text); }\n.container pre .comment { color: var(--text-dim); }\n.container pre .label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-dim); display: block; margin-bottom: 10px; border-bottom: 1px solid var(--border); padding-bottom: 6px; }\n.container code { background: var(--code-bg); border: 1px solid var(--border); border-radius: 4px; padding: 1px 6px; font-size: 0.82rem; color: #2b4acb; }\n.container pre code { background: none; border: none; padding: 0; }\n.container .table-wrap { overflow-x: auto; margin: 20px 0; }\n.container table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }\n.container thead th { background: var(--surface2); color: var(--text-muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em; font-weight: 600; padding: 12px 16px; text-align: left; border-bottom: 1px solid var(--border); }\n.container tbody td { padding: 11px 16px; border-bottom: 1px solid var(--border); color: var(--text); vertical-align: top; }\n.container tbody tr:last-child td { border-bottom: none; }\n.container tbody tr:hover td { background: var(--surface); }\n.container .badge { display: inline-block; border-radius: 4px; padding: 1px 8px; font-size: 0.72rem; font-weight: 600; }\n.container .badge.green { background: rgba(74,222,128,0.12); color: var(--green); }\n.container .badge.red { background: rgba(248,113,113,0.12); color: var(--red); }\n.container .badge.yellow { background: rgba(251,191,36,0.12); color: var(--yellow); }\n.container .badge.blue { background: rgba(108,142,255,0.12); color: var(--accent); }\n.container dl.char-def { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px 24px; margin: 20px 0; display: grid; grid-template-columns: max-content 1fr; gap: 8px 24px; font-size: 0.9rem; }\n.container dl.char-def dt { color: var(--text-dim); font-weight: 600; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.08em; padding-top: 2px; }\n.container dl.char-def dd { color: var(--text); }\n.container blockquote.pull { border-left: 3px solid var(--accent); padding: 4px 0 4px 20px; margin: 28px 0; font-size: 1.05rem; color: var(--text-muted); font-style: italic; line-height: 1.6; }\n.container .char-display { display: inline-block; font-size: 2.5rem; line-height: 1; margin-bottom: 8px; }\n.container .fix-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 14px; margin: 20px 0; }\n.container .fix-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px 20px; }\n.container .fix-card .fix-num { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--accent); margin-bottom: 8px; }\n.container .fix-card h4 { font-size: 0.95rem; font-weight: 600; color: var(--text); margin-bottom: 6px; }\n.container .fix-card p { font-size: 0.85rem; color: var(--text-muted); margin: 0; }\n.container .tldr-box { background: var(--surface); border: 1px solid var(--accent); border-radius: var(--radius); padding: 24px 28px; margin: 32px 0; }\n.container .tldr-box .tldr-label { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--accent); margin-bottom: 12px; }\n.container .tldr-box p { margin: 0; font-size: 0.95rem; color: var(--text); }\n@media (max-width: 600px) { dl.char-def { grid-template-columns: 1fr; gap: 2px 0; } dl.char-def dt { margin-top: 10px; } }\n<\/style>\n<p><main class=\"container\"><\/p>\n<p>  <!-- TOC --><\/p>\n<div class=\"toc\">\n<h3>In this article<\/h3>\n<ol>\n<li><a href=\"#missing-glyphs\">What is a missing glyph?<\/a><\/li>\n<li><a href=\"#tofu\">The tofu problem (\u25a1)<\/a><\/li>\n<li><a href=\"#fallback-fonts\">Fallback fonts &#038; the font stack<\/a><\/li>\n<li><a href=\"#combining-characters\">Combining characters<\/a><\/li>\n<li><a href=\"#emoji-rendering\">Emoji rendering issues<\/a><\/li>\n<li><a href=\"#os-version\">OS &#038; version fragmentation<\/a><\/li>\n<li><a href=\"#fixes\">How to fix it &#8211; for users &#038; developers<\/a><\/li>\n<li><a href=\"#tldr\">TL;DR cheat sheet<\/a><\/li>\n<\/ol><\/div>\n<p>  <!-- \u2500\u2500 Section 01 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"missing-glyphs\">\n<div class=\"section-label\">Section 01<\/div>\n<h2>What Is a Missing Glyph?<\/h2>\n<p>Unicode defines over 150,000 characters. No single font on earth contains all of them. The moment your browser or app needs to draw a character that the current font doesn&#8217;t know about, you have a <strong>missing glyph<\/strong>.<\/p>\n<p>It&#8217;s worth separating two concepts that people often confuse:<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Concept<\/th>\n<th>What it is<\/th>\n<th>Example<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Code point<\/strong><\/td>\n<td>The abstract Unicode number assigned to a character<\/td>\n<td><code>U+1F9F8<\/code> (Teddy Bear)<\/td>\n<\/tr>\n<tr>\n<td><strong>Glyph<\/strong><\/td>\n<td>The actual drawn shape that represents the character in a font file<\/td>\n<td>The teddy bear image inside an emoji font<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<p>A font is essentially a dictionary: it maps code points to glyph drawings. If a code point isn&#8217;t in the dictionary, the font has nothing to show you. What happens next depends on the rendering pipeline &#8211; and that&#8217;s where things get interesting.<\/p>\n<div class=\"callout info\">\n<div class=\"callout-title\">\ud83d\udca1 Unicode \u2260 Font<\/div>\n<p>The Unicode Consortium decides <em>which characters exist<\/em>. Font designers decide <em>which characters their font draws<\/em>. These are completely independent decisions. A brand new Unicode character may go years without widespread font support.<\/p>\n<\/p><\/div>\n<\/section>\n<p>  <!-- \u2500\u2500 Section 02 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"tofu\">\n<div class=\"section-label\">Section 02<\/div>\n<h2>The Tofu Problem (\u25a1)<\/h2>\n<p>When a font encounters a code point it can&#8217;t draw, it usually renders a fallback shape in its place. The most common fallback is a plain empty rectangle: <strong>\u25a1<\/strong>. In typography circles, this is affectionately called <strong>tofu<\/strong> &#8211; because it&#8217;s bland, white, and square.<\/p>\n<div class=\"callout warning\">\n<div class=\"callout-title\">\u26a0\ufe0f Why &#8220;tofu&#8221;?<\/div>\n<p>Google engineers coined the term while building the Noto font family. Their goal was to eliminate tofu entirely &#8211; hence the name <strong>No Tofu \u2192 Noto<\/strong>. The Noto project now covers virtually every Unicode script and is the most comprehensive free font collection in existence.<\/p>\n<\/p><\/div>\n<p>Different fonts and renderers signal a missing glyph in different ways:<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Symbol<\/th>\n<th>Name<\/th>\n<th>Meaning<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"font-size:1.3rem\">\u25a1<\/td>\n<td>Tofu \/ empty box<\/td>\n<td>Font has no glyph for this code point<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size:1.3rem\">\u25af<\/td>\n<td>Tall rectangle<\/td>\n<td>Alternate tofu variant<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size:1.3rem; font-family:monospace\">?<\/td>\n<td>Question mark<\/td>\n<td>Some older renderers substitute a literal <code>?<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"font-size:1.3rem; font-family:monospace\">U+XXXX<\/td>\n<td>Code point literal<\/td>\n<td>Developer tools &#038; terminals often print the raw code point<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size:1.3rem\">&#xFFFD;<\/td>\n<td>Replacement character<\/td>\n<td><code>U+FFFD<\/code> &#8211; officially means &#8220;I couldn&#8217;t decode this at all&#8221;<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<p>The <strong>Replacement Character<\/strong> (<code>U+FFFD<\/code> &#8211; &#xFFFD;) is a special case. It&#8217;s not a missing glyph in the font-rendering sense; it&#8217;s the character Unicode itself tells you to display when incoming bytes couldn&#8217;t be decoded &#8211; for example, a UTF-8 file with invalid byte sequences. Tofu means &#8220;the font doesn&#8217;t have it.&#8221; &#xFFFD; means &#8220;I couldn&#8217;t even figure out what character this was supposed to be.&#8221;<\/p>\n<dl class=\"char-def\">\n<dt>Character<\/dt>\n<dd>REPLACEMENT CHARACTER<\/dd>\n<dt>Code Point<\/dt>\n<dd>U+FFFD<\/dd>\n<dt>Appears when<\/dt>\n<dd>Byte sequences are invalid or undecodable for the declared encoding<\/dd>\n<dt>Common cause<\/dt>\n<dd>Opening a Latin-1 file as UTF-8, or corrupted data<\/dd>\n<\/dl>\n<\/section>\n<p>  <!-- \u2500\u2500 Section 03 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"fallback-fonts\">\n<div class=\"section-label\">Section 03<\/div>\n<h2>Fallback Fonts &amp; the Font Stack<\/h2>\n<p>Modern browsers don&#8217;t give up after one font fails. They work through a <strong>font stack<\/strong> &#8211; an ordered list of fonts to try. The moment a glyph is missing from Font A, the browser silently moves to Font B, then Font C, and so on until it either finds the glyph or runs out of options and shows tofu.<\/p>\n<p>In CSS, you declare this stack explicitly:<\/p>\n<pre><span class=\"label\">css - typical body font stack<\/span>body {\r\n  font-family:\r\n    \"Helvetica Neue\",   \/* preferred - high-quality sans *\/\r\n    Arial,              \/* safe fallback on Windows *\/\r\n    \"Liberation Sans\",  \/* open-source equivalent *\/\r\n    sans-serif;         \/* generic family - OS picks a default *\/\r\n}\r\n<\/pre>\n<p>The final keyword &#8211; <code>sans-serif<\/code>, <code>serif<\/code>, <code>monospace<\/code>, <code>emoji<\/code>, etc. &#8211; is a <strong>generic family<\/strong>. It tells the OS &#8220;if nothing else works, pick whatever you think is best for this category.&#8221; The OS maps generic families to real installed fonts, which vary by platform.<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Generic family<\/th>\n<th>Windows default<\/th>\n<th>macOS default<\/th>\n<th>Android default<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>sans-serif<\/code><\/td>\n<td>Arial<\/td>\n<td>Helvetica Neue<\/td>\n<td>Roboto<\/td>\n<\/tr>\n<tr>\n<td><code>serif<\/code><\/td>\n<td>Times New Roman<\/td>\n<td>Times New Roman<\/td>\n<td>Noto Serif<\/td>\n<\/tr>\n<tr>\n<td><code>monospace<\/code><\/td>\n<td>Courier New<\/td>\n<td>Courier New<\/td>\n<td>Droid Sans Mono<\/td>\n<\/tr>\n<tr>\n<td><code>emoji<\/code><\/td>\n<td>Segoe UI Emoji<\/td>\n<td>Apple Color Emoji<\/td>\n<td>Noto Color Emoji<\/td>\n<\/tr>\n<tr>\n<td><code>system-ui<\/code><\/td>\n<td>Segoe UI<\/td>\n<td>-apple-system<\/td>\n<td>Roboto<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<h3>How the Browser Picks a Font for a Single Character<\/h3>\n<p>The font selection process for each character is more granular than most people realise. The browser doesn&#8217;t pick one font and apply it to the whole string &#8211; it picks a font <em>per character<\/em>:<\/p>\n<pre><span class=\"label\">what the browser does for \"Hello \ud83c\udf0d \u0645\u0631\u062d\u0628\u0627\"<\/span>\"H\"  \u2192 try font 1 \u2192 found \u2713 \u2192 use font 1\r\n\"e\"  \u2192 try font 1 \u2192 found \u2713 \u2192 use font 1\r\n\"l\"  \u2192 try font 1 \u2192 found \u2713 \u2192 use font 1\r\n...\r\n\"\ud83c\udf0d\" \u2192 try font 1 \u2192 NOT found\r\n     \u2192 try font 2 \u2192 NOT found\r\n     \u2192 try system emoji font \u2192 found \u2713 \u2192 use emoji font\r\n\"\u0645\"  \u2192 try font 1 \u2192 NOT found\r\n     \u2192 try font 2 \u2192 NOT found\r\n     \u2192 try system Arabic font \u2192 found \u2713 \u2192 use Arabic font\r\n<\/pre>\n<p>This is why a single sentence can render in three or four different fonts simultaneously, and why mixing scripts in a design requires careful font selection.<\/p>\n<div class=\"callout info\">\n<div class=\"callout-title\">\ud83d\udca1 Font synthesis<\/div>\n<p>If a font has a regular weight but not bold, some browsers will <em>synthesize<\/em> bold by algorithmically thickening the strokes. The result is usually inferior to a properly designed bold font. You can disable this with <code>font-synthesis: none<\/code> in CSS if quality matters.<\/p>\n<\/p><\/div>\n<h3>The Unicode Font Fallback Algorithm<\/h3>\n<p>Browsers implement the CSS Fonts specification&#8217;s font matching algorithm. At a high level it works like this:<\/p>\n<ol style=\"margin-left:20px; margin-bottom:20px; color:var(--text); line-height:2;\">\n<li>Try each font in the <code><a href=\"https:\/\/www.cssportal.com\/css-properties\/font-family.php\">font-family<\/a><\/code> list in order.<\/li>\n<li>For each font, check if a glyph exists for the target code point.<\/li>\n<li>If the glyph is found, use that font for this character.<\/li>\n<li>If no listed font has the glyph, fall through to the browser&#8217;s built-in system fallback list.<\/li>\n<li>If nothing works: render the .notdef glyph (usually tofu or the font&#8217;s own missing-glyph placeholder).<\/li>\n<\/ol>\n<blockquote class=\"pull\"><p>&#8220;The font stack is less like a queue and more like a safety net &#8211; every character falls through until something catches it.&#8221;<\/p><\/blockquote>\n<\/section>\n<p>  <!-- \u2500\u2500 Section 04 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"combining-characters\">\n<div class=\"section-label\">Section 04<\/div>\n<h2>Combining Characters<\/h2>\n<p>Some Unicode characters aren&#8217;t standalone shapes &#8211; they&#8217;re <strong>modifiers<\/strong> that attach to the character before them. These are called <strong>combining characters<\/strong>, and they&#8217;re a surprisingly common source of display problems.<\/p>\n<p>The classic example is accented letters. The letter <strong>\u00e9<\/strong> can be encoded two completely different ways:<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Form<\/th>\n<th>Code points<\/th>\n<th>Description<\/th>\n<th>Bytes (UTF-8)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>NFC<\/strong> (composed)<\/td>\n<td><code>U+00E9<\/code><\/td>\n<td>Single precomposed character &#8220;\u00e9&#8221;<\/td>\n<td>2 bytes<\/td>\n<\/tr>\n<tr>\n<td><strong>NFD<\/strong> (decomposed)<\/td>\n<td><code>U+0065<\/code> + <code>U+0301<\/code><\/td>\n<td>Letter &#8220;e&#8221; + combining acute accent<\/td>\n<td>3 bytes<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<p>To a human eye &#8211; and usually to a browser &#8211; these look identical. But to a font renderer, they are fundamentally different challenges. The composed form (<code>U+00E9<\/code>) is a single glyph that the font either has or doesn&#8217;t. The decomposed form requires the renderer to draw <code>e<\/code>, then <em>overlay<\/em> a separate combining accent glyph on top, positioning it correctly relative to the base letter.<\/p>\n<div class=\"callout warning\">\n<div class=\"callout-title\">\u26a0\ufe0f The combining diacritic problem<\/div>\n<p>Not every font includes combining diacritic glyphs, and those that do may not position them correctly for all base characters. You can end up with an accent floating to the right of a letter, stacked too high, or clipping into text above. This is especially common with Arabic, Devanagari, and Southeast Asian scripts that rely heavily on combining marks for correct rendering.<\/p>\n<\/p><\/div>\n<h3>Stacked Combining Characters<\/h3>\n<p>You can stack multiple combining characters on a single base. This is occasionally used legitimately (Vietnamese: <strong>\u1ed9<\/strong> = o + combining circumflex + combining dot below), but it&#8217;s also famously abused to create &#8220;Zalgo&#8221; text &#8211; characters with so many stacked combining marks they overflow their line box and collide with surrounding text:<\/p>\n<pre><span class=\"label\">Zalgo text - legitimate Unicode, chaotic rendering<\/span>H\u0337\u0321\u0326\u030b\u030d\u0358\u0119\u0336\u0347\u0339\u0312l\u0334\u0353\u034a\u0313l\u0334\u035a\u033b\u0314\u030a\u0313o\u0338\u0321\u030a \u2190 same \"Hello\", but with dozens of combining marks\r\n                  stacked on each base letter<\/pre>\n<div class=\"callout tip\">\n<div class=\"callout-title\">\u2705 Normalisation to the rescue<\/div>\n<p>Unicode defines four normalisation forms: NFC, NFD, NFKC, and NFKD. For most text processing, <strong>NFC<\/strong> (Canonical Decomposition, followed by Canonical Composition) is the right choice. Normalising to NFC collapses decomposed sequences into precomposed characters wherever possible, reducing rendering inconsistencies and making string comparison reliable. In JavaScript: <code>str.normalize('NFC')<\/code>.<\/p>\n<\/p><\/div>\n<h3>Zero Width Characters<\/h3>\n<p>A particularly invisible category of combining characters are zero-width characters &#8211; they take up no horizontal space and often don&#8217;t render anything visible at all, yet they actively affect how surrounding text behaves:<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Character<\/th>\n<th>Code Point<\/th>\n<th>Effect<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>ZWJ<\/td>\n<td><code>U+200D<\/code><\/td>\n<td>Joins adjacent emoji into a single combined emoji (e.g. \ud83d\udc69\u200d\ud83d\udcbb)<\/td>\n<\/tr>\n<tr>\n<td>ZWNJ<\/td>\n<td><code>U+200C<\/code><\/td>\n<td>Prevents joining &#8211; forces adjacent letters to stay separate in Arabic\/Persian<\/td>\n<\/tr>\n<tr>\n<td>ZWSP<\/td>\n<td><code>U+200B<\/code><\/td>\n<td>Zero-width space &#8211; allows line-breaking without a visible space<\/td>\n<\/tr>\n<tr>\n<td>SHY<\/td>\n<td><code>U+00AD<\/code><\/td>\n<td>Soft hyphen &#8211; invisible unless the browser decides to break the line there<\/td>\n<\/tr>\n<tr>\n<td>WJ<\/td>\n<td><code>U+2060<\/code><\/td>\n<td>Word joiner &#8211; prevents a line break between two characters<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<p>Zero-width characters are invisible but real. They can be inserted into text to watermark it, bypass keyword filters, or confuse text comparisons. If you ever copy-paste text from a web page and find string matching mysteriously failing, invisible characters are a common culprit.<\/p>\n<\/section>\n<p>  <!-- \u2500\u2500 Section 05 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"emoji-rendering\">\n<div class=\"section-label\">Section 05<\/div>\n<h2>Emoji Rendering Issues<\/h2>\n<p>Emoji are where Unicode&#8217;s abstract ideals collide hardest with messy reality. Unlike regular characters, emoji have no standardised <em>appearance<\/em> &#8211; only a standardised <em>code point<\/em>. The laughing-crying face \ud83d\ude02 is <code>U+1F602<\/code> on every platform, but what it looks like is entirely up to whoever made the emoji font.<\/p>\n<div class=\"callout warning\">\n<div class=\"callout-title\">\u26a0\ufe0f Emoji are not standardised images<\/div>\n<p>Apple, Google, Samsung, Microsoft, and Twitter\/X all draw their own emoji from scratch. The same code point can look dramatically different &#8211; sometimes even conveying a different emotion &#8211; depending on the platform.<\/p>\n<\/p><\/div>\n<h3>Skin Tone Modifiers<\/h3>\n<p>Unicode defines five <a href=\"\/emojis\/emoji-modifiers\/\">skin tone modifiers<\/a> (U+1F3FB through U+1F3FF), based on the Fitzpatrick dermatology scale. When a modifier immediately follows a supporting emoji, the two code points are combined by the renderer into a single skin-toned variant. When the renderer <em>doesn&#8217;t<\/em> support the modifier, you see both characters independently: the base emoji plus a coloured square.<\/p>\n<pre><span class=\"label\">skin tone modifier encoding<\/span>\ud83d\udc4d      = U+1F44D                 (thumbs up, no modifier)\r\n\ud83d\udc4d\ud83c\udffd     = U+1F44D + U+1F3FD       (thumbs up + medium skin tone modifier)\r\n\r\nIf the font\/OS doesn't support the modifier:\r\n\u2192 renders as: \ud83d\udc4d \ud83d\udfeb  (two separate code points visible)<\/pre>\n<h3>ZWJ Sequences<\/h3>\n<p>Some <a href=\"\/emojis\/\">emojis<\/a> are actually sequences of multiple emoji joined by a Zero Width Joiner (<code>U+200D<\/code>). If the rendering platform recognises the full sequence, it displays a single combined image. If it doesn&#8217;t, each component shows separately.<\/p>\n<pre><span class=\"label\">ZWJ sequence example - family emoji<\/span>\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66  = U+1F468 + ZWJ + U+1F469 + ZWJ + U+1F467 + ZWJ + U+1F466\r\n       = man  +      + woman +      + girl  +      + boy\r\n\r\nRendered on a supporting platform: \ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66  (one family image)\r\nRendered on an older platform:      \ud83d\udc68 \ud83d\udc69 \ud83d\udc67 \ud83d\udc66  (four separate emoji)<\/pre>\n<p>The number of recognised ZWJ sequences has grown from a handful in 2015 to over 1,000 today. Older devices simply don&#8217;t know about sequences added after their OS shipped.<\/p>\n<h3>Text vs. Emoji Presentation<\/h3>\n<p>Many Unicode characters have both a text (monochrome) form and an emoji (colourful) form. Which one you get depends on whether a <strong>variation selector<\/strong> follows the character:<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Sequence<\/th>\n<th>Code points<\/th>\n<th>Renders as<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u260e<\/td>\n<td><code>U+260E<\/code> alone<\/td>\n<td>Black telephone (text style)<\/td>\n<\/tr>\n<tr>\n<td>\u260e\ufe0f<\/td>\n<td><code>U+260E<\/code> + <code>U+FE0F<\/code><\/td>\n<td>\ud83d\udfe0 Emoji style (coloured)<\/td>\n<\/tr>\n<tr>\n<td>\u260e\ufe0e<\/td>\n<td><code>U+260E<\/code> + <code>U+FE0E<\/code><\/td>\n<td>Text style (forced)<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<p><code>U+FE0F<\/code> is the <strong>emoji variation selector<\/strong>; <code>U+FE0E<\/code> is the text variation selector. Many emoji look different depending on whether this invisible character is attached. When variation selectors are missing or ignored, platforms make their own decisions &#8211; which is why the same character can appear as text on one device and emoji on another.<\/p>\n<h3>Flag Emoji<\/h3>\n<p>Country flag emoji are encoded as pairs of <strong>Regional Indicator letters<\/strong>. The letters A\u2013Z each have a Regional Indicator equivalent (U+1F1E6\u2013U+1F1FF). Pair them correctly &#8211; <code>\ud83c\uddec<\/code> + <code>\ud83c\udde7<\/code> &#8211; and a supporting platform renders a \ud83c\uddec\ud83c\udde7 flag. On a platform that doesn&#8217;t support flags (notably, Windows doesn&#8217;t natively render most flags), you see the two raw regional letters side by side: GB.<\/p>\n<div class=\"callout info\">\n<div class=\"callout-title\">\ud83d\udca1 Windows and flag emoji<\/div>\n<p>Microsoft has historically not shipped flag emoji in Segoe UI Emoji, citing that country flags are politically sensitive. As a result, Windows users often see two-letter codes instead of flag images, unless they&#8217;re using a browser (like Chrome) that substitutes its own emoji font.<\/p>\n<\/p><\/div>\n<\/section>\n<p>  <!-- \u2500\u2500 Section 06 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"os-version\">\n<div class=\"section-label\">Section 06<\/div>\n<h2>OS &amp; Version Fragmentation<\/h2>\n<p>New Unicode characters are approved regularly &#8211; Unicode 17.0 was released in 2025. But a character existing in the Unicode standard doesn&#8217;t mean every device can display it. The pipeline from &#8220;character approved&#8221; to &#8220;rendered on your screen&#8221; involves several slow-moving links:<\/p>\n<pre><span class=\"label\">the journey from Unicode approval to your screen<\/span>1. Unicode Consortium approves character (e.g. Unicode 17.0, 2025)\r\n        \u2193\r\n2. Font designers add the glyph (Apple, Google, Microsoft...)\r\n        \u2193\r\n3. Font ships in an OS update\r\n        \u2193\r\n4. User installs OS update\r\n        \u2193\r\n5. Character finally renders \u2713\r\n\r\nEach step can take months to years.<\/pre>\n<p>This means a perfectly valid Unicode character can display on a fully updated iPhone, turn to tofu on an Android that&#8217;s two OS versions behind, and show a question mark on an old Windows 10 install that skipped the relevant font update.<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Platform<\/th>\n<th>Emoji font<\/th>\n<th>Update mechanism<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>macOS \/ iOS<\/td>\n<td>Apple Color Emoji<\/td>\n<td>OS updates &#8211; tightly coupled to system<\/td>\n<\/tr>\n<tr>\n<td>Windows<\/td>\n<td>Segoe UI Emoji<\/td>\n<td>Windows updates &#8211; often delayed or skipped<\/td>\n<\/tr>\n<tr>\n<td>Android<\/td>\n<td>Noto Color Emoji<\/td>\n<td>OS updates <em>or<\/em> Google Play system updates<\/td>\n<\/tr>\n<tr>\n<td>Chrome \/ Edge<\/td>\n<td>Bundled Noto (some versions)<\/td>\n<td>Browser auto-updates &#8211; often faster than OS<\/td>\n<\/tr>\n<tr>\n<td>Linux<\/td>\n<td>Noto Color Emoji (if installed)<\/td>\n<td>Package manager &#8211; manual or distro-dependent<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<blockquote class=\"pull\"><p>&#8220;A new emoji is only as universal as the oldest device in your audience&#8217;s pocket.&#8221;<\/p><\/blockquote>\n<p>This fragmentation is why the this site exists &#8211; it documents what each emoji looks like across every platform and version, so you can check whether your chosen emoji will render consistently for your audience.<\/p>\n<\/section>\n<p>  <!-- \u2500\u2500 Section 07 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"fixes\">\n<div class=\"section-label\">Section 07<\/div>\n<h2>How to Fix It &#8211; For Users &amp; Developers<\/h2>\n<p>Whether you&#8217;re a user seeing boxes everywhere or a developer shipping text to millions of people, there are concrete steps you can take.<\/p>\n<h3>For Users<\/h3>\n<div class=\"fix-grid\">\n<div class=\"fix-card\">\n<div class=\"fix-num\">Fix 01<\/div>\n<h4>Update your OS<\/h4>\n<p>Emoji fonts and system character support ship with OS updates. The most common reason for tofu is a device that hasn&#8217;t been updated in a year or more.<\/p>\n<\/p><\/div>\n<div class=\"fix-card\">\n<div class=\"fix-num\">Fix 02<\/div>\n<h4>Install a comprehensive font<\/h4>\n<p>Install <strong>Noto fonts<\/strong> (free, by Google) or <strong>GNU Unifont<\/strong>. Noto covers virtually every Unicode block. Most Linux distros let you install <code>fonts-noto<\/code> via the package manager.<\/p>\n<\/p><\/div>\n<div class=\"fix-card\">\n<div class=\"fix-num\">Fix 03<\/div>\n<h4>Use a modern browser<\/h4>\n<p>Chrome, Firefox, and Edge all ship with better fallback font logic than older browsers. Chrome in particular bundles Noto emoji and handles complex ZWJ sequences well.<\/p>\n<\/p><\/div>\n<div class=\"fix-card\">\n<div class=\"fix-num\">Fix 04<\/div>\n<h4>Check your encoding<\/h4>\n<p>If you&#8217;re seeing &#xFFFD; or garbled text, the file was opened with the wrong encoding. In most text editors, you can re-open with <strong>UTF-8<\/strong> specified explicitly.<\/p>\n<\/p><\/div>\n<\/p><\/div>\n<h3>For Web Developers<\/h3>\n<p><strong>Always declare UTF-8<\/strong> in every HTML document. Without this, browsers have to guess, and they sometimes guess wrong:<\/p>\n<pre><span class=\"label\">html - declare encoding early in &lt;head&gt;<\/span>&lt;meta charset=\"UTF-8\"&gt;<\/pre>\n<p><strong>Use a thoughtful font stack<\/strong> that covers the scripts your audience uses. If you support a multilingual audience, consider loading subset fonts per language and letting the browser handle the rest via system fallbacks:<\/p>\n<pre><span class=\"label\">css - multilingual-aware font stack<\/span>body {\r\n  font-family:\r\n    \"Your Brand Font\",\r\n    \/* Latin fallback *\/\r\n    \"Helvetica Neue\", Arial,\r\n    \/* CJK fallback *\/\r\n    \"Noto Sans CJK SC\", \"PingFang SC\", \"Microsoft YaHei\",\r\n    \/* Arabic fallback *\/\r\n    \"Noto Sans Arabic\", \"Segoe UI\",\r\n    \/* Catch-all *\/\r\n    sans-serif;\r\n}\r\n<\/pre>\n<p><strong>Use <code>@font-face<\/code> with <code>unicode-range<\/code><\/strong> to load font subsets only when they&#8217;re needed. This avoids loading a massive pan-Unicode font for users who only need Latin characters:<\/p>\n<pre><span class=\"label\">css - unicode-range subsetting<\/span\">@font-face {\r\n  font-family: \"MyFont\";\r\n  src: url(\"myfont-latin.woff2\");\r\n  unicode-range: U+0000-00FF; \/* Basic Latin + Latin-1 *\/\r\n}\r\n\r\n@font-face {\r\n  font-family: \"MyFont\";\r\n  src: url(\"myfont-devanagari.woff2\");\r\n  unicode-range: U+0900-097F; \/* Devanagari *\/\r\n}<\/pre>\n<p><strong>Normalise strings server-side<\/strong>. If users input text that may come from different platforms (iOS vs Android vs desktop), normalise to NFC before storing or comparing:<\/p>\n<pre><span class=\"label\">javascript - normalise to NFC<\/span>const userInput = req.body.text;\r\nconst normalised = userInput.normalize('NFC');\r\n\r\n\/\/ Now safe to store, compare, and display<\/pre>\n<p><strong>Count grapheme clusters, not code points<\/strong> when you need to measure &#8220;user-visible length&#8221;. JavaScript&#8217;s <code>Intl.Segmenter<\/code> handles this correctly:<\/p>\n<pre><span class=\"label\">javascript - correct character counting<\/span\">const text = \"\ud83d\udc69\u200d\ud83d\udcbb caf\u00e9\";\r\n\r\n\/\/ Wrong approaches:\r\ntext.length              \/\/ \u2192 10  (counts UTF-16 code units)\r\n[...text].length         \/\/ \u2192 7   (counts code points, still wrong for ZWJ emoji)\r\n\r\n\/\/ Correct approach:\r\nconst segmenter = new Intl.Segmenter();\r\nconst segments = [...segmenter.segment(text)];\r\nsegments.length          \/\/ \u2192 7   (counts grapheme clusters as a human would)<\/pre>\n<div class=\"callout tip\">\n<div class=\"callout-title\">\u2705 Test with real content<\/div>\n<p>When building text-heavy UIs, test with content that includes emoji, CJK characters, Arabic (right-to-left), combining diacritics, and long unbreakable strings. Edge cases in font fallback and layout almost always hide until you throw real diverse content at a design.<\/p>\n<\/p><\/div>\n<h3>For Developers Targeting Older Devices<\/h3>\n<p>If your app needs to support users on older OS versions that don&#8217;t have recent emoji, consider one of these strategies:<\/p>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Strategy<\/th>\n<th>How it works<\/th>\n<th>Trade-off<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Emoji polyfill<\/strong><\/td>\n<td>Libraries like Twemoji replace text emoji with inline SVG\/PNG images from a CDN<\/td>\n<td><span class=\"badge green\">\u2713 Universal support<\/span> <span class=\"badge red\">\u2717 Layout shifts, CDN dependency<\/span><\/td>\n<\/tr>\n<tr>\n<td><strong>Stick to old emoji<\/strong><\/td>\n<td>Only use emoji from Unicode 6.0 (2010) &#8211; these exist on virtually every device still in use<\/td>\n<td><span class=\"badge green\">\u2713 Zero render risk<\/span> <span class=\"badge yellow\">\u26a0 Limited range<\/span><\/td>\n<\/tr>\n<tr>\n<td><strong>Emoji version check<\/strong><\/td>\n<td>Detect OS version server-side and serve different content<\/td>\n<td><span class=\"badge green\">\u2713 Precise<\/span> <span class=\"badge red\">\u2717 Complex to maintain<\/span><\/td>\n<\/tr>\n<tr>\n<td><strong>Custom icon font<\/strong><\/td>\n<td>Map your required symbols to Private Use Area code points in a custom font you control<\/td>\n<td><span class=\"badge green\">\u2713 Full control<\/span> <span class=\"badge red\">\u2717 Accessibility concerns, font file overhead<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<\/section>\n<p>  <!-- \u2500\u2500 Section 08 \u2500\u2500 --><\/p>\n<section class=\"post-section\" id=\"tldr\">\n<div class=\"section-label\">Section 08<\/div>\n<h2>TL;DR Cheat Sheet<\/h2>\n<div class=\"table-wrap\">\n<table>\n<thead>\n<tr>\n<th>Problem<\/th>\n<th>Cause<\/th>\n<th>Fix<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Tofu (\u25a1)<\/strong><\/td>\n<td>Font has no glyph for the code point<\/td>\n<td>Install Noto fonts; use a font stack with good fallbacks<\/td>\n<\/tr>\n<tr>\n<td><strong>&#xFFFD; everywhere<\/strong><\/td>\n<td>File decoded with wrong encoding<\/td>\n<td>Force UTF-8; add <code>&lt;meta charset=\"UTF-8\"&gt;<\/code><\/td>\n<\/tr>\n<tr>\n<td><strong>Floating accents<\/strong><\/td>\n<td>Decomposed combining characters; font doesn&#8217;t position them<\/td>\n<td>Normalise to NFC; use fonts with good diacritic support<\/td>\n<\/tr>\n<tr>\n<td><strong>Emoji showing as components<\/strong><\/td>\n<td>OS doesn&#8217;t recognise ZWJ sequence or skin tone modifier<\/td>\n<td>Update OS; use Twemoji polyfill for old device support<\/td>\n<\/tr>\n<tr>\n<td><strong>Flags as two letters<\/strong><\/td>\n<td>Platform doesn&#8217;t support Regional Indicator pairs (especially Windows)<\/td>\n<td>Use Twemoji; test cross-platform; consider text alternatives<\/td>\n<\/tr>\n<tr>\n<td><strong>New emoji not showing<\/strong><\/td>\n<td>Character approved by Unicode but OS font not updated<\/td>\n<td>Check here for support matrix; stick to established emoji<\/td>\n<\/tr>\n<tr>\n<td><strong><code>\"\ud83d\ude00\".length === 2<\/code><\/strong><\/td>\n<td>JavaScript strings are UTF-16; emoji are surrogate pairs<\/td>\n<td>Use <code>Intl.Segmenter<\/code> or spread operator <code>[...str]<\/code> for code points<\/td>\n<\/tr>\n<tr>\n<td><strong>Same char, different look<\/strong><\/td>\n<td>Missing or extra variation selector (<code>U+FE0E<\/code> \/ <code>U+FE0F<\/code>)<\/td>\n<td>Check for invisible variation selectors in source text<\/td>\n<\/tr>\n<tr>\n<td><strong>String compare fails<\/strong><\/td>\n<td>Mixed NFC \/ NFD normalisation or invisible zero-width chars<\/td>\n<td>Normalise inputs; strip zero-width characters if not needed<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<div class=\"tldr-box\">\n<div class=\"tldr-label\">\ud83c\udfaf The one-paragraph summary<\/div>\n<p>Characters go missing because fonts are finite and Unicode is vast. Browsers try to bridge the gap with font stacks &#8211; falling through fonts until they find a glyph. When nothing works, you get tofu (\u25a1). Combining characters and emoji add more complexity: a single visible symbol may be several code points that only newer platforms know how to merge. The fix is layered: declare UTF-8, build smart font stacks, normalise text input, use <code>Intl.Segmenter<\/code> to count correctly, and test with diverse real-world content.<\/p>\n<\/p><\/div>\n<\/section>\n<p><\/main><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article What is a missing glyph? The tofu problem (\u25a1) Fallback fonts &#038; the font stack Combining characters Emoji rendering issues OS &#038; version fragmentation How to fix it &#8211; for users &#038; developers TL;DR cheat sheet Section 01 What Is a Missing Glyph? Unicode defines over 150,000 characters. No single font on [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":113,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-112","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-characters","wpautop"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Why Some Characters Don&#039;t Display in Your Browser or Font - CharacterCodes Blog<\/title>\n<meta name=\"description\" content=\"Ever seen a \u25a1 where a character should be? Discover why glyphs go missing, how browsers choose fallback fonts, why emoji look different across devices, and how to fix it all.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Why Some Characters Don&#039;t Display in Your Browser or Font - CharacterCodes Blog\" \/>\n<meta property=\"og:description\" content=\"Ever seen a \u25a1 where a character should be? Discover why glyphs go missing, how browsers choose fallback fonts, why emoji look different across devices, and how to fix it all.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/\" \/>\n<meta property=\"og:site_name\" content=\"CharacterCodes Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-04-10T04:37:26+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png\" \/>\n\t<meta property=\"og:image:width\" content=\"840\" \/>\n\t<meta property=\"og:image:height\" content=\"480\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/www.charactercodes.net\/blog\/#\/schema\/person\/756aa07230428706f227ac4e178a7977\"},\"headline\":\"Why Some Characters Don&#8217;t Display in Your Browser or Font\",\"datePublished\":\"2026-04-10T04:37:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/\"},\"wordCount\":2644,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png\",\"articleSection\":[\"Characters\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/\",\"url\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/\",\"name\":\"Why Some Characters Don't Display in Your Browser or Font - CharacterCodes Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png\",\"datePublished\":\"2026-04-10T04:37:26+00:00\",\"author\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/#\/schema\/person\/756aa07230428706f227ac4e178a7977\"},\"description\":\"Ever seen a \u25a1 where a character should be? Discover why glyphs go missing, how browsers choose fallback fonts, why emoji look different across devices, and how to fix it all.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage\",\"url\":\"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png\",\"contentUrl\":\"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png\",\"width\":840,\"height\":480,\"caption\":\"character display issues\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.charactercodes.net\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Why Some Characters Don&#8217;t Display in Your Browser or Font\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.charactercodes.net\/blog\/#website\",\"url\":\"https:\/\/www.charactercodes.net\/blog\/\",\"name\":\"CharacterCodes Blog\",\"description\":\"Characters &amp; Emojis\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.charactercodes.net\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.charactercodes.net\/blog\/#\/schema\/person\/756aa07230428706f227ac4e178a7977\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/e188a164246c600f0cec7b14aec001469d0529676269f7d0fc364bfe2da4d7c2?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e188a164246c600f0cec7b14aec001469d0529676269f7d0fc364bfe2da4d7c2?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e188a164246c600f0cec7b14aec001469d0529676269f7d0fc364bfe2da4d7c2?s=96&d=mm&r=g\",\"caption\":\"admin\"},\"sameAs\":[\"https:\/\/charactercodes.net\/blog1\"],\"url\":\"https:\/\/www.charactercodes.net\/blog\/author\/rspronk\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Why Some Characters Don't Display in Your Browser or Font - CharacterCodes Blog","description":"Ever seen a \u25a1 where a character should be? Discover why glyphs go missing, how browsers choose fallback fonts, why emoji look different across devices, and how to fix it all.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/","og_locale":"en_US","og_type":"article","og_title":"Why Some Characters Don't Display in Your Browser or Font - CharacterCodes Blog","og_description":"Ever seen a \u25a1 where a character should be? Discover why glyphs go missing, how browsers choose fallback fonts, why emoji look different across devices, and how to fix it all.","og_url":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/","og_site_name":"CharacterCodes Blog","article_published_time":"2026-04-10T04:37:26+00:00","og_image":[{"width":840,"height":480,"url":"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png","type":"image\/png"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#article","isPartOf":{"@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/"},"author":{"name":"admin","@id":"https:\/\/www.charactercodes.net\/blog\/#\/schema\/person\/756aa07230428706f227ac4e178a7977"},"headline":"Why Some Characters Don&#8217;t Display in Your Browser or Font","datePublished":"2026-04-10T04:37:26+00:00","mainEntityOfPage":{"@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/"},"wordCount":2644,"commentCount":0,"image":{"@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage"},"thumbnailUrl":"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png","articleSection":["Characters"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/","url":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/","name":"Why Some Characters Don't Display in Your Browser or Font - CharacterCodes Blog","isPartOf":{"@id":"https:\/\/www.charactercodes.net\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage"},"image":{"@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage"},"thumbnailUrl":"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png","datePublished":"2026-04-10T04:37:26+00:00","author":{"@id":"https:\/\/www.charactercodes.net\/blog\/#\/schema\/person\/756aa07230428706f227ac4e178a7977"},"description":"Ever seen a \u25a1 where a character should be? Discover why glyphs go missing, how browsers choose fallback fonts, why emoji look different across devices, and how to fix it all.","breadcrumb":{"@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#primaryimage","url":"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png","contentUrl":"https:\/\/www.charactercodes.net\/blog\/wp-content\/uploads\/2026\/04\/blog-display-issues.png","width":840,"height":480,"caption":"character display issues"},{"@type":"BreadcrumbList","@id":"https:\/\/www.charactercodes.net\/blog\/why-some-characters-dont-display-in-your-browser-or-font\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.charactercodes.net\/blog\/"},{"@type":"ListItem","position":2,"name":"Why Some Characters Don&#8217;t Display in Your Browser or Font"}]},{"@type":"WebSite","@id":"https:\/\/www.charactercodes.net\/blog\/#website","url":"https:\/\/www.charactercodes.net\/blog\/","name":"CharacterCodes Blog","description":"Characters &amp; Emojis","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.charactercodes.net\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.charactercodes.net\/blog\/#\/schema\/person\/756aa07230428706f227ac4e178a7977","name":"admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/e188a164246c600f0cec7b14aec001469d0529676269f7d0fc364bfe2da4d7c2?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/e188a164246c600f0cec7b14aec001469d0529676269f7d0fc364bfe2da4d7c2?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e188a164246c600f0cec7b14aec001469d0529676269f7d0fc364bfe2da4d7c2?s=96&d=mm&r=g","caption":"admin"},"sameAs":["https:\/\/charactercodes.net\/blog1"],"url":"https:\/\/www.charactercodes.net\/blog\/author\/rspronk\/"}]}},"_links":{"self":[{"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/posts\/112","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/comments?post=112"}],"version-history":[{"count":2,"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/posts\/112\/revisions"}],"predecessor-version":[{"id":115,"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/posts\/112\/revisions\/115"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/media\/113"}],"wp:attachment":[{"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/media?parent=112"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/categories?post=112"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.charactercodes.net\/blog\/wp-json\/wp\/v2\/tags?post=112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}