トランスビットの開発ノート

Webサイト制作に役立つTipsやトラブルシューティングなどの備忘録

- tips -

iPhoneのSafariで、fixedしてある要素のonClick領域がズレる件

毎回タイトル長いな…。
でも、私にとって大切なことなのでもう一度。

どんな現象か

  1. それはAndroidではなく、iPhoneのSafariで起こる。
  2. 対象は、fixedで固定してある要素で、クリックなどでイベントが発火する物である。(例えばヘッダのハンバーガーメニューとか、フッタ付近の何かのメニューとか)
  3. 最下部までスクロールしてあり、下からタブバー(メニューバー?)がひょこっと出てきた・もしくは出てくる直前の状態が鬼門。
  4. タブバー出現に備えて?画面領域が再計算され、クリックできるはずの領域がタブバーの高さ分だけ上部にズレてしまう不思議。
  5. よって、フッター付近の固定要素ならタップすべきはその直前の亜空間となり、ヘッダーなどで最上部に固定してある場合は、タップすべき場所は画面外となる。

スマホのメニューってドロワーかトグルで大抵右上固定なんで、メニュー押せないとか普通に困ります。
ささっとcssとかソースとか見たんですが、これといった問題も見つけれなかったので、急場凌ぎでscriptとかも書いてみました。
フッターにpadding-bottomを60pxくらいあてといて、scriptでスクロール量を取って、copyright表示部分まで来たら、下部から60px分スクロールとかするように。
が、今度はタイミングによってはバウンスが起こるので、scriptが走って走って、画面がブレブレにw
バウンスをどうこうするよりも、scriptを改修するよりも、大元を突き止めたほうが幸せになれるので、がんばって原因を探ることにしました。

犯人はviewport!

私の書くcssがそんなに悪いのか!?と思って、色々いろいろ試してみました。
よく見る transform: translate3d(0,0,0); とか、divで囲ってうんたらかんたらとかも試しましたが駄目でした。
ただ、同じようなことしてあっても、そんな現象起きてないサイトもたくさんあるわけです。何かが決定的に違うわけです。

で、まさかと思って変更してみたviewportがビンゴでした。

ダメなviewportの書き方

<meta name="viewport" content="width=320">
<meta name="viewport" content="width=320, initial-scale=1">
<!-- どっちもダメ -->

大丈夫なviewportの書き方

<meta name="viewport" content="width=device-width, initial-scale=1">

要は、すべて端末に委ねなさい、っていうことですね。
外の人と話し合って、今後のレスポンシブのデザイン規定を変更することにしました。
まさに紆余曲折五里霧中状態でしたが、これでほっと一安心です。

ちなみに、↓が本家本元Appleのviewport指定です。

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">

Appleと一緒なら怖くないので、今後はこれを採用ですね。
ちなみに、 viewport-fit=cover” は、iPhoneXの両端の白いバーを表示しないようにする設定です。
全世界で絶大なる不評を得たダサいあの領域が、存在を主張するわけですね。
だからいっそのこと消してしまえと。わかります。

……って、あれ?あれれれれ??
Apple…おまえさん……。

Filed under:

IE10とIE11で、背景画像とグラデーションを重ね付け

