PROMARI JOURNAL

そういえば、書く場所へは共有できなかった。Qiita・Zenn・note・Medium・アメブロへの共有ボタンを足しました

作成: / 公開: / 内容更新:

執筆:tamito0201 / 掲載・運営:プロマリ

記事の下の共有欄に、X や LINE はあるのに、読んだ人が自分の記事で紹介する Qiita・Zenn・note・Medium・アメブロへの入口がありませんでした。note は公式の共有入口へ、入口の無い4つは「題名と URL をコピーして投稿画面を開く」新しい動きで足しました。4.2.0 では、貼った先でそのまま記事のカードになるよう、共有先ごとの書き方をそろ…

PASS IT ON

ひとつの発見を、次の会話へ。

見える棚に置くか、引き出しにしまうか

前のページで、5つの共有先の動きがそろいました。このページでは、増えたボタンを共有欄のどこに並べたかを見ていきます。ボタンの動きを決めるのはプラグインで、どのボタンをどこに並べるかを決めるのは、それを使うサイトの設定です。この2つを分けておくと、同じプラグインを使うサイトごとに、自分の読者に合った並べ方を選べます。

図4-1 見える棚に置くか、引き出しにしまうか
図4-1 見える棚に置くか、引き出しにしまうか。現在のしくみ。よく使われそうな4つは見える棚に、アメブロは引き出しに入れました。どちらに置くかは、サイトの設定の2つの項目で決まります。図4-1 見える棚に置くか、引き出しにしまうか。現在のしくみ。よく使われそうな4つは見える棚に、アメブロは引き出しに入れました。どちらに置くかは、サイトの設定の2つの項目で決まります。

promari.jp の共有欄には、ボタンを置く場所が2つあります。1つは、いつも見えている主の列で、お店でいえば店先の陳列棚です。もう1つは、「その他」を押すと開く引き出しで、お店の奥の棚にあたります。主の列は目に入りやすい代わりに、並べられる数に限りがあります。引き出しはいくらでも入りますが、開けてもらわないと見えません。

今回、Qiita・Zenn・note・Medium の4つは、主の列に並べました。このブログの読者がよく書く場所は、探さなくても見える場所にあってほしいからです。技術ブログの読者にとって、Qiita と Zenn は日常的に使う場所ですし、note と Medium も、技術や仕事について書く人の多い場所です。せっかく足しても、「その他」の中に隠れていたら、足したことに気づいてもらえません。

一方、アメブロは「その他」の中に入れました。アメブロは日記や暮らしの話を書く人が多い場所で、技術ブログの読者が紹介の記事を書く場所としては、ほかの4つほど多くないと考えたからです。使う人がいる以上、入口は用意しておきたい。けれど、主の列の貴重な場所を使うほどではない。そういう共有先の置き場所として、引き出しはちょうどよい棚です。

どちらに置くかは、サイトの設定ファイル(.config/share_config.toml)の2つの項目で決まります。主の列は share.destinations の並び、引き出しは share.secondary の表です。

TOMLpromari.jp の .config/share_config.toml(変更した行の抜粋)
[share]
destinations = ["x", "line", "facebook", "qiita", "zenn", "note", "medium", "copy", "native"] # 記事を書く場所(Qiita・Zenn・note・Medium)は「その他」に入れず見える列へ

[share.labels]
qiita = "Qiita"
zenn = "Zenn"
note = "note"
medium = "Medium"
ameba = "アメブロ"

[share.secondary]
hatena = true
linkedin = true
email = true
ameba = true # アメブロは「その他」に入れる

destinations の並びは、そのまま左から右への並び順です。言いふらす場所(X・LINE・Facebook)のあとに、書く場所(Qiita・Zenn・note・Medium)を置き、その後ろに手元に残すための URL のコピーと端末の共有を置きました。1ページ目の路線図の3つの方向が、左から順に並ぶようにしています。share.labels はボタンの下に出す名前で、share.secondary に true と書いたものが「その他」の中に入ります。

