トランスビット
トランスビットの開発ノート Webサイト制作に役立つTipsやトラブルシューティングなどの備忘録 - jQuery -

jQueryのドロワープラグインSlidebarsが、Androidでちょっとした問題を起こしていた件について

仕事が終わってまったりしていたら、トランスビットの外の人に「これ原因突き止めといて。じゃ、出かけてくるから!」って投げられた宿題の話です。

AndroidのChromeでページを一気にスクロールさせていると、footerを表示するあたりで一セクション前の部分まで勝手にスクロールして戻ってしまうので、正常な状態に直す。

他のデバイスではなんともないので、cssかscriptだろうとあたりをつけて探っていくと、Slidebars(2系)でした。
スクロールするのみでドロワーメニューをタップしていないにもかかわらず、slidebars.jsが動いて何らかの処理をしてしまう……。
ということで、slidebars.jsを見ていくと、一番最後にありました!

//459行目(最後から2行目)をコメントアウト

//$( window ).on( 'resize', this.css.bind( this ) );

PCでウインドウ幅を狭めてスマホ版表示にした時、ドロワー表示用のボタンが出てくるようになっています。
このドロワー表示用のボタンをタップしてドロワーメニューを表示させたままウインドウ幅を広げ、PC版表示にした時、ドロワーメニュー用の領域をきれいになかったことにしてくれるのが、この一文です。
なので、この一文がないと、ドロワーメニューを表示させたままウインドウ幅を広げPC版表示にした時、ドロワーメニュー用の領域が白い帯として残ってしまいます。

そもそもトランスビットではスマホ版でしかドロワー使わないということもあるのですが、

  • PCでサイト閲覧してて
  • 320pxまでウインドウ幅狭めてスマホ表示にして
  • ドロワー出して
  • 更にそのままウインドウ幅広げてPC表示に戻したりする

そんな人はいないんじゃないか?

という性善説で、トランスビットでは459行目をコメントアウトして問題なしとなりました。
これで宿題クリアです。

Androidでスクロールすると、ウインドウ再描画してるみたいやなーって思うときがあったんですが、リサイズしてたんですね。
cssやscriptの読込順とかなんか色々関係してるんでしょうか……リサイズ……謎です。

Filed under: ,

jQueryのドロワープラグインSlidebarsとスムーススクロール

今やってる案件でiPhoneでの読込が異常に遅く、外の人から「重いから軽くして」と頼まれました。
原因はドロワーでした。script切るとサクサク…。
ちなみに、jQueryのドロワーといえば、これだと思っております。おすすめです。
Slidebars

バージョンが2に上がったことは去年の11月には既に知っていた(!)のですが、メニューとコンテンツのゾーン分けにcanvas使うようになっていて、既存のcssの書き換えやらなんやらに時間取られたら嫌やなーと、手を出しておりませんでした。(jQueryは1.12以降)
そして、canvasっていうと図形描写やんか、と思っていたので、正直戸惑いも強く。
html5ゲームとか作る以外にも使い道あったんやなぁ、と。

で、最初に入れていたバージョン1系を2系に換装したら、読込もサクサクになって喜んでいたんですが、今度はTOPに戻るボタンが動かない……。
どう考えてもSlidebarsが真っ黒なのでよーく見てみると、slidebars.min.cssのせいでした。

