LINEヤフー Tech Blog

LINEヤフー株式会社のサービスを支える、技術・開発文化を発信しています。

LINEギフトの新規キャンペーン「ギフトくじ」のフロントエンド実装(インターンレポート)

はじめに

はじめまして。東京理科大学大学院 創域理工学研究科 情報計算科学専攻 修士1年の佐藤太心です。

私は2025年度のサマーインターンシップで、LINEギフトのサービスフロントエンド開発業務に従事しました。このレポートでは、LINEギフトの新たなキャンペーンである「ギフトくじ」のフロントエンド実装における体験談、そして6週間にわたるインターンシップを通して学んだこと・感じたことを書いています。

LINEギフトとは

みなさん、LINEギフトはご存知でしょうか。LINEアプリ上で友だちと簡単にギフトを贈り合えるサービスで、私自身は大学の友人から誕生日にeギフトをもらったのをきっかけに使うようになりました。

技術スタック

LINEギフトのフロントエンドはVue 3 + TypeScriptで構成されており、今回のインターンシップでもその技術スタックで開発しました。

タスクと開発の流れについて

インターンシップ期間の3分の2ほどをかけて取り組んだ「ギフトくじ履歴画面」の実装について紹介します。

実装した「くじ履歴画面」のモック画面
実装した「くじ履歴画面」のモック画面

※景品等はイメージです。実際のギフトくじ履歴画面の内容とは異なる場合があります。

ギフトくじとは

LINEギフトでは、2025年10月に「ハロウィンギフトくじ」キャンペーンを行いました。期間中に対象商品を友だちに贈ると、ギフトを贈った人ともらった人の両方が抽選に参加できるキャンペーンで、後日抽選で人気ギフトが当たります。

実装した「くじ」のモック画面
実装した「くじ」のモック画面

ギフトくじ履歴画面の実装

今回実装した「ギフトくじ履歴画面」では、友だちからもらった/友だちに贈ったギフトくじの番号や、くじの当選結果を確認できます。企画の方が考えてくださった仕様書をもとに機能を実装し、デザイナーの方のFigmaをもとにUIを実装するという流れでした。しかし、実装を進めていくと思わぬ問題点が発覚し、途中で仕様やデザインを修正していただく場面もありました。

LINEギフトのデザインデータは、基本的にはビューポート幅が375pxの場合を基準に作成され、それ以外の横幅の場合は実装者が適宜レイアウトを調整します。しかし、ギフトくじ履歴画面では下図のAs-isのように、横幅320pxの環境では名前のほとんどが省略されてしまうほか、くじ番号やボタンの大きさや配置をエンジニアの裁量だけでは決めかねる状況でした。そこで、要素の大きさやフォントサイズを手元で調整しながら、横幅320px時のデザイン仕様をデザイナーの方と一緒にTo-beのような形に決めました。(ちなみにiPhone SE(第1世代)のように実際の画面横幅が320pxの場合のみならず、より大きい画面サイズのスマートフォンでも拡大表示設定している場合を想定し、横幅320pxでも画面が崩れないように調整しました。)

320px時の表示のAs-isとTo-be

与えられたタスクを進めるだけでなく、企画やデザイン、そしてサーバーの方とも密に連携を取ることの重要性を感じました。「この仕様は、こういう解釈で実装して問題ないか」、「このデザインは、他のコンポーネントのこの部分に合わせたほうがいいかもしれない」、そして「この内容を処理するために、他にもこの項目をAPIで返してほしい」など、「こうしたほうがいい」と思ったことを積極的に提案できる環境でした。

試行錯誤と得られた知見

個人開発や大学サークル内での開発ではなかなか気づかないような課題に直面し、とてもよい経験になりました。ここでは、以下の2つをピックアップしてご紹介します。

  1. 絵文字を含む文字列のトランケーション
  2. Lottie形式のアニメーションの実装

1. 絵文字を含む文字列のトランケーション

絵文字はUnicodeで標準化されており、OSやフォントの更新によって順次新しいものが追加されています。その中でも、ZWJ(ゼロ幅接合子)を使い、複数の絵文字を組み合わせて1つの絵文字のように表示するようなものも増えています。たとえば、絵文字「ライム🍋‍🟩」は「レモン🍋 + ZWJ + 緑の大四角🟩」から構成されています。

絵文字ライムの構成要素: 🍋‍🟩=🍋+ZWJ+🟩

このように合字表現される絵文字を含む文字列を特定の文字数でトランケート(切り詰め)しようとしたときに、以下の画像のAs-isのようになってしまい、期待通りにならない問題が発生しました。

絵文字を含む文字列のトランケーションのAs-isとTo-be

結論

先に結論から説明すると、文字数でのトランケーションをあきらめ、CSSのみを使い、あふれたコンテンツに省略記号をつける実装が最も妥当だと判断しました。以下の例では、containerの横幅にnameArea全体が収まりきるように、nameBodyをトランケートしています。

<div class='container' id='container'>
  <div class='nameArea'>
    <span 
      class='nameBody' 
      id='name'>🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩</span><span 
      class='nameSuffix'>さんからもらった
    </span>
  </div>
</div>
.container {
  width: 200px;
  border: 1px solid #e0e0e0;
}

.nameArea {
  display: flex;
}

