knowledge base

マークアップ/フロントエンドエンジニアのWEB制作における備忘録です。平日はWEB屋、休日は社会人劇団の主宰・劇作家をしています。

IEで「いいね」ボタンが文字化けする

Helveticaが原因

IEfacebookの「いいね」ボタンを実装すると、文字化けしてしまいました。

f:id:ShinImae:20160113160034j:plain

どうやら、デフォルトでHelveticaがフォント指定されているらしく、そのため文字化けを起こしてしまったようです。

IEHelveticaとの相性の悪さは有名で、今回のように文字化けしてしまったり、フォントそのものが表示されないなど様々なものが報告されています。

今回もそのような例のひとつであるとのことですが、パラメータにて別のフォントを指定することが可能であるようです。

下記記事に各種実装方法における解決策が紹介されていましたので、抜粋しておきます。

www.ajike.co.jp

/* iframe */ 
<iframe style="border: none; overflow: hidden; width: 110px; height: 21px;" src="//www.facebook.com/plugins/like.php?href=http%3A%2F%2FXXXXX.XX.XX%2F&send=false&layout=button_count&width=110&show_faces=false&font=arial&colorscheme=light&action=like&height=21&appId=XXXXXXXXXXXXXX" frameborder="0" scrolling="no">  
/* XFBML */ <fb:like href="//www.XXXXX.jp/" send="false" layout="button_count" width="110" show_faces="false" font="arial" data-mce-href="//www.XXXXX.jp/">
/* HTML5 */ <div class="fb-like" data-width="105" data-layout="button_count" data-show-faces="true" data-send="false" data-font="arial" data-href="//www.facebook.com/pages/XXXXXXX/XXXXXXXXXXXX">>

Likeboxも同じ要領で対応できるそうです。

 

IEで埋込みYouTubeが最前面に表示される

Flash特有の属性値を指定

スクロールに追従する固定ヘッダーを実装していたところ、IEでのみYouTubeを埋め込んだiframeがヘッダーより前面に表示されてしまうという現象が起きました。

f:id:ShinImae:20160108184303j:plain

本来は左図のようにヘッダーが最前面に表示されるべきところ、右図ではYouTubeが最前面になってしまっています。

これはレガシーなIEでのみ起こる現象ではなく、最新版のIEでも発生してしまいます。

z-indexを用いて重なり順を明示的に指定してみたのですが、効果はありませんでした。

調べたところ、wmodeというパラメータを指定すれば解決するそうです。

YouTubeをiframeで埋め込んだ際、iframe内にはFlashコンテンツが生成されるそうです。

Flashコンテンツには重なり順を指定するwmodeというパラメータがあり、デフォルトでは重なり順を無視して最前面に表示される「wmode=window」が設定されているとか。

これを「wmode=transparent」にすることで、背面に表示することが可能になります。

Flashの場合はembet要素の属性値として指定しますが、iframeによるYouTube埋込みの場合は、GETパラメータにこの値を指定します。

<iframe src="//www.youtube.com/embed/?wmode=transparent"></iframe>

これで、意図した表示に戻すことができました。

wmodeとは

僕自身はあまりFlashには馴染みがなかったので、wmodeという属性値について調べてみました。

helpx.adobe.com

window
SWF コンテンツは、Web ページ上で専用の長方形のウィンドウに再生されます。window を指定した場合、SWF コンテンツと HTML レイヤーは相互に影響し合うことはなく、Flash アプリケーションが常に最前面のアイテムになります。
direct
パスレンダリングを使用します。スクリーンバッファへの格納がバイパスされ、SWF コンテンツを直接画面に描画します。
コンテンツ再生のパフォーマンスを重視する場合にこの値を指定してください。Stage Video や Stage 3D などを使用するハードウェアアクセラレーションが有効になります。
opaque
SWF コンテンツが、その他の HTML 要素と同一レイヤーに配置されます。
SWF は不透明で、下層レイヤーにあるすべてのページ要素が非表示になります。
window やdirect を指定した場合と比較して、再生パフォーマンスが低下します。
transparent
SWF コンテンツが、その他の HTML 要素と同一レイヤーに配置されます。SWF ファイルの背景色(ステージカラー)は透明になります。
透明領域の背面にある HTML 要素は表示され、透明度によってブレンドされます。
window や direct を指定した場合と比較して再生パフォーマンスは低下します。
gpu
インターネット接続のテレビやモバイルデバイスなどにおける追加のハードウェアアクセラレーションを使用します。
その他の値を指定した場合とは対照的に、表示データリストグラフィックにおけるピクセルの正確性は保証されません。
その他の点については direct を指定した場合と同様です。