/* ---------------------------------------------
body,html{width:100%;height:100%;overflow:hidden}
が原因。
実はwidth:100%は無罪なんですが、なくても困らない。
--------------------------------------------- */
[canvas],[off-canvas*=push]{z-index:1}[off-canvas*=reveal],[off-canvas*=shift]{z-index:0}[canvas=container],[off-canvas],body,html{margin:0;padding:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}/*body,html{width:100%;height:100%;overflow:hidden}*/[canvas=container]{width:100%;height:100%;overflow-y:auto;position:relative;background-color:#fff;-webkit-overflow-scrolling:touch}[canvas=container]:after,[canvas=container]:before{clear:both;content:'';display:table}[off-canvas]{display:none;position:fixed;overflow:hidden;overflow-y:auto;background-color:#000;color:#fff;-webkit-overflow-scrolling:touch}[off-canvas*=top]{width:100%;height:255px;top:0}[off-canvas*=right]{width:255px;height:100%;top:0;right:0}[off-canvas*=bottom]{width:100%;height:255px;bottom:0}[off-canvas*=left]{width:255px;height:100%;top:0;left:0}[off-canvas*=overlay]{z-index:9999}[canvas],[off-canvas]{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0);-webkit-transition:-webkit-transform .3s;transition:transform .3s;-webkit-backface-visibility:hidden}[off-canvas*=shift][off-canvas*=top]{-webkit-transform:translate(0,50%);transform:translate(0,50%)}[off-canvas*=shift][off-canvas*=right]{-webkit-transform:translate(-50%,0);transform:translate(-50%,0)}[off-canvas*=shift][off-canvas*=bottom]{-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}[off-canvas*=shift][off-canvas*=left]{-webkit-transform:translate(50%,0);transform:translate(50%,0)}@media print{[canvas]{-webkit-transform:translate(0,0)!important;-ms-transform:translate(0,0)!important;transform:translate(0,0)!important}[off-canvas]{display:none!important}}

これで次回から安心。

Filed under:

アンカー付リンクから、スライドトグルさせる

もうちょっとタイトル分かりやすくならんかな、と思ったんですが諦めました。
Q&Aとかでよくある、質問行をクリックすると隠れていた回答ボックスが出てくるトグル関連の話です。
基本、cssは略してます。
↓こういう定義リストをトグルさせるのは簡単。

<dl class="qa">
  <dt>愛媛県の県庁所在地は?</dt>
  <dd>松山市</dd>
  <dt>愛媛県の県の花は?</dt>
  <dd>みかんの花</dd>
  <dt>愛媛県の県の木は?</dt>
  <dd>マツ</dd>
</dl>

<style type="text/css">
  dd{display:none;}
</style>
  $(function(){
    $(".qa dt").on("click", function() {
      $(this).next('dd').slideToggle();
    });
  });

もう一歩進んで、質問へのアンカー付きリンクでページを開いたと同時に、回答部分を表示させる方法。
スムーススクロールさせたいなら、return falseの前に処理を書けばOK。

<dl class="qa">
  <dt id="qa_where">愛媛県の県庁所在地は?</dt>
  <dd>松山市</dd>
  <dt id="qa_flower">愛媛県の県の花は?</dt>
  <dd>みかんの花</dd>
  <dt id="qa_tree">愛媛県の県の木は?</dt>
  <dd>マツ</dd>
</dl>

<style type="text/css">
  dd{display:none;}
</style>
  $(function(){
    // URLのハッシュを取得
    var urlHash = location.hash;
    if(urlHash){
      $(urlHash).next('dd').slideToggle();
      return false;
    }

    $(".qa dt").on("click", function() {
      $(this).next('dd').slideToggle();
    });
  });

ここからさらに進んで、質問部分をタブメニューっぽく横に並べて、スライドトグルするやつ。

<ul class="q">
  <li class="q_where">愛媛県の県庁所在地は?</li>
  <li class="q_flower">愛媛県の県の花は?</li>
  <li class="q_tree">愛媛県の県の木は?</li>
</ul>
<div class="a">
  <div id="qa_where"><p>松山市</p><p class="close">×</p></div>
  <div id="qa_flower"><p>みかんの花</p><p class="close">×</p></div>
  <div id="qa_tree"><p>マツ</p><p class="close">×</p></div>
</div>

<style type="text/css">
  .q li{
    float:left;
    width:200px;
    border:1px solid #ccc;
  }
  .a div{display:none;}
</style>
  $(function(){
    // アンカーリンクからスライドトグル。ついでにスムーススクロール  ---------
    // URLのハッシュを取得。
    var urlHash = location.hash;
    if(urlHash){
      $(urlHash).slideToggle();
      var href= urlHash;
      var target = $(href == "#" || href == "" ? 'html' : href);
      var position = target.offset().top;
      $('body,html').animate({scrollTop:position}, 1000, 'swing');
      return false;
    }

    $(".qa dt").on("click", function() {
      $(this).next('dd').slideToggle();
    });

    // 閉じるボタン  ----------------------------
    $(".close").on("click", function() {
      $(this).parent().slideToggle();
    });

    // メニューからスライドトグル  ---------------
    $(".q li").on("click", function() {
      // メニューのclassを取得し、余分をとる
      var q = $(this).attr("class").replace(/q_/g,'');

      // div総当たり
      $(".a div").each(function(i) {
        // divのidを取得し、余分をとる
        var qa = $(this).attr("id").replace(/qa_/g,'');
        // メニューとmatchしたらトグル
        if (qa .match(q)) {
            $(this).slideToggle();
        }else{
            $(this).hide();
        }
      });
    });
  });

別にタブでいいんじゃない?と思うでしょうが、色々理由があって画面稼ぎしないといけない、そんなニッチな仕様の時にどうぞww

Filed under:

iOSの、hover付いてると2回タップ必須なバグについて

こういうの↓があったとしたら…。

<style type="text/css">
.menu{
    width:200px;
    text-align:center;
    background:#f7f7f;
}
.menu::hover{
    background:#e5e5e5;
}
</style>

<ul class="menu">
    <li>
        説明や<img>とかいれつつ
        <a href="link.html">リンク</a>
    </li>
</ul>

理想:リンクを[タップ]する → hoverが適用され背景色が変わり、リンク先にとぶ
現実:リンクを[タップ]する → hoverが適用され背景色が変わる → もう一回リンクを[タップ]する → リンク先にとぶ

ってなることを言っています。
設定されているイベント的には「二つ」なんだから2回タップ、っていう理屈もわからんでもないです。
だたこれってiOS8系で発生してたバグで、iOS9ではちゃんと潰されています。

が、hoverにhoverを重ねてリンクさせるデザイン案件がありまして同様の問題が起こりました。
iOSは最新の9.3.1です。
Androidは平気なのになー……Safariはイベントに対する解釈がかなり違うのかな。

理想:リンクを[タップ]する → 隠れていたBOXがでてくる → BOX内のリンクを[タップ]する → hoverが適用され背景色が変わり、リンク先にとぶ
現実:リンクを[タップ]する → 隠れていたBOXがでてくる → BOX内のリンクを[タップ]する → hoverが適用され背景色が変わる → もう一回リンクを[タップ]する → リンク先にとぶ

どうにかしなくてはいけないと、どうにかしたのが下記scriptです。
htmlは省略。上記htmlのliに、ulネストしてリンクが入ってると思ってください。

//まずはユーザーエージェント確認
var _ua = (function(u){
  return {
    Tablet:(u.indexOf("windows") != -1 && u.indexOf("touch") != -1)
    || u.indexOf("ipad") != -1
    || (u.indexOf("android") != -1 && u.indexOf("mobile") == -1)
    || (u.indexOf("firefox") != -1 && u.indexOf("tablet") != -1)
    || u.indexOf("kindle") != -1
    || u.indexOf("silk") != -1
    || u.indexOf("playbook") != -1,
    Mobile:(u.indexOf("windows") != -1 && u.indexOf("phone") != -1)
    || u.indexOf("iphone") != -1
    || u.indexOf("ipod") != -1
    || (u.indexOf("android") != -1 && u.indexOf("mobile") != -1)
    || (u.indexOf("firefox") != -1 && u.indexOf("mobile") != -1)
    || u.indexOf("blackberry") != -1
  }
})(window.navigator.userAgent.toLowerCase());

//PC以外なら
if(_ua.Tablet || _ua.Mobile){ 
        $(".menu li li").on('mouseover',function(){
          window.location=$(this).find("a").attr("href");
        });
}

最初は厳密にtouchイベントを書いてみようとしてたんですが、試しに入れてみたmouseoverが鍵でした。※tapではアウト。
hoverも適用されるし、ページ読み込み中のプログレスバーもきちんと見える。
一先ず解決です。

Filed under:

iPhone5、6、6+を判別した上でviewportを最適化

こんにちは。一ヶ月ほど前にiPhone6無印を支給されたトランスビットの中の人です。

外)「これで、い つ で も 実機で確認できるから」
中)「……そうですネ(外堀埋められた気分)」

