ブログサイトのロゴsui Tech Blog

iOSでもWindowsと同じ絵文字を表示したい!

絵文字は私たちのデジタルコミュニケーションに欠かせない存在ですが、同じ絵文字コードでもOSによって見た目が大きく異なります。例えば「🫠」(溶ける顔)や「😎」(サングラスの顔)は、iOSとWindowsで全く異なるデザインです。本記事では、Webアプリケーション上でOSに関係なく統一した絵文字表示を実現するため、MicrosoftのFluent UI Emojiを使った実装方法を解説します。

iOSとWindowsでの絵文字差異

絵文字は Unicode で定義されています。
Unicode では絵文字ごとに固有のコードポイント(番号)が割り当てられており、これによってデバイス間で同じ絵文字が識別されます。

  • 😎 : U+1F60E
  • 😂 : U+1F602

Unicode はデザインを指定していません。
「😎=サングラスをかけた顔」という意味は統一されていますが、「どんなサングラスをかけるか」「表情はどうするか」などは各プラットフォームごとで自由にデザインできます。
これは意図的な設計選択であり、各企業が自社のデザイン言語に合わせた絵文字スタイルを開発できるようにしています。例えば以下のような違いがあります。

  • Apple の絵文字:光沢のある 3D 調デザインが特徴
  • Microsoft の絵文字:Fluent Design System に準拠したフラットでカラフルなデザイン
  • Google の絵文字:Material Design に基づいたシンプルなアウトラインと鮮やかな色使い

実際に絵文字の違いを見ていきましょう。
例えば「😎=サングラスをかけた顔」の絵文字は iOS ではこのようなアイコンになっています。
https://pub-37c337e4f6b74be784982bc3041040b4.r2.dev/images/IMG_9132.jpeg-1743294181758.png

Windows の PC で見たときはこのようなアイコンになっています。
https://pub-37c337e4f6b74be784982bc3041040b4.r2.dev/images/IMG_9133.jpeg-1743294181758.png
これは Microsoft の Fluent UI Emoji コレクションの一部です。
このコレクションはオープンソースで公開されており、以下のリポジトリからダウンロードできます。

github.com

GitHub - microsoft/fluentui-emoji: A collection of familiar, friendly, and modern emoji from Microsoft

A collection of familiar, friendly, and modern emoji from Microsoft - microsoft/fluentui-emoji

以下の Web サイトで各アイコンの比較をできます。

fluentemoji.com

Fluent Emoji - Browse Microsoft's delightful new emoji

Comprehensive online catalog of Microsoft's Fluent Emoji

どちらの絵文字も可愛いんですが、個人的には Fluent UI
Emoji のほうが可愛いですよね!?
ということで私のポートフォリオに表示しているブログページのアイコンを、Fluent UI
Emoji にしていきましょう。

Fluent Emojiの概要

絵文字はFluent Emojiで公開されている SVG を使用します。
例えば、「😎」は以下のような URL で定義されています。途中の %20 は半角スペースです。

https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Smiling%20face%20with%20sunglasses/Flat/smiling_face_with_sunglasses_flat.svg

各絵文字は /assets/{slug}/{style}/{slug}_{style}.svg という定義に成り立っているので、それにあわせて絵文字を fetch します。
今回は Flat アイコンのみを使用するので、style の箇所は flat 固定です。

絵文字の slug 特定には unicode-emoji-json を使用します。

pnpm add unicode-emoji-json

以下は unicode-emoji-json の構造体です。絵文字アイコンに紐づいて slug が設定されています。

{
  "😀": {
    "name": "grinning face",
    "slug": "grinning_face",
    "group": "Smileys & Emotion",
    "emoji_version": "1.0",
    "unicode_version": "1.0",
    "skin_tone_support": false
  }
}

変換ロジックの作成

絵文字の構造体が分かったところで、実際に絵文字アイコンを unicode-emoji-json を利用して変換する処理を実装していきましょう。
絵文字の構造体を見るに、各絵文字に紐づいている状態なので以下のような実装で slug 等を取得できます。

import emojiData from 'unicode-emoji-json';
 
type Emoji = {
  name: string;
  slug: string;
  group: string;
  emoji_version: string;
  unicode_version: string;
  skin_tone_support: boolean;
};
 
async function getValidFluentEmojiUrl(icon: string) {
  const emojiInfo = emojiData[icon as keyof typeof emojiData];
 
  if (!emojiInfo) {
    return icon;
  }
 
  // URLを生成
  const url = generateFluentEmojiUrl(emojiInfo);
 
  // URLが有効かどうかを確認
  const isValid = await checkUrlValidity(url);
 
  if (!isValid) {
    return icon;
  }
 
  return url;
}

絵文字が取得できたら、各絵文字の URL を取得していきます。
注意点としては、2015 年頃に人の顔や手足などを表す絵文字の一部で、ユーザーが肌の色(スキントーン)を選べるようになりました。その影響で一部絵文字の URL が異なっています。

(公式サイトから引用しようとしたらページが削除されていました…)

internet.watch.impress.co.jp

Apple、絵文字の“肌の色”を変更可能に、OS XとiOSの最新バージョンで 

肌の色を選ぶことができる絵文字は skin_tone_supportture のものが対象です。

今回は初期設定のデフォルトを選択します。

function generateFluentEmojiUrl(emojiInfo: Emoji) {
  const { name, slug, skin_tone_support } = emojiInfo;
 
  // ディレクトリ名は最初の単語の先頭のみ大文字、残りは小文字
  // grinning face -> Grinning face
  const dirName = name.charAt(0).toUpperCase() + name.slice(1);
 
  const encodedDirName = dirName.replace(/ /g, '%20');
 
  if (!skin_tone_support) {
    return `https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/${encodedDirName}/Flat/${slug}_flat.svg`;
  }
 
  return `https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/${encodedDirName}/Default/Flat/${slug}_flat_default.svg`;
}

最後に絵文字の有効性を確認します。
もし URL が異なっていたり、アイコンがなくなっているときは入力元のアイコンを表示したいので、fetch して正常終了するか確認していきましょう。

async function checkUrlValidity(url: string) {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      return false;
    }
    return true;
  } catch (error) {
    const message = error instanceof Error ? error.message : '不明なエラー';
    console.error(
      `URLの有効性チェックに失敗しました: ${url} message: ${message}`
    );
    return false;
  }
}

上記のソースコードを実装したものを、以下の記事で紹介したロジックに追加して記事を追加します。

suntory-n-water.com

LINE Messaging APIから自動でGitHubにPRを発行する

ポートフォリオの技術記事投稿頻度をあげるためにNotion + Messaging APIでブログ記事を自動でPull Requestを発行できるようにしました。mdxファイルの作成はnotion-markdown-converterを使用しています。

確認したところ、iOS でFluent
Emoji
の内容が反映されていますね。
https://pub-37c337e4f6b74be784982bc3041040b4.r2.dev/images/IMG_9137.png-1743294181758.png

見づらいですが救急車と波が iOS のものではないことが確認できます。
https://pub-37c337e4f6b74be784982bc3041040b4.r2.dev/images/IMG_9138.jpeg-1743294181758.png

まとめ

  • 絵文字は Unicode で統一的に定義されていますが、実際の表示デザインはプラットフォームによって異なる。
  • iOS でもFluent Emojiを使うことで、Windows で表示される絵文字と同様のものを使用できる。
  • Microsoft の Fluent UI Emoji はオープンソースで提供されており、Web アプリケーションで利用可能。
  • unicode-emoji-json ライブラリを利用して絵文字コードから Fluent Emoji へのマッピングを実装できます

関連記事