[Next.js] SNSシェアボタンを実装した
![[Next.js] SNSシェアボタンを実装した](/assets/note/eyecatch/sns-share-buttons-implementation-eyecatch.png)
やりたいこと
記事の末尾にSNSシェアボタンを置きたい。
X、Facebook、Threads、はてなブックマーク、LINEの5つに対応し、コピーボタンも追加する。
あわせて、このサイトのscheduleページにも同じ機能を入れたい。
主に自分のライブ告知用途で、イベント詳細をそのままXやLINEに貼り付けられるようにしたい。
最近のブラウザにはOSネイティブの共有機能が備わっていて、「わざわざシェアボタンを実装しなくてもいいのでは?」という意見もある。ブラウザの共有ダイアログからSNSに投稿できるし、実際それで十分なケースも多い。
今回実装した理由は単純にこの機能に興味があったからで、そもそもこのブログ自体あまり共有されるような内容でもなく、上記のような必要性の有無は実際のところどうでも良い。
ブログ然とした仕上がりを目指して徐々に機能を追加している最中で、そのひとつの要素にシェアボタン機能があったので実装することにした。
実装の概要
技術スタックはNext.js(App Router)+ TypeScript。シェアボタンはSnsShareButtonsというClient Componentとして切り出した。urlとshareTextをpropsで受け取る汎用的な設計にしたことで、記事ページとscheduleページで同じコンポーネントを使い回せている。
// 記事ページ
<SnsShareButtons
url="https://ofurousagi.com/note/my-post"
shareText="記事タイトル | ofurousagi"
/>
// scheduleページ
<SnsShareButtons
url="https://ofurousagi.com/schedule/2026-02-14"
shareText={scheduleShareText}
copyText={`${scheduleShareText}\n\n${url}\n`}
exclude={["はてな"]}
/>exclude にSNS名の配列を渡すと、そのボタンを非表示にできる。scheduleページははてなブックマークを除外している。
アイコンはCSS mask-image を使って実装した。PNG画像のアルファチャンネルをマスクとして使い、background-color: currentColor で色を乗せる。これによってライト/ダークモードの切り替えをCSSだけで吸収できる。
.maskedIcon {
display: block;
background-color: currentColor;
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
}各SNSのシェアURL
それぞれのシェアURLの形式をまとめる。TEXT と URL はいずれも encodeURIComponent() でエンコードして渡す。日本語や記号がURLに含まれると壊れるためだ。
const encodedUrl = encodeURIComponent("https://ofurousagi.com/note/my-post");
const encodedText = encodeURIComponent("記事タイトル | ofurousagi");X
https://twitter.com/intent/tweet?text=TEXT&url=URLtext にツイート本文、url にシェアするURLを渡す。url パラメータはX側で自動的に短縮されてテキスト末尾に付与される。
ただし url パラメータを使うとテキストとURLの間の改行を制御できない。改行を入れたい場合は url パラメータを使わず、text の中にURLを含めて %0A(改行)で区切る。
https://twitter.com/intent/tweet?text=TEXT%0A%0AURLhttps://www.facebook.com/sharer/sharer.php?u=URLURLのみ渡す。表示内容はページのOGPから取得される。
Threads
https://www.threads.net/intent/post?text=TEXTtext に投稿本文を渡す。URLも text に含める。
はてなブックマーク
https://b.hatena.ne.jp/entry/add?url=URLURLのみ渡す。
LINE
https://line.me/R/share?text=TEXTtext にテキストを渡す。URLも text に含める。
よく紹介される social-plugins.line.me/lineit/share?url= はURLのみ対応の仕様で、本文テキストを追加できない。本文も送りたい場合は line.me/R/share を使う。モバイルではLINEアプリが起動し、PCではLINE for Windows/Macが起動する。
scheduleページのシェアテキスト
scheduleページでは、イベントのフロントマターから以下のフォーマットでシェアテキストを自動生成している。
『イベント名』
日付 @会場
出演者1
出演者2
開場 XX:XX / 開演 XX:XX
¥2,500 +1drink ¥500コピーボタンではこのテキストの末尾にURLも含めた形でクリップボードにコピーされる。Xに貼ってそのまま投稿できる状態を目指した。皆さんもぜひ私のライブを告知してください。
GA4でクリック計測
シェアボタンのクリックはGA4の share イベントで計測している。method パラメータにSNS名(X、LINE など)を渡すことで、どのSNSからシェアされたかを把握できる。
const trackShare = (method: string) => {
if (typeof gtag !== "undefined") {
gtag("event", "share", { method, link_url: url });
}
};gtag はGA4のスクリプトがグローバルに定義する関数。typeof でチェックしてからコールすることで、スクリプトが未ロードの場合のエラーを防いでいる。
サイト全体のリンククリックは別途 link_click イベントで計測しているため、シェアボタンには data-no-track を付けて二重計測を防いでいる。
<a
href={href}
onClick={() => trackShare(label)}
data-no-track // グローバルの link_click 計測から除外
>
{icon}
</a>余談:CSS知識の退化
今回実装していて気づいたことがある。アイコンの色をCSSで制御したいと思ったとき、mask-image というプロパティ名がすぐに出てこなかった。「PNGのアルファチャンネルを使って色を乗せる方法」というイメージはあるのに、プロパティ名が思い出せない。これは結構ショックだった。
手でCSSを書く機会が減り、AIに任せることが増えた結果だと思う。知識が「なんとなく知っている」状態に薄まっている感覚がある。
AI時代の弊害とも言えるし、役割分担の変化とも言える。ただ、「何ができるかを知っている」ことと「どう書くかを知っている」ことは別物で、前者が失われると適切な指示すら出せなくなる。知識をどう保つか、あるいは保ち方そのものを変えるべきなのか、まだ答えが出ていない。
まとめ
urlパラメータを使うとXがURLを自動付与するため改行を制御できない。改行を入れたい場合はtextにURLを含め%0Aで区切る- LINEで本文付きシェアをするには
social-plugins.line.me/lineit/shareではなくline.me/R/share?text=を使う - CSS
mask-image+background-color: currentColorの組み合わせでモノクロPNGアイコンをテーマカラーに追従させられる - シェアボタンはscheduleページの告知用途にも流用できるよう、
urlとshareTextを外から渡す汎用設計にした
参考リンク
- Web Intent | X Developer Platform - XのシェアURLのパラメータ仕様
- LINE URL scheme | LINE Developers - LINEのURLスキーム一覧
- share イベント | Google Analytics(GA4) - GA4のshareイベントのパラメータ仕様


