Last updated on

SNSシェア用URLの組み立て(href・コード例・SNS差)

  • Web
  • SNS
  • URL
  • JavaScript
  • EJS

Web ページに「X で共有」「Facebook で共有」などのリンクを置くとき、**href は「シェア用リンクの土台になるURL」+「クエリ」**で組み立てるのが一般的です。本記事では、SNS シェア用 URL に絞って、実装例とサービスごとの差を整理します。

クエリ文字列や百分率エンコード、URLSearchParams の基本は、先に URLのクエリと百分率エンコード、URLSearchParamsで組み立てる にまとめています。

各サービスの エンドポイント名・パラメータ名は変更され得るため、本番では 公式ドキュメントをあたってください。以下は代表的な整理です。


SNS シェア用 href の考え方

多くのサービスでは、次の形になります。

(シェア用リンクの土台になるURL)?(パラメータ名1)=(値1)&(パラメータ名2)=(値2)&…

具体例(意味合いだけ。実際のキー名はサービスごとに異なる):

https://twitter.com/intent/tweet?url=https%3A%2F%2Fexample.com%2Fpage&text=%E3%81%8A%E7%9F%A5%E3%82%89%E3%81%9B

ポイントは次のとおりです。

  • ? の左 … 共有先が用意している シェア用リンクの土台になるURL(X の intent や Facebook の sharer など、サービスが決めたパスに当たる部分)。
  • ? の右クエリ文字列url=...text=... のような 名前と値のペアを、複数あるときは & でつなぐ。
  • 値の部分 … 共有したい ページ URLあらかじめ入れておきたいテキストなど。ここに日本語や & が入る場合は、URLSearchParams などにエンコードを任せる。

「1 本の文字列として href に渡す」か、「ビルドやスクリプトの中でオブジェクトから組み立てる」かは実装次第ですが、最終的にブラウザに渡る href は上の形になります。


実装時の注意点

シェア用 URL では、共有したい ページの URLあらかじめ入れておきたい文言をクエリの値として渡します。日本語、改行、#& などが入ることがあるため、手で文字列連結するより URLSearchParams に元の文字列を渡して組み立てる方が安全です。

注意したい点は次の3つです。

  • 二重にエンコードしない … すでにエンコード済みの文字列を、もう一度 encodeURIComponent しない。
  • 完成した href 全体を encode しないURLSearchParams には、キー名と元の値を渡す。
  • HTML 属性に出す文面 … ユーザー入力をそのまま href に入れる前に、サニタイズや属性向けのタグ除去が必要な場合は、プロジェクトのルールに従う。

エンコードする仕組み(主要コードの例)

中身は、「キー名 → 元の文字列(未 encode)」を渡し、ライブラリ/API にエンコードを任せる形にすると事故が減ります。

1. URLSearchParams(ブラウザ・Node 18+ 等)

URLSearchParams は、値を set する段階では文字列で持ち、toString() するとエンコード済みのクエリ文字列になります。

const pageUrl = 'https://example.com/記事?id=1';
const shareText = '【お知らせ】タイトル\n本文';

const params = new URLSearchParams();
params.set('url', pageUrl);
params.set('text', shareText);
const q = params.toString();
// 例: "url=...&text=..." (値は percent-encoded)

const href = 'https://twitter.com/intent/tweet?' + q;

表示中の URL を使うブロックなら、例えば pageUrllocation.hrefshareTextdocument.titledata-* から渡す、といった形にできます。

2. ビルド用ヘルパ(土台の URL にオブジェクトをマージする例)

テンプレートや site.config 側のユーティリティとして、シェア用リンクの土台になるURLクエリオブジェクトを受け取り、URLSearchParamstoString() して付与する、という薄いラッパを置く例です(関数名はプロジェクトで好きな呼び方で)。

/**
 * 土台のURL(シェア用リンクの土台)にクエリを付与(URLSearchParams で値を百分率エンコード)
 * @param {string} base 例: "https://twitter.com/intent/tweet"
 * @param {Record<string, string | number | undefined | null>} query
 */
export const appendQuery = (base, query = {}) => {
  const usp = new URLSearchParams();
  for (const [k, v] of Object.entries(query)) {
    if (v === undefined || v === null) continue;
    usp.set(k, String(v));
  }
  const s = usp.toString();
  if (!s) return base;
  return base + (base.includes('?') ? '&' : '?') + s;
};

// 使用例(X)
// appendQuery("https://twitter.com/intent/tweet", { url: absolutePageUrl, text: "お知らせ" });
// Facebook では u キーなど、サービスごとにキー名が違う点に注意

