🔗

Web で URL やテキストをシェアする時の手法(SNS シェアボタン, Clipboard API, Share API)

2023/07/08に公開

どういう人向けか

Web サービスやサイトで URL やテキストをシェアする機能を作りたい人向け。

JavaScript が必要な箇所は React で記載しています。

動機

Web サイトを見ると当然のように SNS へのシェアボタンが SNS 毎に用意されており、個人的は 1 ボタンにまとめられないかと思っていました。

最近は Twitter から様々な SNS へ乗り換えを検討する人が増えてきたこともあり、それぞれに対して SNS アイコンを増やすのも、実装の面でも見た目の面でも野暮ったい印象があるため、何かいい解決策がないかと思いました。

結論

  • 依然として SNS シェアボタンが実装が楽で、投稿させるのが楽
  • Clipboard API を利用する場合は、コピー完了時のアクションを用意する方が丁寧
  • Share API も使えない事はないが、動かないデバイスとブラウザの組み合わせがあったり、特定の SNS にはアプリインストールの前提があったり、考慮点が多い
  • 妥協案として、それぞれの SNS のシェアボタンをツールチップとして表示する(後述)

下記は自分が試すために作った CodeSandbox です。(Twitter のシェアリンクはブロックされるみたいなので、Open In New Window で開いてください)

https://codesandbox.io/s/sns-share-links-and-clipboard-share-api-s6dfj5?file=/src/App.tsx

SNS シェアボタン

現時点で最も普及していると思われる方法です。

指定のクエリパラメーター付きのリンクを用意し、それをクリックすると SNS の投稿画面に遷移し、投稿時の初期テキストが設定されているものです。

よくある Twitter や Facebook、LINE へのシェアリンクはこれが大半だと思います。

仕組みとしては下記のような URL を a タグに指定するだけで OK です。(Twitter の場合)

<a
  href="https://twitter.com/intent/tweet?text=ツイートしたいテキスト"
  target="_blank"
  rel="noopener noreferrer"
>
  ツイートする
</a>

他にどのようなクエリパラメータが設定できるかは下記に記載があります。

https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/guides/web-intent

メリット

  • 実装が楽
  • 他のシェア方法に比べて投稿に必要なアクションが少ない

デメリット

  • シェアしたい SNS 毎にリンクを増やす必要がある

Clipboard API

https://developer.mozilla.org/ja/docs/Web/API/Clipboard_API

JavaScript 側でクリップボードに読み書きする API です。
Read する場合には権限が必要なことがありますが、テキストの Write はほぼどの環境でも動作します。

const CopyButton = () => {
  const copy = async () => {
    try {
      await navigator.clipboard.writeText("シェアしたいテキスト");
      // 成功時アクション
    } catch (error) {
      // 失敗時時アクション
    }
  };
  return (
    <button onClick={copy} type="button">
      クリップボードにコピー
    </button>
  );
};

メリット

  • 特定の SNS に依存しない

デメリット

  • SNS シェアボタンと比べ、投稿するのにクリップボードからの貼り付け、という 1 アクションが増える
  • コピー完了時に何もアクションがないため、場合によってはコピー完了のポップアップの表示が必要

Share API

https://developer.mozilla.org/ja/docs/Web/API/Web_Share_API

JavaScript でデバイスに組み込みの共有機能を利用する API です。
共有 API というとあまり馴染みがありませんが、ブラウザ側に搭載されている共有ボタンをクリックしたときと同じような挙動ができます。

iOS 版 Google Chrome
Share at Google Chrome

iOS 版 Safari
Share at Safari

実装例は下記です。JS 経由での共有 API は動作しないことがあるため、"canShare" in navigator && navigator.canShare(data) でチェックを入れています。

const ShareButton = () => {
  const data: ShareData = {
    title: "Google",
    text: "Googleのリンク",
    url: "https://www.google.com/",
  };

  const share = async () => {
    try {
      await navigator.share(data);
      // 成功時アクション
    } catch (error) {
      // 失敗時時アクション
    }
  };

  const isCanShare = "canShare" in navigator && navigator.canShare(data);

  return (
    <button onClick={share} disabled={!isCanShare} type="button">
      {isCanShare
        ? "シェアする"
        : "このデバイスとブラウザの組み合わせではシェアできません"}
    </button>
  );
};

メリット

  • 1 箇所のアクションで、複数の SNS やアプリに対応できる

デメリット

  • 動作しないデバイスとブラウザの組み合わせがあるため、表示の出し分けが必要
    • 例: Chrome on macOS は動かないが Safari on macOS は動く
  • ブラウザ側にもある機能のため、サイト側で実装すると二重実装になる
  • どのアプリのみで共有したい、という指定ができない
    • Twitter で共有してほしくても、メールや Google Drive などへの導線が出てしまう
    • 共有可能先がデバイスやアプリのインストール状況で変わってしまう。特にモバイルとデバイスでは挙動がかなり変わる

妥協案

結局のところ、SNS のシェアボタンが利便性や安定性がいいのですが、対応する SNS 毎にボタンが増えるとスペースを圧迫します。
そこで妥協案として、ボタンをクリックするとそれぞれの SNS のシェアリンクが展開されるツールチップを作成してみます。

リンクが表示されればいいので Modal でもいいです。Popover API でもいいのですが、対応できてないブラウザも多いので外部ライブラリでツールチップを使っています。

実装した例は下記で確認できます。

https://s6dfj5.csb.app/

import { Tooltip } from "react-tooltip";

const generateTweetLink = (shareText: string) => {
  try {
    const url = new URL("https://twitter.com/intent/tweet");
    shareText && url.searchParams.set("text", shareText);
    return url.href;
  } catch (error) {
    return "";
  }
};

const generateTootLink = (shareText: string) => {
  try {
    const url = new URL("https://mstdn.jp/share");
    shareText && url.searchParams.set("text", shareText);
    return url.href;
  } catch (error) {
    return "";
  }
};

const ShareLinks = () => {
  const shareText = "Google https://www.google.com/";

  const tweetLink = generateTweetLink(shareText);
  const mastodonLink = generateTootLink(shareText);

  return (
    <>
      <button data-tooltip-id="my-tooltip-click" data-tooltip-place="bottom">
        SNSでシェア
      </button>
      <Tooltip
        id="my-tooltip-click"
        openOnClick
        clickable
        style={{ color: "white" }}
      >
        <ul>
          <li>
            <a
              href={tweetLink}
              target={"_blank"}
              rel={"noopener noreferrer"}
              style={{ color: "white" }}
            >
              Twitter
            </a>
          </li>
          <li>
            <a
              href={mastodonLink}
              target={"_blank"}
              rel={"noopener noreferrer"}
              style={{ color: "white" }}
            >
              mstdn.jp
            </a>
          </li>
        </ul>
      </Tooltip>
    </>
  );
};

まとめ

多くのサイトでは当然のように Twitter,Facebook,LINE 向けのシェアボタンがあるのですが、このまま SNS が増えていったらどうするんだろうと思い調べてみましたが、シェアボタンだと投稿の導線が楽というのは変わっていません。

現在注目されている分散型の SNS だとインスタンスが異なるとドメインが変わってしまうので、それ用のシェアボタンを用意するかは悩ましいです。

Discussion