久しぶりにIEです。
backgroundにまとめて書くと、IE10と11では背景画像もグラデもでません。
edgeなら問題ないんですけどねぇ。

  /* 何も出てこない */
    background: url("背景画像") center top no-repeat,-webkit-linear-gradient(top, #色, #色々 ),linear-gradient(to bottom,#色, #色々);

なので、面倒ですが、下のように書かないといけません。
この時、背景画像を先に記述することが大切です。

  /* 面倒でも分ける */
    background-color: #背景色;
    background-image: url("背景画像"), -webkit-linear-gradient(top,#色, #色々);
    background-image: url("背景画像"),linear-gradient(to bottom,#色, #色々);
    background-position: center top;
    background-repeat: no-repeat;

いつまで上のようなことしないといけないのかなーと気になったのでちょっと調べてみました。
引用中の表が2016年1月時点でのWindowsのIEサポート状況です。

マイナビニュース:IE10、IE9、IE8のサポート終了

2016年1月のアップデートの段階で、次のオペレーティングシステムおよびInternet Explorerがサポートされている。

オペレーティングシステム 2016年1月のアップデートでサポートされているIE
Windows Vista SP2 Internet Explorer 9
Windows Server 2008 SP2 Internet Explorer 9
Windows 7 SP1 Internet Explorer 11
Windows Server 2008 R2 SP1 Internet Explorer 11
Windows Server 2012 Internet Explorer 10
Windows 8.1 Internet Explorer 11
Windows Server 2012 R2 Internet Explorer 11
Windows 10 Internet Explorer 11
Windows Server 2016 Preview Internet Explorer 11

Microsoftはこれまでのように1つのOSで複数のバージョンのInternet Explorerをサポートするというポリシーから、それぞれのWindowsで最新版のInternet Explorerのみをサポートするように方針を変更。サポートが終了したInternet Explorerを使い続けると、攻撃を受けるなどセキュリティ上の問題が懸念されるため、サポートが提供されている最新版へアップデートするか、またはセキュリティサポートが提供されている他のWebブラウザへ移行することが推奨される。

『それぞれのWindowsで最新版のInternet Explorerのみをサポート』っていうことですので、WindowsのIEサポート状況と、OSのサポート状況をあわせて表にしてみました。

オペレーティングシステム 2016年1月のアップデートで
サポートされているIE
メインストリーム
サポート終了
延長サポート終了
Windows Vista SP2 Internet Explorer 9 2012/04/10 2017/04/11
Windows Server 2008 SP2 Internet Explorer 9 2015/01/13 2020/01/14
Windows 7 SP1 Internet Explorer 11 2015/01/13 2020/01/14
Windows Server 2008 R2 SP1 Internet Explorer 11 2015/01/13 2020/01/14
Windows Server 2012 Internet Explorer 10 2018/01/09 2023/01/10
Windows 8.1 Internet Explorer 11 2018/01/09 2023/01/10
Windows Server 2012 R2 Internet Explorer 11 2018/01/09 2023/01/10
Windows 10 Internet Explorer 11 2020/10/13 2025/10/14
Windows Server 2016 Preview Internet Explorer 11 2022/01/11 2027/01/11

Vistaはあと一か月足らずで延長サポート切れます。さよならVista。
サーバOSをどう考えるかによりますが、クライアントOSでの閲覧者が大半を占めるはずですので、基本的にIE11以降対応で組んだので問題なさそうですね。

それにしても、IE11は息が長そうや……!

Filed under: , ,

作ったはずのピンがGoogleMapに表示されない件

通常トランスビットでGoogleMapを設置する際には、アナリティクスが使えることもあって、お客様専用Googleアカウントをとった後、APIキー使って設置することが多いです。
今回も、そのAPIキーで設置してるものについてのことです。

scriptでピン(マーカー)をきちんと設定したはずなのに、なぜか表示されない。
オリジナルの画像を使ったわけでもないし、設定はあっているからデフォのピンは読み込まれているはず……cssがコンフリクトしているに違いない!

で、探したらやっぱりコンフリクトしている所がありました。見つかってよかった(=_=;

レスポンシブなサイトの場合、AndroidのデフォルトブラウザとAndroidのchrome、要するにAndroidのために、コンテンツ幅が勝手に縮小されたりフォントサイズが勝手に大きくなったりする現象を抑えるためのcssを書いています。
↓うちではこんな感じ。

p,dt,dd,li,div{
background-image: url('../img/android_bug.png'); // 透過pngで幅対策
max-height: 100%; // フォントサイズ対策
}

この、divについたフォントサイズ対策のmax-heightが犯人でした。
なので、↓のようにmax-heightをなくしてやります。※GoogleMap用のidは適当。

#googlemap{
max-height: none;
}

これで無事、いつもの赤いマーカーが表示されました。
やれやれだぜ。

Filed under: ,

見出しタグと同じテキストをtitleタグに設定

ちょっとだけ題名を変えて、前回結論が出たやつを書いてみました。
やりたいことは↓です。

  1. headerやfooterはincludeして使いまわすため、header内のtitleタグを各ページに合わせて変化させたい。
  2. urlに対応するページタイトルを設定しておき、titleタグに書き加える。
function get_pagetitle(){

// 現在のurlを取得
$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$domain = 'http://●●●●●/';
$pagetitle; // 入れ物

// 配列に、urlとページタイトルを入れておく
$pages = array (
  array ( 'href' => $domain.'cat.php', 'text' => '猫派' ),
  array ( 'href' => $domain.'dog.php', 'text' => '犬派' ),
  array ( 'href' => $domain.'bird.php', 'text' => '鳥派' )
);

// 配列の中で、現在のurlと対応するものを判別、その後、textを取得。
foreach($pages as $page){
  if($page['href'] == $url){
    $pagetitle = $page['text'];
  }
}
return $pagetitle;
}

これで、ページタイトルをゲットできるようになりました。
せっかくの配列なので、引数を設定したらfooter用のナビゲーションを書き出せるようにしてもいいかもです。

Filed under: , ,

見出しタグ内のテキストをtitleタグに設定

やりたいことは至って単純なんです。

  1. headerやfooterはincludeして使いまわすため、header内のtitleタグを各ページに合わせて変化させたい。
  2. 各ページには、見出しタグh2でページタイトルがついている。
  3. だから、それを取ってきてtitleタグに自動で書き加えたら楽な気がする!

jQueryなら簡単なんですが、titleをDOMで出すのは流石に良心が痛むので(SEO的に)、phpでやることにしてググってみました。

↓↓ 辿り着いたありがたいサイトを参考にしてみました。
PHPでWEBページのタイトルを抜き出すサンプル

function get_pagetitle(){
$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; //当該ページ
$html = file_get_contents($url); //HTML取得
// ↓マルチバイトencode。今回はもとからutf-8なので不要。
// $html = mb_convert_encoding($html, mb_internal_encoding(), "auto" ); 
if ( preg_match( "/<h2 class=\"page_title\">(.*?)<\/h2>/i", $html, $matches) ) {
    $pagetitle = $matches[1]; //h2を丸ごと取得
} else {
    return false;
}

return strip_tags($pagetitle); //タグを除いて、中身だけ返す
}

できたー!
できた……が、file_get_contentsを使わずに、現在のページを舐めることはできないの!?
そして、わかっていたけどpreg_matchの重さは異常!!
たった一つのタグを探し出すための仕掛けなのに……(TT

結論:ファイル名とタイトルの連想配列を作っといて、foreachするのが一番良いと思います。

Filed under: , ,

JSON形式のデータを用意してPHPで配列処理

すっかり春めいてまいりました。我が家の庭では、去年植えた枝垂れ桃が無事開花。
今日、郵便受けに入ってたフリーペーパーの星占い(よく当たる気がする)では、私の運勢も開花していました。

『学問の世界に誘われ、語学習得すると吉』

ええ、ちょうどJSONとPHPにイザナわれるところでしたから……orz

ということで、いつもメールフォームで郵便番号から住所入力したりするのにお世話になっているJSON。
↓food.json。こんな感じの構造です。

[
  {"food":"肉","name":"牛","kana":"ウシ","like":"2"},
  {"food":"肉","name":"鳥","kana":"トリ","like":"5"},
  {"food":"乳製品","name":"チーズ","kana":"チーズ","like":"5"},
  {"food":"乳製品","name":"ヨーグルト","kana":"ヨーグルト","like":"4"},
  {"food":"野菜","name":"ほうれん草","kana":"ホウレンソウ","like":"3"}
]

今回はデータがExcelで用意されていたので、ソートを済ませてからマクロ使ってJSONに落としました。
上記の例だと、第一キーがfoodで、第二キーがkanaですね。
私はstabuckyさんのマクロを使わせてもらいましたが、ググッたら結構出てくるのでお好きなのを。
ExcelのテーブルをJSON形式に変換するマクロ | You Look Too Cool

出来上がったJSONがUTF-8無印で保存されているか確認してサーバにアップします。
ちなみに私はBOM付いててハマりました。元がExcelなんだから当然チェックすべきポイントですな……反省。

次はPHPでJSONを配列として扱うために、json_decode()を使います。

$url = "json/food.json";
$json = file_get_contents($url);
$food = json_decode($json,true);

echo var_dump($food); //NULLならBOM付いてるかも

ちゃんとdumpできてたら、あとはお好きなように~です!

Filed under: ,

Google Fontsで代替フォント3選

あっという間に季節が過ぎてもうすぐ椿さんですね。
「……長い間ブログさぼってるやろ」って先日突っ込まれたトランスビットの中の人です。
無論、気づかれていないなどとは思ってもいませんよ……ええ。

さて、スマホの普及率が高くなったので、どこのサイトでもwebフォントが最早デフォルトのように使われていますね。
トランスビットでは、Windowsでも、Macでも、スマホでも表示できるということで、ポイントとなるような欧文のフォントには、Google Fontsが便利でよく使ってます。
Androidをぶったぎったら、システムフォントのみで済ますことができるんですけど、そういうわけにもいきませんしね。

Google Fontsで使える代替フォントの記事は、ググれば色々でてきます。
ただ、大抵ベーシックな物だけを求めている私には、情報過多。
ということで…

「アレ」と似ているGoogle Fontsの覚書:トランスビットバージョン

ゴシック

ド定番。安定のHelvetica、Arial、Gill Sans →  Open Sans または Lato

セリフ系

電話番号にも最適。みんな大好きTimes New Roman → Lusitana

その他

一気に溢れる品の良さ。碑文体のOptima → Cinzel

ゴシックの場合、Open SansよりLatoの方がすっきりしてて好みです。
両方とも選べるくらいウエイトがあるので、Arial Blackの代わりにも。
数字だけOpen Sanを使ったりもするんですが、そんな時は下記のようにパラメータを与えてサブセット化すると、軽量になって素敵。

<link href='https://fonts.googleapis.com/css?family=Open+Sans&text=089623-' rel='stylesheet' type='text/css'>

セリフ系は書体数が結構あるんですが、Lusitanaは字面から字詰めまでTimes New Romanに酷似しています。
Cinzelは……ほんと、よくぞ無料で提供してくださいましたっ!(TT)

今後も代替フォントを見つけたら、書き留めていきたいと思います。
——
追記(2016/07/06)

セリフ系の電話番号

A-OTFリュウミン → Vidaloka

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: , ,

正規表現を制す

もう夏かな、毎日暑いわー。よーし、今日ははりきって布団洗っちゃうぞー……なんて、羽毛布団を丸洗いした翌6月3日が梅雨入りだったトランスビットの中の人です。
運良く4日は早朝からカンカンに晴れ渡ったので、羽毛布団は無事ふっかふかに乾きました。

世の中結果が全てですね……本当に((((;゚Д゚))))ガクガクブルブル

勿論、過程も大切だと思います。
結果に至るまでの過程で、不安になったり躓いたりが少ないに越したことはありません。
羽毛布団と絡めて何が言いたいかというと、まずは正規表現をきちんと勉強しようってことです……orz

そうして辿り着いたのはここらへん。
偉い方々のお陰で、今まであやふやだった知識が定着しそうです。

■サルにもわかる正規表現入門
http://www.mnet.ne.jp/~nakama/

■正規表現サンプル集
http://hodade.adam.ne.jp/seiki/

■正規表現マスター ~文字列の魔術師へ・・・
http://seikihyougenn.com/

■PHP正規表現チェッカー
http://www.rider-n.sakura.ne.jp/regexp/regexp.php

各種ソフトのショートカットキーと一緒で、こういうのって体で覚える方が早いからツールの存在はありがたいですね。

ただ、正規表現サンプル集さんのとこで、\w使ってるのに一緒にアンダースコアも指定してあったりするのは、何か特別な意味があるのか、はたまた単なるうっかりなのか……個人的にはうっかりしてて欲しいw

ちなみにメアドなんかは突き詰めて考えるとすごいことになるようです。深遠やわー。

Filed under: ,

PHPで値に「日本語」を含むか調べる(正規表現)

前回似たような記事を書いたとき、もしかしているかもなーと思いながらスルーしていたツケが……。

if(preg_match( "/[一-龠]+|[ぁ-ん]+|[ァ-ヴー]+|[a-zA-Z0-9]+/u", $str) ){
  // 「日本語」を含む時の処理
}else{
  // 「日本語」を含まない時の処理
}

Filed under: ,