この設定の変更は、プラグインの変更とは別の PR にしています。理由は5ページ目でお話ししますが、プラグインの新しい版が配られるより前に、サイトの設定だけが変わると困るからです。

スマホの幅に、10個の丸は入らない

主の列に4つ足したことで、1つ困ったことが起きました。円いボタンが、主の列の9個と「その他」の1個で、合わせて10個になったのです。これが、スマホの画面に収まりませんでした。

図4.1-1 スマホの幅に、10個の丸は入らない
図4.1-1 スマホの幅に、10個の丸は入らない。実測。1列に並べたままだと、幅390pxのスマホでも右へはみ出します。そこで、入りきらない分を次の段へ折り返すようにしました。図4.1-1 スマホの幅に、10個の丸は入らない。実測。1列に並べたままだと、幅390pxのスマホでも右へはみ出します。そこで、入りきらない分を次の段へ折り返すようにしました。

スマホの幅での円いボタンは、1個が38ピクセルで、ボタンとボタンのすき間が7ピクセルです。10個を1列に並べると、38×10+7×9で、443ピクセルになります。よく使われるスマホの画面の幅は、390ピクセルや、小さいもので320ピクセルほどです。1列のままだと、ボタンの列が画面の右へはみ出して、ページ全体が横にスクロールできてしまうのです。横にずれるページは読みにくく、指で触ったときに画面がふらつく原因にもなります。

これまでボタンは6個だったので、1列でも収まっていました。数を増やしたとたん、それまで表に出なかった「折り返さない」という作りが、問題として現れたわけです。そこで、円いボタンの列に折り返し(flex-wrap)の指定を足し、入りきらないボタンは次の段へ折り返すようにしました。

CSSweb/src/presentation/CircularShareBarView.ts(ボタンの列の指定・変更後の抜粋)
.socials{display:flex;flex-wrap:wrap;align-items:flex-start;gap:12px 9px;min-width:0}

flex-wrap:wrap が「入りきらなければ折り返す」、gap:12px 9px が「段と段のあいだは12ピクセル、ボタンとボタンのあいだは9ピクセル」という指定です。min-width:0 は、中身の大きさに引っ張られて列そのものが画面より広がらないようにする指定です。

直したあとは、本物のブラウザを動かして確かめる道具(Playwright)で、3つの幅の画面に10個のボタンを並べ、はみ出さないことを確かめる試験を足しました。