さて、レスポンシブで組むのに慣れてきたと思っていても、色々な問題に出くわします。
その度にちぎっては投げ、ちぎっては投げ……今回はiPhoneのviewport絡みです。

基本的にトランスビットの外の人は幅320pxでスマホ用縦デザインをあげてきます。
いつももっと大きいけど、仮にPC用デザインは幅1024pxとし、画面サイズ480px(スマホ横)からはPC用デザインで表示するとしましょう。
iPhone5以下、6、6+でそれぞれ画面幅が違うので、各デバイスで同一表示になるよう調整します。
※Androidぶったぎりコード

jQuery(function($){

/* ==============================================================================
   0. ユーザーエージェントタブレット・スマホの二極で取得
 ================================================================================ */
var _ua = (function(u){
  return {
    Tablet:(u.indexOf("windows") != -1 && u.indexOf("touch") != -1)
    || u.indexOf("ipad") != -1
    || (u.indexOf("android") != -1 && u.indexOf("mobile") == -1)
    || (u.indexOf("firefox") != -1 && u.indexOf("tablet") != -1)
    || u.indexOf("kindle") != -1
    || u.indexOf("silk") != -1
    || u.indexOf("playbook") != -1,
    Mobile:(u.indexOf("windows") != -1 && u.indexOf("phone") != -1)
    || u.indexOf("iphone") != -1
    || u.indexOf("ipod") != -1
    || (u.indexOf("android") != -1 && u.indexOf("mobile") != -1)
    || (u.indexOf("firefox") != -1 && u.indexOf("mobile") != -1)
    || u.indexOf("blackberry") != -1
  }
})(window.navigator.userAgent.toLowerCase());

/* ==============================================================================
   1. まずはviewportの変数を設定
 ================================================================================ */
if(navigator.userAgent.indexOf('iPhone') > 0){
  // iPhoneの場合
  if(window.devicePixelRatio == 3) {
      // iPhone6+
      var vpSp = 'width=320px,initial-scale=1.293750,maximum-scale=1.293750,user-scalable=0';
    }else if(window.devicePixelRatio <= 2){
      // iPhone6以下なら
      var height_num = screen.height * window.devicePixelRatio;
      if( height_num > 1136){
        // iPhone6
        var vpSp = 'width=320px,initial-scale=1.171875,maximum-scale=1.171875,user-scalable=0';
      }else{
        // iPhone5+以下
        var vpSp = 'width=320px,initial-scale=1,maximum-scale=1,user-scalable=0';
      }
    }
  }else{
    // iPhoneに非ず
    var vpSp = 'width=320px,initial-scale=1, maximum-scale=1, user-scalable=0';
}

/* ==============================================================================
   2. 次に、viewportの設定
 ================================================================================ */
 var vpPc = 'width=1024px';
  if(_ua.Mobile){ // スマホ用viewportの設定
    // 初期設定
    $('head').prepend('<meta name="viewport" content="' + vpSp + '">');

    $(window).on("orientationchange", function() {
        // 傾き検出
        if(Math.abs(window.orientation) === 90) {
          // 横向き
          $('meta[name=viewport]').remove();
          $('head').prepend('<meta name="viewport" content="' + vpPc + '">');
        } else {
          // 縦向き
          $('meta[name=viewport]').remove();
          $('head').prepend('<meta name="viewport" content="' + vpSp + '">');
        }
      });

  }else{ // PC用viewportの設定
    // 初期設定
    $('head').prepend('<meta name="viewport" content="' + vpPc+ '">');
  }

/* ==============================================================================
   3. 最後に、ウインドウリサイズ時のviewportの設定
 ================================================================================ */
  $(window).on("resize", function() {
    if( window.matchMedia("(max-width: 479px)").matches ){
      $('meta[name=viewport]').remove();
      $('head').prepend('<meta name="viewport" content="' + vpSp + '">');
    }
    if( window.matchMedia("(min-width: 480px)").matches ){
      $('meta[name=viewport]').remove();
      $('head').prepend('<meta name="viewport" content="' + vpPc + '">');
    }
  });
});

