てくすた

ピクスタ株式会社のエンジニア・デザイナーがつづるよもやまテクニカルブログです

PIXTAにおけるモバイル対応

この記事は、PIXTA Advent Calendar 2017 14日目の記事です。

こんにちは、開発部で技術基盤を担当しているid:Yasaichiです。
乃木坂46で橋本奈々未さんの次に推していた伊藤万理華さんが年内で同グループを卒業することを発表*1し、悲しみのあまり思わず彼女の初の個展である「伊藤万理華の脳内博覧会」を観に京都まで遠征してしまいました。 「はじまりか、」最高かよ。

本エントリでは、先日行われたRails Developer Meetup 2017での私の発表内容と、時間の都合上割愛した事項について紹介したいと思います。なお、当日の発表資料はこちらになります。

以下、この資料の流れに沿って各トピックについて説明していきます。

モバイル対応の背景

PIXTAでは、全トラフィックのうちPCからのアクセスが約7割を占めているため、一部の機能を除いて基本的にはPC向けのページしかありませんでした。 しかし、昨年11月にGoogleがMobile-First Index(以下、MFI)の導入を発表したことでモバイル対応を決定し、現在対応を進めているところです。

webmaster-ja.googleblog.com

MFIの導入によって変わるのは、端的に言うと「評価対象」です。 今まではPC向けのページの内容を評価してPC・モバイル両方の検索順位が決まっていましたが、MFIの導入後はモバイル向けのページが評価され、PC・モバイルの検索順位が決まるようになります。 PIXTAのようにPC向けのページしか存在しない場合にも引き続き評価はされますが、類似サービスのモバイル向けページと比較した場合に検索順位が低下する可能性があります。

対応方針の選択

同一URLで*2モバイル対応を行う方法としては、一般的に「レスポンシブデザインを利用する」方法と「ユーザーエージェントによって表示内容を振り分ける」方法があります。 2つの方法にはそれぞれ次のようなメリット・デメリットがあります。

  • レスポンシブデザインを利用する場合
    • メリット: Viewがひとつで済むので運用が楽
    • デメリット: PIXTAのように既にPC向けのデザインがある場合に移行が大変
  • ユーザーエージェントによって表示内容を振り分ける場合
    • メリット: PIXTAのようにPC向けのページが既に存在する場合、モバイル向けのそれを作るだけで済む
    • デメリット: Viewが多重管理になるので将来的な運用が大変

PIXTAでは言語によって内容が大きく異なるページがあり、このようなページでは言語ごとにViewを作ることで対応しています。 ユーザーエージェントによって表示内容を振り分けようとするとViewの数がさらに2倍になってしまうことから、将来の運用コストを考えてレスポンシブデザインを採用しました。

段階的リリースを実現する実装

PIXTAはサービスの性質上ログインしていなくても利用できる機能が多いため、"検索エンジン向けの"モバイル対応にあたってレスポンシブ化すべきページが数多く存在します。 一度に全てのページを対応してリリースするのが理想ではありますが、テストフェーズの段階であるものの既にごく一部のサイトではMFIが導入されていると言われている*3こともあり、モバイル対応の効果の高いページから段階的にリリースしていく*4ことにしました。

しかしながら、ここでひとつの問題が発生します。モバイル端末でモバイル未対応ページを閲覧した際に、モバイル対応済みのheader等と表示が合致しなくなってしまうのです。

f:id:Yasaichi:20171210183038p:plain
前述の発表資料より抜粋

この問題にはいくつかの解決策が考えられると思いますが、PIXTAではモバイル対応済みのページにのみ動的にviewportを適用することで対処しました。 Ruby on Rails(以下、Rails)における実装例を前述の発表資料に記載していますので、詳細はそちらを参照してください。

当日発表できなかったこと: もうひとつの選択肢

先ほど、同一URLでモバイル対応を行う方法としては「レスポンシブデザインを利用する」方法と「ユーザーエージェントによって表示内容を振り分ける」方法があると述べました。 実は、対応方針を議論している過程で「MFIの導入に間に合わせることを最優先とするのなら、(モバイル向けのViewを作るだけで済むので)ユーザーエージェントによって表示内容を振り分ける方法の方が良いのではないか」という意見も出ていました。 そのため、私の方でこの方針を選択した場合の実装方法やその懸念点をあらかじめ調査していました。 当初、この調査結果についても発表で触れる予定でしたが、時間の都合上なくなく割愛することになったので、代わりに本エントリで紹介します。

Rails側での対応

ユーザーエージェントによって表示内容を振り分ける場合、Rails側ではActionPack Variantsを利用することで対応できます。これはデバイスごとに異なるViewを表示するためにRailsに用意された標準機能で、4.1系で導入されました。

weblog.rubyonrails.org

以前は同等の機能を実現するためにjpmobile等のgemを利用しなければいけませんでしたが、現在では(特に理由のない限り)ActionPack VariantsというRailsのレールに乗ることがベストな選択だといえるでしょう。

段階的リリースを実現する"gem"

ActionPack Variantsを利用する場合にも、段階的にリリースしようとすると前述した「ちぐはぐ問題」が発生してしまいます。 この問題を解決するために、Railsのテンプレート探索とページレンダリングの挙動を調査したところ*5、「アクションに対応するテンプレートが探索された後、その内容を評価する際にレイアウト等の探索が行われる」ことがわかりました。 これらの処理は、(Rails 5.1系では)このあたりに記述されています。

module ActionView
  class TemplateRenderer < AbstractRenderer #:nodoc:
    def render(context, options)
      @view    = context
      @details = extract_details(options)
      template = determine_template(options)

      prepend_formats(template.formats)

      @lookup_context.rendered_format ||= (template.formats.first || formats.first)

      render_template(template, options[:layout], options[:locals])
    end

    ...
  end
end

抜粋したコード内で呼び出されているrender_templateにいい感じのパッチを当てることで、request.variant:mobileのような値がセットされたものの該当のアクションにモバイル向けのテンプレートが存在しなかった場合に、レイアウト等をデフォルトのそれにフォールバックさせることができます。このパッチをgemify*6したものが私の作成したactionview-consistent_fallbackになります。

github.com

このgemを利用することで、ユーザーエージェントによって表示内容を振り分ける場合にも段階的リリースを実現することができます。 同じような問題に直面している方が(どの程度いるのか謎なところですがもし)いたら、ぜひご利用ください。

おわりに

来週のPIXTA Advent Calendar 2017では、実際に作業に携わっているエンジニア・デザイナーがモバイル対応に関するエントリを執筆する予定です。どうぞご期待ください。

*****

ピクスタでは、「ユーザーに価値を速く継続的に届けるために技術をどう使うか」というテーマに興味のあるエンジニアを募集しています!

recruit.pixta.co.jp

*1:橋本奈々未さんは今年の2月20日にさいたまスーパーアリーナで行われた卒業ライブをもって同グループを卒業、同時に芸能界を引退しています

*2:モバイル向けサイトを別ドメインで運用する方法もあるため、このような表現をしています

*3:Google Mobile First Index Is Live For Few Sites & Never Will Stop Rolling Out

*4:MFIはサイト単位ではなくページ単位で導入されるため、段階的にリリースしたページから順次切り替わっていくことになります

*5:こちらの調査にあたり、「Railsはどのようにテンプレートを見つけているか」がとても参考になりました

*6:当初はgemとして公開するつもりはなかったのですが、異なるバージョンのRailsで自分の書いたパッチが動作するか手作業で確認するのが面倒で自動テストを書きたかったのと、同様の問題を解決するgemが見つけられなかったこともあってこうしました