norinyang メガ進化!

気ままに色々

サイト埋め込みコードをつくるには?

サイト埋め込みコードを作るにはどうしたらいいのかを最近真剣に考えてた

Youtubeだとこういうの

<iframe width="560" height="315" src="//www.youtube.com/embed/WIKqgE4BwAY" frameborder="0" allowfullscreen></iframe>

実際に埋め込むとこうなる

Twitterだとこういうの

<blockquote class="twitter-tweet" lang="ja"><p>「アナと雪の女王」主題歌の百花繚乱カバー合戦で日本人が完敗すぎる件 | 熊坂仁美 | note (54 users) <a href="http://t.co/kkaZmuaqHe">http://t.co/kkaZmuaqHe</a></p>&mdash; はてなブックマーク::Hotentry (@hatebu) <a href="https://twitter.com/hatebu/statuses/457530582189080577">2014, 4月 19</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

実際に埋め込むとこうなる

ほかのサイトでも色々あるけどとりあえずこの2つをみるとYoutubeはiframeを直接書いているけどTwitterの場合はblockquoteを一緒に読み込んだwidget.jsでiframeに置き換えるっていうことをしている

どっちがいいんですかね?

とりあえず、どっちがいいのかって話はサイトの特性によると思うんだけどYoutubeとかだと動画の高さや幅が基本的に固定でよいのでjavascriptで何かを頑張る必要があんまりない
一方でTwitterの場合コンテンツの高さが投稿毎に違ったりする、特にメディアが引っ付いていたりすると高さを推定しづらいし、ある程度レスポンシブルで動的に横幅かわるとかっこ良かったりするので、固定にするのは無理があるけどかといって上の方しか見えないとか、スクロールバーでるとかかっこわるい
その辺り解決するためにjavascriptを利用しているようである
さらにTwitterのよいところはblockquote内にコンテンツ事態の内容が書かれているので、埋め込み先のサイトがRSSとかに対応していたときとかにリーダーで読むことができるので幸せな気持ちになれますね
このblockquoteをiframeに置き換えているのも当然javascriptでやっている

Youtubeの方法だと掘り下げるものがあんまりないのでTwitterみたいなアプローチでするならどうしたらいいか考えてみる

気をつけるべきこと

  • 埋め込み先のサイトで読み込まれるjsはプレーンでかくべき
    • 埋め込み先サイトでどんなライブラリが使われているかわからないので、ライブラリを読み込むことによって事故が起きる可能性がある
  • 埋め込み先のサイトで読み込まれるjsが埋め込み先のサイトに影響を与えないようにする
    • 名前空間が必ずユニークになって衝突したりしないようにする
  • 複数回jsが読み込まれても問題ないようにする
    • ユーザはわざわざスクリプトタグが1つになるように書き換えたりしないので複数回読み込まれることを想定する
  • 1回しかjsが読み込まれなくても問題ないようにする
    • これは理想的にはやった方がいいけど、どっちでもいい気がする
    • リテラシーの高いユーザが消す可能性を考慮する
  • pjaxに対応しているサイトに埋め込まれても問題ないようにする
  • オートページャーで読み込まれるサイトでも問題ないようにする
  • 自信以外のサイトの埋め込み投稿がされている可能性がある
  • 同じコンテンツが複数張られる可能性がある
    • IDをつける場合にコンテンツが同じでもユニークなるようにする
  • jsが動かない環境を想定する
    • blockquoteをiframeに置き換える方法ならコンテンツの内容を入れておく、リンクをつけておくなどしておくとよい
  • コードが埋め込まれる場所に影響をされないコードにする
    • 例えば、bodyの直下にあるとか、blockquoteの中で一番下にあるとか、そういう事を決めつけたコードにしない

こんなもん?気をつけたらよい気がしますね

iframeでレスポンシブル

iframeでレスポンシブルに対応するにはどうしたらよいのか?
というのを考えたときに色々問題あるんだけど、とりあえず幅が動的にかわるにはどうしたらいいかは簡単でwidthとmin-widthとmax-widthをiframeに指定してあげればいい

width 基本的なサイズで、これ以上大きくしたくないサイズを指定
min-width 一番小さいサイズでこれ以上小さくなってほしくないサイズを指定
max-width 画面に対して最大でどういう大きさまで許容できるか%で指定する

問題は高さをどうするかである
iframeの中からiframeの高さを変更するもしくは外からコンテンツの高さを取得する必要がある
当然クロスサイトドメイン制約があるので
iframeで読み込むページの高さを取得して、heigthに代入する方法 - Eiji
こういう方法は使えない
なので、PostMessageを使用するのが一般的?なきがする
postMessageとiframeでクロスドメインメッセージを送受信してみる | Zafiel
この方法でiframeの内部のコンテンツでresize時とload時に外側にメッセージ送ってそれにあわせてiframeのサイズ変えればレスポンシブルに高さかわって幸せな気持ちになれる

これでよいんだけどPostMessageに対応していないブラウザでみたときにレスポンシブルにならない

PostMessageに対応していない場合のiframeレスポンシブル

俺たちのIE7以前とか対応してなかったりする訳ですね!
正直シェアとか考えるとそこまでしなくていい感じしかしないけどどうやらTwitterはそこを解決しているようである
PostMessageが使えないので
iframeで読み込むページの高さを取得して、heigthに代入する方法 - Eiji
コンテンツの高さを取得するにはこっちの方法でとるしかなくなる
ということは、クロスサイトドメイン制約をどうにかして回避すればよい!

ではどのようにiframeでクロスサイトドメイン制約を回避するのかといえば
iframeの中のコンテンツをsrcで読み込むのではなく、jsで直接差し込んでやればよい
src のない iframe を動的生成した際の location の謎 - Please Sleep
こんな感じ
上のサイトで説明されていますが、locationの値が親と子で同じになるらしい
つまりクロスサイトじゃなくなる!!!
こうすることで、window.parent.documentとかとれちゃうようになるみたいですね

これで高さをかえるようにするとPostMessageに対応していないブラウザでもうまく動くようになる!!はず。。。
(軽く実験した程度ぐらいで、実際にはこの手段を使わなかったので行う場合はシッカリ検証してください

肝心のコンテンツはじゃぁどうやって取得するのかといえば、jsonpで頑張ってとる
って感じですかね
Twitterjsonpでやってるみたい

まとめ

ぶっちゃけ、PostMessageでレスポンシブル対応ぐらいまでやったらいい気がする
それ以上やるのはつらい気持ちにしかならなさそう

Twitterのコード読む努力はしたけど、minifyされてるので大変読みにくいしsとかaとかに変数名とか関数名がなってるので間違ってる部分が多々ありそう
あと、推測してる部分もかなりある