純然たるFlashコンテンツの場合、このwmodeによっては日本語の文字入力領域を設定しても入力ができないなど問題点があるそうですが、昨今ではさほど気にしなくてもよいでしょう。

Gmailで画像を非表示にできない

display:noneは無効

何かとクセの多いHTMLメールコーディングですが、Gmailは特に癖が多く、先日は画像の非表示ができないというバグに直面しました。

調べたところ、どうやらdisplay:noneは無効になってしまうとのことです。

stackoverflow.com

こちらの記事よると、次のスタイルを指定することで非表示にできるとのこと。

    <img alt="XXX" src="XXX" style="width:0px; min-height:0px;">

ただし、この方法だとOutlookでは表示されてしまうので、次の指定も追加します。

    <img alt="XXX" src="XXX" style="width:0px; min-height:0px; display:none; mso-hide:all;">

mso-XXXとは、Outlook専用のハックのようなものです。

OutlookレンダリングがWord(Microsoft Office Word) を利用していることが由来だとか。

WordドキュメントをHTML出力した際につけられるプロパティらしく、ほかにもmso-para-marginなど様々なものがあるとか。

余談

横道にそれてしまいますが、Outlookのみに有効な条件付きコメントが存在するそうです。

<!--[if gte mso 9]>
    <style type="text/css">
    /* Outlook用のスタイルを記述. */
    </style>
<![endif]-->

確実に有効とは言い切れないそうですが、覚えておいて損はないでしょう。

ブラウザで表示できる最小フォントサイズ(10px)以下の文字を表示する

ブラウザが表示できる最小フォントサイズは10px

ブラウザは可読性維持のために、CSSで10px未満のフォントサイズを指定しても無視するという機能が備わっています。 以下の例では、決して7pxで表示されることはありません。 後述しますが、zoomを使っても無駄でした。

p {
  font-size: 7px; /* 10pxで表示されてしまう */
}

下記事例はとある図表の一部なのですが、見出しエリアを一行分しか確保していなかったため、あふれてしまいました。

 

f:id:ShinImae:20160108174635j:plain

これは英語を基準にデザインされていたコンテンツを他言語対応する際に起きた問題です。

ロシア語など文字量の多い言語では改行が必要になってしまい、見出し用に確保したエリアからあふれてしまいました。

諸事情によりHTMLを編集することができないため、見出し部分を画像に置き換えることもできませんでした。

そこで文字サイズを小さくすることで対応しようとしたのですが、10px以下の文字サイズでないとタイル状に並べた画像エリアに重なってしまうことが分かりました。

ちなみには、本来想定していたもの(一行の見出し)は次のようなデザインです。

f:id:ShinImae:20160108174648j:plain

先日印刷プレビューについて記事を書かせて頂いたときと同様、ユーザー側の設定で最小文字サイズを変更することができますが、デザインの都合上どうしても極小の文字サイズで表示したい場合があります。

今までは画像に頼らざるを得ませんでしたが、モダンブラウザが普及しつつある最近であれば画像に頼らなくとも実装することができます。

transform:scale を使う

モダンブラウザ(IE9+, GoogleChrome, FireFox, Safari, Opera)であれば、CSS3のプロパティであるtransformを用いて拡縮します。

h2 {
   -moz-transform: scale(0.8);
   -webkit-transform: scale(0.8);
   -o-transform: scale(0.8);
   -ms-transform: scale(0.8);
   transform: scale(0.8);
}

scaleの引数には倍率を指定します。今回は0.8倍になるように指定しています。

ただしこれらの指定のみでは次のようになってしまいます。