色んな方が書いてくださったscriptを、適当に繋ぎ合わせて動かしてるんですが……。

↓↓ いつも一方的に勝手にお世話になっていて、今回もお世話になった方々のブログ記事 ↓↓
2015年版JavaScriptユーザエージェント判別・判定
JavaScript(jQuery)とCSSでiPhone6 Plusを判別するいろいろ
iPhone 5S 以前だけでなく、iPhone 6 や iPhone 6 Plus でも幅320pxでスケールを固定する方法

みんなこういうのどうしてるんだろう……もしかして、もっとスマートな方法があるんだろうか。
ハナからリキッドデザインなんだろうか……。
ちなみに、私はこのコードの中にハンバーガーメニュー用のスライドトグルを初めとし、「スマホデザインで使う関数や色々」とか、「PC用で使う諸々」とかも、2のとこで一緒にぶち込み、ごった煮にしてます。

今更ながら、$(‘meta[name=viewport]’).remove();から$(‘head’).prepend~の下りを、attrで処理した方が数行稼げる気もするのですが、明日にしてもう寝ます。
ちなみに…。

$(window).on("load orientationchange resize", function() {}

こんな風に、ロードもリロードも傾き変化も、全部くくってしまうと設定がまとまって見やすいです。
何故か、後々別々にわけて動かす必要性が出てくるんですけどね……私だけ?

Filed under: , ,