ブラウザで表示できる最小フォントサイズ(10px)以下の文字を表示する
ブラウザが表示できる最小フォントサイズは10px
ブラウザは可読性維持のために、CSSで10px未満のフォントサイズを指定しても無視するという機能が備わっています。 以下の例では、決して7pxで表示されることはありません。 後述しますが、zoomを使っても無駄でした。
p { font-size: 7px; /* 10pxで表示されてしまう */ }
下記事例はとある図表の一部なのですが、見出しエリアを一行分しか確保していなかったため、あふれてしまいました。
これは英語を基準にデザインされていたコンテンツを他言語対応する際に起きた問題です。
ロシア語など文字量の多い言語では改行が必要になってしまい、見出し用に確保したエリアからあふれてしまいました。
諸事情によりHTMLを編集することができないため、見出し部分を画像に置き換えることもできませんでした。
そこで文字サイズを小さくすることで対応しようとしたのですが、10px以下の文字サイズでないとタイル状に並べた画像エリアに重なってしまうことが分かりました。
ちなみには、本来想定していたもの(一行の見出し)は次のようなデザインです。
先日印刷プレビューについて記事を書かせて頂いたときと同様、ユーザー側の設定で最小文字サイズを変更することができますが、デザインの都合上どうしても極小の文字サイズで表示したい場合があります。
今までは画像に頼らざるを得ませんでしたが、モダンブラウザが普及しつつある最近であれば画像に頼らなくとも実装することができます。
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倍になるように指定しています。
ただしこれらの指定のみでは次のようになってしまいます。
薄く塗られた領域分だけ、ずれてしまいました。
これは、変形する際の基準点が要素の中心に設定されているためです。
そこで、変形の基準点を左上に変更するため、次のプロパティも変更します。
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と算出方法は同じです。
こうすることで、意図した表示を実装することができました。
レガシーなIEはzoomを用いたほうが早い
実はIE8以下には、filterプロパティにより独自拡張機能で透過・フィルター・シャドウ・変形などのCSS3ライクな機能がすでに実装されています。
下記のようなものを一度は見たことがあるのではないでしょうか。
filter:progid:DXImageTransform.Microsoft...
これにMatrixを渡して拡縮させることは可能なのですが、算出方法がたいへん難解なのでお勧めしません。
コンバートするサイトもあるようですが、むしろ直感的に分かりやすいzoomを指定したほうがよいと個人的には思います。
レガシーなIEならばzoomで文字サイズを拡縮させることが可能だからです。
/* レガシーなIEにのみ効くようなクラスを追加 */ h2.ie-fix { zoom: 0.8; }
多少サイズ感が変わってしまうので、高さなどを別途調整すれば、CSS3を用いた場合と同様の表示を実装することが可能です。
Androidデフォルトブラウザでviewportが無視される
たとえば下記のようなページを想定します。
ビジュアルが表示幅ぴったりに広がっており、とても洗練されたデザインですね。
今回はこのデザインを横幅320pxに最適化して表示する際の問題について書きたいと思います。
横幅320pxに最適化とは
横幅320px固定のデザインを、各デバイスの幅に合わせてフィットさせることを言います。
具体的には次の指定をすることで最適化を行います。
<meta name="viewport" content="width=320" />
この指定により、横幅320px固定でコーディングしても、各デバイスの幅にぴったりフィットします。
ところが、デバイス幅が320px以上のAndroid端末(デフォルトブラウザ)で表示すると下図のようにviewportの指定が無視されてしまい、ページ両端に余白が生じてしまいます。
どうやらAndroidデフォルトブラウザのもつバグのようで、Android版GoogleChromeやFirefoxでは、デバイスの横幅にぴったりフィットします。
この問題を解決するには2段階の方法をとります。
- Androidデフォルトブラウザのみを判別できるようにする
- コンテンツがデバイスの横幅にフィットするように拡大するような指定をかける
では、ひとつづつ解決法を見てゆきましょう。
Androidデフォルトブラウザの判別
あまり知られてはいませんが、IE,Chrome,FireFoxと同様にデフォルトブラウザもUserAgentから判別できます。
こちらの記事で詳しく解説されているとおり、どうやら「linux; u;」という文字列が含まれていればデフォルトブラウザであるようです。
まずは下記方法で、デフォルトブラウザを判別します。
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プラグインを利用してスライダーを作っていました。
どうやらこのプラグインは、サムネイルではなく番号をコントローラーとして出力するようです。
ところがデザインでは、この部分には番号ではなく丸いボタンが指定されていました。
なので、背景色や角丸をCSSで設定し、番号を飛ばすことにしました。
※プラグインの中身をカスタマイズする方法もあるのですが、文書構造的に番号をソースに残したかったのでCSSのみで対応することにしました。
テキストを非表示にするためによく使われる、以下のスタイルを指定しました。 ポイントとなるのは7行目、text-indentに大きな値を指定する点です。
ul li{ width: 17px; height: 17px; background: #FFF; border-radius: 50%; text-align: right; text-indent: -99999px; }
ところが、テキストが非表示になりません。
CSSをよく見て頂ければわかるのですが、実はこのサムネイルにはtext-align:rightも同時に指定されており、これが原因であるようです。
理屈はいたって簡単で、インデントで負の値を指定しても、右揃えになってしまうためテキストの末端が表示されてしまうという仕組みでした。
なので、今回のようにtext-align:rightが指定してある場合は、次のように指定を変えれば解決できます。
text-indent: 99999px;
これで無事に意図した表示を実装することができました。
Androidデフォルトブラウザで表示が崩れる
ところがこのスタイルをAndroidデフォルトブラウザで表示すると、次のような表示になってしまいました。
どうやらAndroid端末ではtext-indentで指定した分だけ、描画領域を確保してしまうようです。
ほかにもAndroidではtext-indentが効かないというバグが頻繁に効かれます。
そこで、Androidにも対応できるスタイル指定を行います。
※下記CSSではサイズや背景色の指定は省略しています。
ul li{ text-indent: 100%; white-space: nowrap; overflow: hidden; }
text-indent:99999pxの代わりに上記のスタイルを3つセットで指定すると、きちんとテキストを非表示にすることができます。
こちらの指定、もちろんPCやiOSでも有効です。
なのでレスポンシブコーディングや、マルチデバイス対応の際は、この指定を使えばたいていのデバイスでテキストを非表示にすることができます。
関数内でその関数自身を取得実行する
関数内で、その関数自身の情報を得たいなと思っていました。
次の方法で可能となります。
var functionA = function(){ console.log(arguments); }
argumentsというオブジェクトは、本来名前の通り関数に渡された引数を参照できる配列に似たものです。
もし関数に3つの引数が渡されたなら、arguments[0], arguments[1], arguments[2]という具合に参照ができます。
arguments.callee
さて、argumentsにはlengthとcalleeというプロパティがあり、lengthは引数の数、calleeは現在実行している関数の関数本体を示します。
今回用いるのは、まさしくこのarguments.calleeというプロパティです。
このarguments.calleeにはいくつかプロパティがあり、関数名などを取得することができます。
var functionA = function(){ console.log(arguments.callee); /* 関数そのものを出力 */ console.log(arguments.callee.name); /* 関数名(functionA)を出力 */ }
arguments.calleeは関数本体を参照するため、呼び出すことが可能です。
たとえば、無名関数内で再帰処理をしなければいけない時などに利用できます。
ちなみに下記コードは再帰処理を終わらせるための分岐を書いていないので、無限ループになります。あしからず。
function(){
/* 関数名を与えなくても再帰呼び出しできる */ arguments.callee(); }
また、自分自身をイベントにon/offすることもできます。
下記例ではmyEventというカスタムイベントに一度関数を紐づけたのち、その関数実行後にイベントとの紐づけを解除しています。
myEventというイベントは何度も起こりえますが、それに紐づけた関数onMyEventFuncは一度のみの実行でよい場合に使えます。 (※ちなみにカスタムイベント作成のプログラムは省略しています)
var onMyEventFunc = function(){ $(window).off('myEvent', arguments.callee ); } $(window).on('myEvent', onMyEventFunc );
余談
しかしながら、strictモードの際にこのプロパティを参照するとエラーになるそうです。
紹介した割に、最近は非推奨になっているという悲しい結末で申し訳ありません。
どうやら引数に対して操作を行えるということが、あまりよろしくないそうです。
strictモードでは、関数名を与えたり、引数を別の変数で受け取る等の代替案をとらなければいけません。
JavaScriptを用いずにクリックを無効にする
クリックを無効にするには、JavaScriptを用いる手法をよく見かけますが、CSSでも実装が可能です。
a{ pointer-events: none; }
対応ブラウザはモダンブラウザが中心となっているそうです。
なぜこのようなプロパティがあるのだろうと思ったのですが、どうやらSVGと併用するといろいろなことが実現できるそうです。
以下で解説されているように、SVGのためのプロパティがいくつか用意されています。