f:id:ShinImae:20160108174658j:plain

薄く塗られた領域分だけ、ずれてしまいました。

これは、変形する際の基準点が要素の中心に設定されているためです。

そこで、変形の基準点を左上に変更するため、次のプロパティも変更します。

h2 {
   -moz-transform: scale(0.8);
   -webkit-transform: scale(0.8);
   -o-transform: scale(0.8);
   -ms-transform: scale(0.8);
   transform: scale(0.8);
   -moz-transform-origin: 0px 0px;
   -webkit-transform-origin: 0px 0px;
   -o-transform-origin: 0px 0px;
   -ms-transform-origin: 0px 0px;
   transform-origin: 0px 0px;
}

transform-originは50% 50%がブラウザの持つ初期値です。

基準点の指定方法については、左上を基点として算出します。

background-positionと算出方法は同じです。

こうすることで、意図した表示を実装することができました。 

f:id:ShinImae:20160108174709j:plain

レガシーなIEはzoomを用いたほうが早い

実はIE8以下には、filterプロパティにより独自拡張機能で透過・フィルター・シャドウ・変形などのCSS3ライクな機能がすでに実装されています。

下記のようなものを一度は見たことがあるのではないでしょうか。

filter:progid:DXImageTransform.Microsoft...

www.htmq.com

これにMatrixを渡して拡縮させることは可能なのですが、算出方法がたいへん難解なのでお勧めしません。

コンバートするサイトもあるようですが、むしろ直感的に分かりやすいzoomを指定したほうがよいと個人的には思います。

レガシーなIEならばzoomで文字サイズを拡縮させることが可能だからです。

/* レガシーなIEにのみ効くようなクラスを追加 */
h2.ie-fix {
   zoom: 0.8; 
}

多少サイズ感が変わってしまうので、高さなどを別途調整すれば、CSS3を用いた場合と同様の表示を実装することが可能です。

Androidデフォルトブラウザでviewportが無視される

たとえば下記のようなページを想定します。

 

f:id:ShinImae:20160108163451j:plain

ビジュアルが表示幅ぴったりに広がっており、とても洗練されたデザインですね。

今回はこのデザインを横幅320pxに最適化して表示する際の問題について書きたいと思います。

横幅320pxに最適化とは

横幅320px固定のデザインを、各デバイスの幅に合わせてフィットさせることを言います。

具体的には次の指定をすることで最適化を行います。

<meta name="viewport" content="width=320" />

この指定により、横幅320px固定でコーディングしても、各デバイスの幅にぴったりフィットします。

ところが、デバイス幅が320px以上のAndroid端末(デフォルトブラウザ)で表示すると下図のようにviewportの指定が無視されてしまい、ページ両端に余白が生じてしまいます。

f:id:ShinImae:20160108163458j:plain

 

どうやらAndroidデフォルトブラウザのもつバグのようで、AndroidGoogleChromeFirefoxでは、デバイスの横幅にぴったりフィットします。

この問題を解決するには2段階の方法をとります。

  1. Androidデフォルトブラウザのみを判別できるようにする
  2. コンテンツがデバイスの横幅にフィットするように拡大するような指定をかける

では、ひとつづつ解決法を見てゆきましょう。

Androidデフォルトブラウザの判別

あまり知られてはいませんが、IE,Chrome,FireFoxと同様にデフォルトブラウザもUserAgentから判別できます。

こちらの記事で詳しく解説されているとおり、どうやら「linux; u;」という文字列が含まれていればデフォルトブラウザであるようです。

yoyogisan.hatenablog.com

まずは下記方法で、デフォルトブラウザを判別します。

var ua = window.navigator.userAgent.toLowerCase();
if(ua.indexOf('linux; u;') != -1){
    return true;
}

より確実に判別したいなら、OSがAndroidであるか判別した上で、デフォルトブラウザであるかどうかを判定します。

var ua = window.navigator.userAgent.toLowerCase();
if(ua.indexOf('android') != -1){						
   if(ua.indexOf('linux; u;') != -1){
      return true;
   }
}

横幅にフィットするように拡縮指定をする

