夏休み自由研究: タブレットの表示
内容
はじめに
近頃は、Webサイト閲覧に使用する機器が、従来のパソコン一辺倒から、タブレットやスマートフォンへと多様化しています。私は、パソコン派なのですが、HTML/CSSを人様に教える身である以上、他の機器でもどのように表示されるか、やはり気になってきました。
用意したタブレット
もちろん、様々な意味でプライバシーを侵害する機器であるスマートフォン(や携帯電話)を持つ気にはなれないので、とりあえずはタブレットを探求してみることにしました。昨年、記念すべきMicrosoft純正ハードウェアとして登場したSurface Proを皮切りに、この夏までに計3台のタブレットを購入。以下の表が、その概要です。
Microsoft Surface Pro | Lenovo Thinkpad 8 | Asus MeMO Pad7 (ME176C) | |
---|---|---|---|
画面サイズとdpi値は当方で算出したものなので、実際の製品仕様とは異なる場合があります。 Surface Proのデフォルトのデバイスピクセル比は1.5ですが、1に変更して使用しています。
|
|||
画面 | 10.6型 | 8.3型 | 7型 |
画面サイズ※ | 9.24 x 5.20 in | 7.04 x 4.40 in | 5.94 x 3.71 in |
画面解像度 | 1920 x 1080 px | 1920 x 1200 px | 1280 x 800 px |
dpi※ | 207 | 272 | 215 |
使用解像度 | 1920 x 1080 px | 1280 x 800 px | 960 x 600 px |
デバイスピクセル比 | 1※ | 1.5 | 1.33125 |
GPU | インテル HD Graphics 4000 | インテル HD Graphics | インテル HD Graphics |
CPU | インテル Core i5-3317U | インテル Atom Z3770 | インテル Atom Z3745 |
動作周波数(バースト時) | 1.70GHz (2.6GHz) | 1.46GHz (2.39GHz) | 1.33GHz (1.86GHz) |
コア数(スレッド数) | 2 (4) | 4 (4) | 4 (4) |
メモリ | 4GB | 2GB | 1GB |
ストレージ | 256GB | 64GB | 16GB |
TDP/SDP | 17W | 2W | 2W |
OS | Windows 8.1 Pro 64bit | Windows 8.1 32bit | Android 4.4.2 |
まあ、Surface Proはタブレットというよりパソコンに近いのですが、Lenovo Thinkpad 8は、Windowsタブレットとしての性格のほうが強いと言えるでしょう。また、Androidタブレットでの表示も確認するため、Asus MeMO Pad7も仲間に加えました。
これらは、それぞれ10.6型、8.3型、7型、dpiで表す解像度が200以上であり、現時点での主要な表示能力は押さえることができました。Windows、Androidタブレットの双方を含み、主要なタブレット環境は網羅したといえます。林檎? それはもちろん対象外です。
表示サイズの検出
そして、これらのタブレットの表示機能を、概括的にチェックするため、以下のページをサイトに加えました。
https://krzm.jp/test/
JavaScriptによる検出
すなわち、JavaScriptを使用し、以下の手段で各サイズを検出しています(サンプルコード1 参照)。
- デバイスピクセル比
window.devicePixelRatio
- 画面の幅と高さ
screen.width
screen.height
- 画面有効領域の幅と高さ
screen.availWidth
screen.availHeight
- ウインドウ(ビューポート)の幅と高さ
window.innerWidth
window.innerHeight
なお検出は、イベントリスナーを使ってDOMContentLoaded
時に実行しているので、Internet Explorer 8以下では動作しません。同様に、ウインドウ サイズの変更は、rsize
イベントで更新しています。さらに、画面および画面有効領域の幅/高さを、タブレットを回転させたとき(DeviceOrientation
イベント時)に更新しているのですが、このイベントは回転を検知するセンサーによって発生が伝達されるので、タブレットでしか実行されません。しかも、Windowsタブレット上のIE 11、Chrome/Operaでは動作するのですが、AndroidタブレットであるMeMO Pad 7上のChrome/Operaでは反応しませんでした。なお、Firefoxは、いずれのタブレットでも、動作しません。まあ、そんなものでしょう。
CSSによる検出
また、サイズを数値で検出するほかに、CSSのメディアクエリーによって、現在の表示サイズを色分けしています。たとえば、@media (min-width:961px) and (max-width:1024px)
のように記述することで、ウインドウの幅が961~1024ピクセルである状態を検出し、body要素に背景色を指定しています(サンプルコード2 参照)。これによって、1024ピクセル以下の際は、ページの背景がクリムゾン色になります。
高解像度かつ小さな画面のタブレットでは、実際の画面サイズと、ウインドウサイズは異なります。そのあたりを調べるために、データを収集しようと目論んでいるわけです。というわけで、夏休みももう終わりですが、研究は始まったばかりで、まだ検証結果にはたどり着いていません…。大人ですから、8月31日に夏休みの宿題に追われるようなことはせず、秋の夜長に気長に調べていくつもりです。
おまけ: 回転の検出
この過程で、ちょっと思いついたのが、「タブレットの回転検知」ページです。ここでは、やはりDeviceOrientation
イベント時にX、Y、Z軸の回転角度を検出し、それらをCSS transform
プロパティで指定することで(X軸であれば、値はrotateX(角度)
)、SVG画像を各軸で3D回転させています(サンプルコード3 参照)。
もちろん、これもWindowsタブレットのIE 11やChrome/Operaでしか実行できません。
なお、DeviceOrientationについては、「Internet Explorer デベロッパー センター」の「デバイスの向きのイベント」ページに、詳しい解説が日本語で掲載されています。
サンプル ソースコード
var VALUE = new Array;
var obj;
(function () {
if (!document.addEventListener) {
window.onload = function () {
document.getElementById("main").innerHTML = "<hr /><p>IE 8以下では表示されません。</p><hr />";
}
return;
} else {
document.addEventListener("DOMContentLoaded", function (){
obj = document.querySelectorAll("main section:first-of-type dd");
VALUE[0] = window.devicePixelRatio;
VALUE[1] = screen.width;
VALUE[2] = screen.height;
VALUE[3] = screen.availWidth;
VALUE[4] = screen.availHeight;
VALUE[5] = window.innerWidth;
VALUE[6] = window.innerHeight;
for (var i = 0; i <= 6; i++) {
if (i >= 1) {
var TEXT = VALUE[i] + " px";
} else {
var TEXT = VALUE[i];
}
obj.item(i).innerHTML = TEXT;
}
}, false);
window.addEventListener("deviceorientation", function (){
VALUE[0] = window.devicePixelRatio;
VALUE[1] = screen.width;
VALUE[2] = screen.height;
VALUE[3] = screen.availWidth;
VALUE[4] = screen.availHeight;
for (var i = 0; i <= 4; i++) {
if (i >= 1) {
var TEXT = VALUE[i] + " px";
} else {
var TEXT = VALUE[i];
}
obj.item(i).innerHTML = TEXT;
}
}, false);
window.addEventListener("resize", function (){
VALUE[5] = window.innerWidth;
VALUE[6] = window.innerHeight;
for (var i = 5; i <= 6; i++) {
obj.item(i).innerHTML = VALUE[i] + " px";
}
}, false);
}
}) ();
@media only screen and (min-width:2561px) {
body{
background-color:rgb(255,64,32);
}
#frame {
width:2496px;
}
}
@media only screen and (min-width:1921px) and (max-width:2560px) {
body{
background-color:rgb(255,96,255);
}
#frame {
width:1856px;
}
}
@media only screen and (min-width:1367px) and (max-width:1920px) {
body{
color:rgb(255,255,255);
background-color:rgb(32,32,255);
text-shadow:0px 0px 6px rgba(255,255,255,0.8);
}
#frame {
width:1302px;
}
a {
color:rgb(255,255,255);
}
}
@media only screen and (min-width:1281px) and (max-width:1366px) {
body{
background-color:rgb(96,255,255);
}
#frame {
width:1216px;
}
}
@media only screen and (min-width:1201px) and (max-width:1280px) {
body{
background-color:rgb(96,255,96);
}
#frame {
width:1136px;
}
}
@media only screen and (min-width:1081px) and (max-width:1200px) {
body{
background-color:rgb(255,255,64);
}
#frame {
width:1016px;
}
}
@media only screen and (min-width:1025px) and (max-width:1080px) {
body{
background-color:rgb(255,128,32);
}
#frame {
width:960px;
}
}
@media only screen and (min-width:961px) and (max-width:1024px) {
body{
background-color:rgb(153,51,102);
}
#frame {
width:896px;
}
}
@media only screen and (min-width:801px) and (max-width:960px) {
body{
background-color:rgb(204,153,51);
}
#frame {
width:736px;
}
}
@media only screen and (min-width:641px) and (max-width:800px) {
body{
background-color:rgb(153,102,255);
}
#frame {
width:576px;
}
}
@media only screen and (min-width:601px) and (max-width:640px) {
body{
font-size:14px;
background-color:rgb(153,153,102);
}
#frame {
width:536px;
}
}
@media only screen and (min-width:481px) and (max-width:600px) {
body{
font-size:14px;
background-color:rgb(128,128,128);
}
#frame {
width:416px;
}
main {
display:block;
}
main section {
width:100%;
margin:1em;
}
}
@media only screen and (min-width:381px) and (max-width:480px) {
body{
font-size:14px;
background-color:rgb(255,255,255);
}
#frame {
width:316px;
}
main {
display:block;
}
main section {
width:100%;
margin:1em;
}
main section:last-of-type {
box-shadow:
0px 0px 0px 2px rgb(128,128,128),
0px 0px 8px 2px rgba(0,0,0,0.4),
inset 4px 4px 8px rgba(0,0,0,0.4),
inset -2px -2px 6px rgba(128,128,128,0.4);
}
}
@media only screen and (max-width:380px) {
body{
font-size:14px;
color:rgb(255,255,255);
background-color:rgb(0,0,0);
text-shadow:0px 0px 6px rgba(255,255,255,0.8);
}
#frame {
width:316px;
}
main {
display:block;
}
main section {
width:100%;
margin:1em;
}
a {
color:rgb(255,255,255);
}
}
var VALUE = new Array;
var evt;
(function () {
if (!window.addEventListener) {
window.onload = function () {
document.getElementById("main").innerHTML = "<hr /><p>IE 8以下では表示されません。</p><hr />";
}
return;
} else {
window.addEventListener("deviceorientation", function (evt){
var scW = screen.width;
var scH = screen.height;
var obj = document.querySelectorAll("main dd");
var IMAGE = document.querySelectorAll("main img");
VALUE[0] = evt.beta;
VALUE[1] = evt.gamma;
VALUE[2] = evt.alpha;
for (var i=0; i<=2; i++) {
obj.item(i).innerHTML = VALUE[i] + "度";
}
if (scW > scH ) {
IMAGE.item(0).style.transform = "rotateX(" + (0 - VALUE[0]) + "deg)";
IMAGE.item(1).style.transform = "rotateY(" + VALUE[1] + "deg)";
IMAGE.item(2).style.transform = "rotateZ(" + VALUE[2] + "deg)";
} else {
IMAGE.item(0).style.transform = "rotateX(" + (0 - VALUE[1]) + "deg)";
IMAGE.item(1).style.transform = "rotateY(" + (0 - VALUE[0]) + "deg)";
IMAGE.item(2).style.transform = "rotateZ(" + (90 - VALUE[2]) + "deg)";
}
}, false);
}
}) ();