.nameBody {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nameSuffix {
  flex: none;
}

原因と試行錯誤

正常にトランケートできない原因は、絵文字を含む文字列の文字数を正しくカウントできないことにありました。まず、単純に絵文字のlengthを取ろうとすると、以下のようになります。

console.log('🍋‍🟩'.length);
// 5

また、配列に変換した後に長さを取得すると、以下のようになります。

console.log(Array.from('🍋‍🟩').length);
// 3
console.log(Array.from('🍋‍🟩'));
// (3) ['🍋', '‍', '🟩']

先述のとおり「🍋‍🟩」は「🍋 + ZWJ + 🟩」から構成されるので納得感はありますが、期待通りではありません。

そして、ブラウザ標準機能の Intl.Segmenter Constructor を使うことで、文字数でのトランケーションがうまくできましたが、Intl.SegmenterはiOS 14.5以降でサポートされるため、iOS 14をサポート対象に含めるLINEギフトでは使えませんでした。さらに、emoji-regex というパッケージで絵文字のカウントができましたが、文字数での切り出しがうまくできず断念しました。たとえば、文字列「🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩🍋‍🟩」を3文字でトランケートしようとしたとき、「🍋‍🟩 + 🍋 + [ZWJ]」の段階で3文字だと判定してしまい、期待する「🍋‍🟩🍋‍🟩🍋‍🟩」を得られませんでした。

そもそも、仮に正しく文字数で切り出せた(たとえば「🍋‍🟩🍋‍🟩🍋‍🟩」)としても、ライムの絵文字🍋‍🟩はiOS 17.4で登場したため、それ以前の環境ではライムではなくレモン🍋と緑四角形🟩として表示されます。その結果、3文字ではなくなる(たとえば「🍋🟩🍋🟩🍋🟩」のように6文字になる)ので表示が崩れる可能性があります。一方でCSSによるトランケーションの場合、あふれたコンテンツを省略処理するだけなので、各絵文字のOSバージョンごとの対応などを考える必要がありません。

以上の経緯により、JavaScriptでの文字数トランケーションではなく、CSSでの実装を採用しました。

2. Lottie形式のアニメーションの実装

私はこれまでWebページにアニメーションを貼り付けるとき、GIFしか用いたことがありませんでしたが、Animated PNG(APNG)やLottieといった他の形式を知りました。「結果確認」ボタン押下後に画面全体をオーバーレイする「くじ」の開封アニメーションには、Lottieが使われています。Lottieは、Adobe After Effectsで書き出したJSONを解釈し、ベクターアニメーションを再生できるライブラリです。

LottieをSVGでレンダリングすると、以下の動画のようにアニメーションの各パスがすべてDOM要素になるため、特にモバイル端末ではブラウザのレンダリングが追いつかない場合があります。開発用PCではスムーズに動いていましたが、いざ実機で試してみるとカクつきが見られました。

そこで、レンダラーをSVGからCanvasに切り替えました。Canvasレンダリングでは、各フレームのSVGを随時ラスタライズ(ラスター画像化)して、アニメーションが1つのDOM <canvas> 要素に反映されます。ベクター情報は失われてしまうものの、レイアウト、スタイル、描画計算などのDOMの複雑な更新処理をすべてスキップすることで、軽量な描画が実現されます。DOMの変更による頻繁な再計算がクライアントに大きな計算負荷を与えることを実感しました。

インターンシップ全体を通して

普段使っているサービスの裏側にいる人たちと一緒に、3,500万人(※)の累計ユーザー数を誇るサービスの開発に携わることができ、大きなやりがいを感じています。そして何よりもチームのみなさんの人柄がよく、物理出社時もリモート時もスムーズにコミュニケーションが取れたおかげで、とても楽しく過ごせました。(※2024年7月時点)

メンターの方をはじめ、チーム内外でPull requestをレビューしてくれたみなさん、Slack上でいつでもご相談・お話に乗ってくださったみなさん、一緒にお昼ご飯を食べたみなさん、大変お世話になりました。あっという間の6週間でした。本当にありがとうございました。

メンターからの一言

佐藤さんのメンターを務めた丸岡賢人です。普段はLINEギフトのフロントエンド開発を担当しています。

今回のインターンシップでは、実際の業務フローを体験していただけるよう、LINEギフトの新キャンペーンである「ギフトくじ」の主要画面を一から実装していただきました。初めてのキャンペーンであったためステークホルダーも多く、企画・デザインとの仕様すり合わせといった実装以外の業務も重要となりましたが、佐藤さんは積極的にコミュニケーションを取りながら進めてくださり、安心してお任せできました。

技術面でも、絵文字を含む文字列の表示崩れについて、最終的にCSSで解決する判断に至るまでの調査過程を、読みやすいドキュメントに整理してくださいました。実際のプロダクトには反映されない部分ですが、このようなハマりやすいケースについての調査ログは今後開発を進めていく中で非常に有用なものです。素晴らしい成果でした。ありがとうございます!

そのほか、キャッチアップを兼ねて使われなくなったAPI呼び出しの削除やデバッグ用機能の実装にも取り組み、パフォーマンス改善や開発効率向上にも貢献してくださいました。

6週間のインターンシップお疲れさまでした。またお会いできることを楽しみにしています。ありがとうございました!