10個の円いボタンを並べたときの実測(promari-toolkit#29 の試験)
画面の幅段の数いちばん右のボタンの右端「その他」を開いたときの位置横スクロール
1440px1段705px385〜705px出ない
390px2段364px16〜336px出ない
320px2段274px16〜304px出ない

パソコンの広い画面では1段のまま、スマホでは2段に分かれ、どの幅でもボタンの右端は画面の中に収まりました。「その他」の引き出しを開いたときの中身も、画面の左右16ピクセルの内側に入っています。試験を足したときに、折り返しの指定をわざと外して走らせ、幅390ピクセルで失敗することも確かめました。直す前の状態で失敗する試験でなければ、直したことの証明にならないからです。

「その他」の引き出しは、画面の中で開く

ボタンを2段に折り返すと、もう1つ気をつけることがありました。「その他」の引き出しを開いたときの位置です。

「その他」を押すと、はてなブックマーク・LinkedIn・メール・アメブロの4つを並べた小さな板(パネル)が、ボタンの下に開きます。このパネルは、もともと「その他」のボタンの右端にそろえて開く作りでした。1段に並んでいたころは、「その他」がいつも列の右端にあったので、それで問題ありませんでした。ところが2段に折り返すと、「その他」が2段目の途中に来ることがあります。そこで右端にそろえて開くと、パネルが画面の左へはみ出してしまうのです。

この部品には、パネルを開いたあとで、画面からはみ出していないかを確かめて、はみ出していれば内側へずらす処理が、もともと入っていました。

TypeScriptweb/src/presentation/PromariSnsShareElement.ts(パネルを画面の内側へずらす計算・抜粋)
const box = panel.getBoundingClientRect();
const shift = box.left < 16 ? 16 - box.left : Math.min(0, innerWidth - 16 - box.right);

1行目で、開いたパネルが画面のどこにあるかを測ります。2行目で、パネルの左端が画面の左から16ピクセルより内側に入っていなければ、そのぶん右へずらし、右端が画面の右から16ピクセルを越えていれば、そのぶん左へずらします。今回の Playwright の試験では、折り返したあとでも、この処理でパネルが左右16ピクセルの内側に収まることを確かめました。前の節の表の「その他を開いたときの位置」の列が、その結果です。

ただ、この処理は、パネルを開いたあとで動きます。そのため、開いた瞬間のほんの一瞬だけ、パネルが画面の外に出ている可能性があります。人の目にはほとんど分からない時間ですが、これも以前からの作りで、今回の変更の範囲外として記録にとどめています。直したことと、直していないことを分けて書いておくのは、次に触る人のためです。

ボタンの色と印は、借りてきたもの

新しいボタンには、それぞれのサービスの色と、ロゴの形のアイコンを付けています。この色と形を、どこから持ってきたかも大事な話です。

図4.3-1 ボタンの色と印は、借りてきたもの
図4.3-1 ボタンの色と印は、借りてきたもの。現在のしくみ。色は公式の資料か、アイコン集の値から取りました。ロゴの形は、自由に使える条件のアイコン集から借り、出典を定義のファイルに残しました。図4.3-1 ボタンの色と印は、借りてきたもの。現在のしくみ。色は公式の資料か、アイコン集の値から取りました。ロゴの形は、自由に使える条件のアイコン集から借り、出典を定義のファイルに残しました。

色は、できるだけ各サービスの公式の資料から取りました。Qiita の緑(#55C500)は公式のガイドラインから、Zenn の青(#3EA8FF)は公式のメディアキット(報道や紹介のための素材集)から確かめています。note・Medium・アメブロは、公式の資料から色を取り出せなかったので、次に説明するアイコン集に記録されている値を使いました。色の値そのものは、それぞれのカードの brand_color に書いてあります。どの値をどこから取ったかは、プラグインの PR(promari-toolkit#29)の説明に記録しました。

アイコンの形は、simple-icons というアイコン集から借りました。simple-icons は、たくさんのサービスのロゴの形を、自由に使えるCC0という条件で配っています。ただし、気をつけたいのは、アイコンの形を自由に使えることと、ロゴそのものを自由に使えることは別だという点です。ロゴは各社の商標で、使い方の決まりは持ち主が決めます。共有ボタンは「このサービスへ共有する」ことを示すための、ごく一般的な使い方ですが、念のため、借りた出典と「ロゴは各社の商標」であることを、カードの2行目と、プラグインの設定の説明に書き残しました。この記事の図にロゴを描いていないのも、同じ理由です。

ちなみに、円いボタンの表示には、よく使う共有先のアイコンだけを並べた一覧が、プログラムの中に直接書いてあります。新しい5つは、その一覧には足していません。一覧に無い共有先は、カードの icon に書いたアイコンを使う、という既存の仕組みがあるからです。カードに書いたものが、そのまま画面に出るので、共有先を足すたびにプログラムの一覧を直す必要がありません。

書き間違いは、配布の前に検査機で止める

共有先をカード(データ)で持つ作りには、1つ弱点があります。カードはプログラムではないので、書き間違えても、書いた瞬間には誰も教えてくれないのです。たとえば、compose のカードに、うっかり [params] を書いてしまったらどうなるでしょうか。

図4.4-1 書き間違いは、配布の前に検査機で止める
図4.4-1 書き間違いは、配布の前に検査機で止める。現在のしくみ。定義のファイルは、配布物を作る前に生成器の検査を通ります。compose に要らない項目が混ざっていたら、そこで止まります。図4.4-1 書き間違いは、配布の前に検査機で止める。現在のしくみ。定義のファイルは、配布物を作る前に生成器の検査を通ります。compose に要らない項目が混ざっていたら、そこで止まります。

このプラグインでは、カードは配布物になる前に、必ず生成器(tools/config.py)を通ります。生成器は、カードを1枚ずつ読み込み、空港の手荷物検査のように中身を確かめてから、プログラムが使う一覧に組み立てます。そして、知らない項目や、決まりに合わない書き方を見つけたら、その場でエラーを出して止まります。判断に迷うものは通さずに止める、というfail closedの方針です。

今回、compose のために、検査の項目を2つ足しました。

Pythontools/config.py(compose のカードの検査・抜粋)
if action == ShareAction.COMPOSE:
    # compose opens a fixed editor page; nothing is sent in the URL, so [params] is rejected even when empty.
    ensure(d["endpoint"], lambda e: e.startswith("https://") and COMPOSE_ENDPOINT_FORBIDDEN.isdisjoint(e), f"{name}: action = 'compose' には https:// で始まる投稿画面の URL を endpoint に書いてください(空白・引用符は不可)")
    ensure(d, lambda doc: "params" not in doc, f"{name}: action = 'compose' は URL に項目を送らないので [params] を書かないでください")

1つ目は、投稿画面の URL が https:// で始まり、空白や引用符などの紛れ込みやすい文字を含まないことです。compose は URL をそのまま新しいタブで開くので、暗号化されていない http の URL や、壊れた URL を開かないようにしています。2つ目は、[params] が無いことです。compose は URL に何も付けないので、[params] があるなら、それは書き間違いか、動きの勘違いです。中身が空の [params] であっても止めます。「空だから害はない」と通すと、次に誰かがそこへ項目を書き足したとき、読まれない項目を送る失敗につながるからです。

止まるときのエラーの文は、日本語で、何をどう直せばよいかまで書いています。「compose は URL に項目を送らないので [params] を書かないでください」と出れば、書いた人はすぐに直せます。エラーは、止めるためだけでなく、次に何をすればよいかを伝えるためのものでもあります。

この2つの検査には、それぞれ試験も足しました。正しいカードが通ること、http の URL で止まること、空の [params] でも止まること、知らせの文言に既定値があって上書きもできること、を Python の試験で確かめています。こうした試験があるので、いつか検査のコードを直したときにも、止めるべきものを止めなくなっていないかが分かります。

4.2.0 では、下書きのひな形のための検査も足しました。draft と draft_format は、両方書くか、両方書かないか。差し込み口は5つだけで、知らない差し込み口や閉じていない波括弧は止める。draft を書けるのは open と compose だけで、open なら [params] で draft を送っていなければ止め、逆に draft を送るのにひな形が無くても止める。宣言したのに使われない下書きを、配布物に入れないための検査です。

ただ、止める場所を間違えると、止めること自体が害になります。4.2.2 では、その境目を1つ直しました。カードの書き間違いは、ここまで見たとおり、配布の前に生成器が止めます。一方、サイトのページに書く設定(共有欄の属性や config 属性)は、読者のブラウザで初めて読まれます。4.2.1 までは、そこに知らない名前(たとえば facebook を facebok と打ち間違えたもの)が1つ混ざっているだけで部品がエラーを出し、正しく書いた共有先まで含めて、共有欄がまるごと描かれませんでした。4.2.2 からは、知らない名前だけを列から外し、描くたびにブラウザのconsoleへ1回だけ知らせます。固定バーを出す位置(after)に数でない値が書かれたときや、ボタンの大きさ・形などの属性に決まりに無い値が書かれたときも、サイトの設定の値をそのまま使います。サイトの設定を作る生成器(tools/config.py)が知らない名前を拒むのは、これまでどおりです。

直せる人の前では止め、直せない読者の前では、壊れた1つだけを外す。配布の前なら、止まったエラーを読んで直す人がいます。けれど、読者のブラウザで止まっても、読者には直しようがありません。fail closed は、どこで止めるかまで決めて、はじめて役に立つのだと思います。

あなたのサイトで、共有先を足すなら

ここまでの話を、もし自分のサイトで同じことをするならどう進めるか、という手順にまとめておきます。Promari SNS Share を使っている場合の手順ですが、ほかの共有ボタンの仕組みでも、考え方はほとんど同じはずです。

共有先を1つ足すときの手順
順番すること確かめること
1サービスに公式の共有の入口があるか調べる入口の URL を実際に開き、ログインしていないときの動きも見る
2入口か、本文を受け取る投稿画面があれば open、無ければ compose を選ぶ入口が受け取る項目の名前(url・u など)
3destinations/ に TOML のカードを1枚足すファイル名と key が同じ。アイコンの出典を2行目に書く。カードになる書き方があれば draft に書く
4pnpm run build で配布物を作り直す生成器が止まらずに通るか
5pnpm run verify で全部の試験を通すTypeScript・Python・PHP の試験と、配布物が古くないか
6サイトの設定の destinations か secondary に名前を足す見える列に置くか、「その他」に入れるか
7スマホの幅で表示を確かめるボタンが増えても、横にはみ出さないか

この中で、プログラムを書く手順は1つもありません。compose という動きが一度できてしまえば、入口の無いサービスも、カードを1枚足すだけで並べられます。今回いちばん手間がかかったのは、動きを1つ増やすところで、それは一度きりの手間です。次に誰かが「はてなブログにも」「dev.to にも」と思ったときには、1と3のあたりで、ほとんど片付くはずです。

最後の7番目は、今回実際に踏んだ落とし穴から足した手順です。ボタンの数が変わると、それまで問題にならなかった並べ方の作りが、急に表に出てきます。数を変えたら、狭い画面で見る。これも、覚えておきたい習慣です。

並べ方の判断も書き残しておきます。書く場所の4つは見える列に、アメブロは「その他」に。そして、見える列が増えたぶん、狭い画面では折り返す。置く場所の判断と、置いたあとの見た目の直しは、セットで考える必要がありました。

考えてみる:主の列に9個も並べると、かえって選びにくくならない?

その心配はあります。ボタンが増えるほど、1つ1つは目に入りにくくなりますし、スマホでは2段になって場所も取ります。今回は、このブログの読者が「書く人」であることを重く見て、書く場所の4つを見える列に出しました。一方で、アメブロ・はてなブックマーク・LinkedIn・メールは「その他」に入れて、主の列が増えすぎないようにしています。どの共有先がどれくらい押されているかは、5ページ目で見るように、共有先ごとに数えられます。数か月たって、ほとんど押されないボタンがあれば、「その他」へ移すことも考えます。並べ方は、一度決めたら終わりではなく、数えながら直していくものだと思います。

COMMENTS
コメント…

このページ(4ページ目)の感想・質問・設計へのコメント

PASS IT ON

この気づきを、誰かにも。

この記事を書いた人

Takaomi Murasaki

Promari SNS Shareの開発を通して、Webの仕組みや設計の選び方を紹介しています。動く実装と、その判断に至るまでを記事に残しています。

公開記事 11 件

プロフィールを見る
THANK YOU FOR READING.すべての記事へ ↗

FROM INSIGHT TO IMPACT

「できたらいいな」を、
動く仕組みに。

記事で見つけたヒントを、あなたの事業へ。
新しいサービスも、手間のかかる業務も。
いまの課題から、つくるべきものを一緒に考えます。

開発・AI・研修の実績を見る

まだ、仕様書はいりません。

「何から始める?」から、ご一緒に。

課題がまとまっていなくても大丈夫。テーマを選ぶと相談文をご用意します。
連絡先の必須入力は、お名前とメールアドレスだけ。

まずは課題の整理から相談する

ご相談後の流れ

  1. 01 内容を確認
  2. 02 メールでご連絡
  3. 03 課題・進め方をご相談
送信だけで契約やお申込みが確定することはありません。