スマホで固定メニューはそのままにコンテンツをピンチインできるようにする(メモ:未完)

悩み
悩み

バッドノウハウかもシリーズ、といいますかそもそも未完成な状態です。

いくつか試したりしたなかで一番望みがあるレベルまでこれたかなという反面、そこから先が上手くいかず…。

今後何かの折りに解決できるかもしれないので、個人的メモとして。

実現したいこと

実現したいことは以下の通り。

  • スマホでヘッダー固定メニューを設置
  • ユーザーがコンテンツ部分をピンチインで拡大可能にする
  • 固定メニューが拡大されず、かつ、固定されたままにする

スマホで固定メニューは割と見かけますが、設定しただけではピンチインによる拡大に対応できません。

調査してみるとその殆どが「name=”viewport” content=”user-scalable=no”」を指定して、そもそも拡大自体を回避しています。

可能なら、固定した要素はそのままに、コンテンツ(と言いますか固定した要素以外)を拡大可能にしたいと考え対応策を探していました。

結果、実現可能そうな情報を発見し、それに少し手をいれた時点で頓挫という状態です。
以降は、この頓挫した状態の説明です。頓挫している時点でほぼ意味はないので、ご希望に沿う内容でない場合は離脱をおすすめします。

残念ながら、ここに答えはありません…。

現実的な対応策

[追記 2017.2.14]

スマホでの固定ナビに対応する方法として、この記事で目指したこととは別の方法を考えました。詳細は以下の記事をご覧下さい。

頓挫した方法

妙な書出しですが「実現した方法」とはかけませんのでご勘弁を。

まず、今回実現したかった事柄は下記のページの情報で可能なはずでした。

こちらで解決されているのですからできるはずなのですが、できませんでした。
一応少々気になる部分を手直ししつつ粘りましたが断念。

そこで、上記ページで回答されているコードの方を試したところ、うまくいきそうな気配。
ただ、適用したいサイトで使うといろいろおかしくなってしまう(absoluteで配置している要素だけが過剰に拡大するなど)ので、jQueryを併用(使わなくてもいいのですが)してtransformのscaleを使うことに。

ついでに、縮小し過ぎると見えないレベルになって困るので、scaleが1以下にならないように少し手をいれて以下のようにしました。


<div id="header-fixed-menu">
<ul>
<li>ラベル1</li>
<li>ラベル2</li>
<li>ラベル3</li>
</ul>
</div>
<div id="contents">
<p>本文もろもろ</p>
</div>

<script type="text/javascript">
jQuery(function($){
  var pinching = false;
  var d0 = 1;
  var d1 = 1;
  document.addEventListener("touchmove", function(e){
    if (e.touches.length == 2) {
      if (!pinching) {
        pinching = true;
        d0 = Math.sqrt(
          Math.pow(e.touches[1].screenX - e.touches[0].screenX, 2) +
          Math.pow(e.touches[1].screenY - e.touches[0].screenY, 2)
        );
      } else {
        d1 = Math.sqrt(
          Math.pow(e.touches[1].screenX - e.touches[0].screenX, 2) +
          Math.pow(e.touches[1].screenY - e.touches[0].screenY, 2)
        );
        var zoomer = d1 / d0;
        if(zoomer >= 1){
          $("#contents").css({'transform':'scale('+ zoomer +')','-webkit-transform':'scale('+ zoomer +')','-moz-transform':'scale('+ zoomer +')','-ms-transform':'scale('+ zoomer +')'});
        } else {
          $("#contents").css({'transform':'scale(1)','-webkit-transform':'scale(1)'});
        }
      }
    }
  });
  document.addEventListener("touchend", function(e){
    pinching = false;
  });
});
</script>

これで、一応らしくはみえるようになるはずです。
参考にした方のコードでは、ピンチ前後の指と指の間の間隔を取得して比率にしており、なるほどと思いました。この値があれば、要素を意図した拡大率に合わせて動作させることが可能です。

問題

解決できなかった問題は以下の通りです。確認できていないものがもっとあるかもしれません。

  • 拡大すると左端が切れる
  • 少しでもピンチアウトすると原寸に戻る
  • ダブルタップが使えない
  • Android(4.2で確認)では、拡大時にダブルタップによる拡大縮小が動作し、固定した要素の幅が狂う
  • 動作がもっさり

組み込んだサイト自体の構造にも原因がありそうですが、そうでない部分の解決の見通しがつかないため断念しました。

ピンチによる拡大縮小率を算出

なお、本来考えていた「 name=”viewport” content=”user-scalable=no”」を設定しない場合に使えそうな、ピンチによる拡大縮小率を算出する方法が以下のページでわかりました。

この拡大率を逆転して縮小率として用い、固定したい要素のtransformなりzoomなりに代入して、ピンチの拡大に対して「拡大していないように見える」大きさに変化させる。
その上で、見た目の上部(見えている範囲の最上部)に固定するために上左右の値を取得して設定。

のような形を考えていました。うまくいかずでしたが。

結び

以前、海外のサイトで実現していたのを見た覚えがあり、某かの方法があるはずなのですが…。
記憶を頼りに探し当てたそのサイトは、残念ながらリニューアルされており現在は「 name=”viewport” content=”user-scalable=no”」を設定して単に拡大禁止にした状態でした。

今後は英語圏の情報を漁ってみたいと思います。

8人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