横幅320pxに対する現在のウィンドウ幅の比率を算出し、その比率だけ拡縮するようにします。ロジックは次のとおり。

var windowWidth = $(window).width();
var ratio = windowWidth/320;
$('html').css({'zoom' : ratio });

今回はウィンドウの横幅を320で除算していますが、viewportのサイズによってこの値は変化します(たとえば640pxで最適化をするなら640で除算します)。

こうすることで、小さなデバイスでは縮小され、大きなデバイスでは拡大されます。

これを、先ほどご紹介したデフォルトブラウザ判別方法に組み込みます。

var ua = window.navigator.userAgent.toLowerCase();
var windowWidth = $(window).width();
var ratio = windowWidth/320;
if(ua.indexOf('android') != -1){						
   if(ua.indexOf('linux; u;') != -1){
      $('html').css({'zoom' : ratio });
   }
}

こうすることで、デフォルトブラウザでもねらい通りの表示を実現することができます。

text-indentも指定してもテキストを非表示にできない

jQueryプラグインを利用してスライダーを作っていました。

f:id:ShinImae:20160108161745j:plain

どうやらこのプラグインは、サムネイルではなく番号をコントローラーとして出力するようです。

ところがデザインでは、この部分には番号ではなく丸いボタンが指定されていました。

f:id:ShinImae:20160108161818j:plain

なので、背景色や角丸をCSSで設定し、番号を飛ばすことにしました。

プラグインの中身をカスタマイズする方法もあるのですが、文書構造的に番号をソースに残したかったのでCSSのみで対応することにしました。

f:id:ShinImae:20160108161854j:plain

テキストを非表示にするためによく使われる、以下のスタイルを指定しました。 ポイントとなるのは7行目、text-indentに大きな値を指定する点です。

ul li{
  width: 17px;
  height: 17px;
  background: #FFF;
  border-radius: 50%;
 text-align: right;
  text-indent: -99999px;
}

ところが、テキストが非表示になりません。

f:id:ShinImae:20160108161854j:plain

CSSをよく見て頂ければわかるのですが、実はこのサムネイルにはtext-align:rightも同時に指定されており、これが原因であるようです。

理屈はいたって簡単で、インデントで負の値を指定しても、右揃えになってしまうためテキストの末端が表示されてしまうという仕組みでした。

なので、今回のようにtext-align:rightが指定してある場合は、次のように指定を変えれば解決できます。

text-indent: 99999px;

これで無事に意図した表示を実装することができました。

f:id:ShinImae:20160108161818j:plain

Androidデフォルトブラウザで表示が崩れる

ところがこのスタイルをAndroidデフォルトブラウザで表示すると、次のような表示になってしまいました。 

f:id:ShinImae:20160108161933j:plain

どうやらAndroid端末ではtext-indentで指定した分だけ、描画領域を確保してしまうようです。

ほかにもAndroidではtext-indentが効かないというバグが頻繁に効かれます。

そこで、Androidにも対応できるスタイル指定を行います。

※下記CSSではサイズや背景色の指定は省略しています。

ul li{
  text-indent: 100%;
  white-space: nowrap;
  overflow: hidden;
}

text-indent:99999pxの代わりに上記のスタイルを3つセットで指定すると、きちんとテキストを非表示にすることができます。

f:id:ShinImae:20160108162028j:plain

こちらの指定、もちろんPCやiOSでも有効です。

なのでレスポンシブコーディングや、マルチデバイス対応の際は、この指定を使えばたいていのデバイスでテキストを非表示にすることができます。

IE8で明朝体の表示が崩れる

明朝体にするとき、最も簡単なフォント指定は次のとおりです。

font-family: serif;

これでほとんどのブラウザでは明朝体になるのですが、IE8だけ表示が崩れてしまいます。下図の赤枠で囲った文字がその顕著な例です。

f:id:ShinImae:20160107214023j:plain

「青」がゴシック体になっているし、「飾」も明朝体ではあるものの見慣れない字体になっています。
調べたところ、どうやらIE8はきちんとフォント名まで記述しないといけないようです。

font-family: 'MS P明朝', 'MS PMincho', serif;

これで狙い通りのフォントで表示することができます。