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 を使うブロックなら、例えば pageUrl を location.href、shareText を document.title や data-* から渡す、といった形にできます。
2. ビルド用ヘルパ(土台の URL にオブジェクトをマージする例)
テンプレートや site.config 側のユーティリティとして、シェア用リンクの土台になるURLと クエリオブジェクトを受け取り、URLSearchParams で toString() して付与する、という薄いラッパを置く例です(関数名はプロジェクトで好きな呼び方で)。
/**
* 土台の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エンコード) のデモを置いています。
- デモ: SNSシェア | 静的サイト用ejsテンプレート
- ソース:
src/demo/demo-share/index.html
このデモでは、大きく2パターンを分けています。
- ビルド時に
hrefを作る … EJS 側でbaseUrlとページパスから共有 URL を作り、ty_appendQuery相当の処理で X / Facebook のhrefを組み立てる。LINE はサービス側の仕様に合わせて本文を連結する。 - 表示中の URL を使う … 初期マークアップには
data-*を持たせ、main.jsから読み込むdemo/_demo-share.jsでlocation.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>
staticPageUrl は https:// から相対 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/tweet に url, text など。 |
共有 URL を受け取り、パラメータ名が u 系のドキュメントが多い。 | sharer.php 等。キー名は url ではない例に注意。 | |
| LINE | LINE 公式の line it 等、url を取るパターン。 | プラグイン用 URL。 |
オフサイト共有で url を取る形が一般的。 | share-offsite 等。 | |
| 任意の自サイトを X と同じ要領で「一発ポスト」するための、Web 上のシェア用リンクの土台になるURLだけに頼るのは難しめ、という整理が多い。 | 通常はプロフィール・投稿の通常リンクが現実的。 | |
| YouTube | ブログ記事を「YouTube に投稿」は別用途。チャンネル・動画の URL へのリンクと切り分ける。 | 共有UIは主に YouTube コンテンツ向け。 |
「同じ href のパターンで全部いける」わけではないので、UI では Instagram / YouTube 向けに「シェア用リンクの土台になるURL」がある想定のものと、案内用の通常リンクを分けた方が、利用者の期待とズレにくいです。
まとめ
hrefは シェア用リンクの土台になるURL + クエリで、値には 日本語・記号が入るなら 必ずエンコード。- 実装は
URLSearchParamsか、同じ思想の薄いappendQuery的ヘルパに寄せると二重 encode を防ぎやすい。 - デモページのように、ビルド時(EJS 等)と、クライアント上書きの 両方をパターンとして持っておくと、要件に合わせ分けしやすい。
- SNS ごとに、シェア用リンクの土台になるURL があるか、パラメータ名は揃わない。表のように「違い」を1か所にまとめておくと更新しやすい。