ty_appendQuery のような別名site 用ヘルパにしているプロジェクトもあります。要点は、usp.set に「意味のあるキー名」と生の文字列を渡し、連結の結果を href に用いることです。


デモページ

実際に動く見本として、静的サイト用 EJS テンプレートに SNS シェア(URLエンコード) のデモを置いています。

このデモでは、大きく2パターンを分けています。

  • ビルド時に href を作る … EJS 側で baseUrl とページパスから共有 URL を作り、ty_appendQuery 相当の処理で X / Facebook の href を組み立てる。LINE はサービス側の仕様に合わせて本文を連結する。
  • 表示中の URL を使う … 初期マークアップには data-* を持たせ、main.js から読み込む demo/_demo-share.jslocation.href を使って href を差し替える。

Facebook は u に URL のみを渡し、X / LINE は本文と URL を1本のテキストとして扱う、という違いもデモ内で分けています。Instagram や YouTube は、任意の自サイト URL を同じ形で「投稿」する導線とは別物として、通常リンクの例に留めています。


使用例(記述例)

テンプレート(ビルド時に href が確定する例)

EJS などの サーバー/ビルド側で、絶対 URL と文言の変数が取れているとします。関数名は例です。

<%
  const xHref = appendQuery("https://twitter.com/intent/tweet", {
    url: staticPageUrl,
    text: shareTextStatic,
  });
%>
<a href="<%= xHref %>" target="_blank" rel="noopener noreferrer">X でポスト</a>

staticPageUrlhttps:// から相対 path まで含む 1 本の文字列にしてから渡す、と扱いやすいです。

クライアント(表示中のページ URL で href を上書きする例)

初回の href# にしておき、DOMContentLoaded で差し替える、という流れの例です。

const pageUrl = window.location.href;
const text = document.title;

const p = new URLSearchParams();
p.set("url", pageUrl);
p.set("text", text);

const a = document.querySelector('a[href="#"][data-share="x"]');
if (a) {
  a.href = "https://twitter.com/intent/tweet?" + p.toString();
  a.setAttribute("rel", "noopener noreferrer");
  a.setAttribute("target", "_blank");
}

data-*querySelector の条件は、そのページ専用のマーカーを付けて衝突を避けます。

1 行で手で連結する場合

const u = "https://example.com/";
const t = "見出し";
const href =
  "https://twitter.com/intent/tweet?url=" +
  encodeURIComponent(u) +
  "&text=" +
  encodeURIComponent(t);

encodeURIComponent各値ごとに呼び、完成した href 全体を二重に encode しない、という分け方が分かりやすいです。


SNS ごとの違い(ざっくり一覧)

サービスざっくりした扱いクエリの例(キー名は公式要確認)
X任意ページ URL +任意テキストを渡す、シェア用リンクの土台になるURL が定番。https://twitter.com/intent/tweeturl, text など。
Facebook共有 URL を受け取り、パラメータ名が uのドキュメントが多い。sharer.php 等。キー名は url ではない例に注意。
LINELINE 公式の line it 等、url を取るパターン。プラグイン用 URL。
LinkedInオフサイト共有で url を取る形が一般的。share-offsite 等。
Instagram任意の自サイトを X と同じ要領で「一発ポスト」するための、Web 上のシェア用リンクの土台になるURLだけに頼るのは難しめ、という整理が多い。通常はプロフィール・投稿の通常リンクが現実的。
YouTubeブログ記事を「YouTube に投稿」は別用途。チャンネル・動画の URL へのリンクと切り分ける。共有UIは主に YouTube コンテンツ向け。

「同じ href のパターンで全部いける」わけではないので、UI では Instagram / YouTube 向けに「シェア用リンクの土台になるURL」がある想定のものと、案内用の通常リンクを分けた方が、利用者の期待とズレにくいです。


まとめ

  • hrefシェア用リンクの土台になるURL + クエリで、値には 日本語・記号が入るなら 必ずエンコード
  • 実装は URLSearchParams か、同じ思想の薄い appendQuery 的ヘルパに寄せると二重 encode を防ぎやすい。
  • デモページのように、ビルド時(EJS 等)と、クライアント上書きの 両方をパターンとして持っておくと、要件に合わせ分けしやすい。
  • SNS ごとに、シェア用リンクの土台になるURL があるかパラメータ名は揃わない。表のように「違い」を1か所にまとめておくと更新しやすい。