|
|
Andoid向けのアプリケーション開発を始めたものの、自社サイトがスマートフォン対応してないのも格好がつきません。かといって、PCとスマートフォンのアウトプットを出しわけするのも、DokuWikiではなかなか難しいようです。
で、ちょっと考えました。スマートフォンといってもまっとうなフルブラウザを持っています。つまり、CSSやJavaScriptもPCのそれと遜色ありません。違うのは画面の大きさだけと言ってもいいでしょう。
ならば、JavaScriptでレイアウトを書き換えるようにしてしまえば良いのではないか?そういう発想でちょこちょことやってみたら、案外簡単で効果的な結果が得られることがわかりました。
ウインドウ幅によってページを組み替える
User-Agentの値を見て処理をするのがよくある手法ですが、ここではUser-Agentを使わず、ウインドウの幅を基準にページの組み換えをすることにします。これによって、PCのブラウザでもウインドウを小さくしたときに上手く表示できるようになります。
左右のサイドバーの部分は最後に持っていく
左右のサイドバーに表示されるのはナビゲーションや追加的な情報なので、本文の後に表示されるようにします。そういうのが携帯サイトでの常道のようです。
大きな画像
大きな画像も画面に収まるように縮小することも考えたのですが、小さすぎて見えなくなっては元も子もありません。ならばタップしたら拡大ということもやってみましたが、スクロールするときについつい画像をタップしてしまい、大変に邪魔くさいことになってしまいました。で、サイズはそのままにして、左右にスクロールさせて見られるようにしました。
preタグに囲まれた領域
プログラムコードの記述にpreを多用しています。これは途中で改行しないため、ほとんどの場合はみだしてしまって右側を見ることができません。そこで、画像と同様に左右スクロールするようにしました。
大きなテーブル
画像と同様に左右スクロールするのが良さそうですが、本サイトではさほど幅の広いテーブルは使ってないので、今回は対応しないことにします。
//ページ読み込み完了後に動くように、DokuWikiのaddInitEvent()関数を使って呼び出すようにする。
addInitEvent(function() {
if (typeof(window.innerWidth) != 'number') return;
if (window.innerWidth > 500) return;
Function.prototype.bind = function(target) {
var method = this;
return function() {
return method.apply(target, arguments);
}
};
var addscroller = function(wrapper) {
wrapper.ontouchstart = function(evt) {
//console.log(this);
//console.log(evt.touches[0].pageX + ',' + evt.touches[0].pageY);
this.oldX = evt.touches[0].pageX;
this.oldY = evt.touches[0].pageY;
}.bind(wrapper);
wrapper.ontouchmove = function(evt) {
if (this.offsetWidth >= this.scrollWidth) return;
var dx = this.oldX - evt.touches[0].pageX;
var dy = this.oldY - evt.touches[0].pageY;
if (Math.abs(dx) > Math.abs(dy)) {
evt.preventDefault();
evt.stopPropagation();
//console.log('ontouchmove:' + this.oldX + '<=>' + evt.touches[0].pageX);
this.scrollLeft = this.scrollLeft + this.oldX - evt.touches[0].pageX;
}
this.oldX = evt.touches[0].pageX;
this.oldY = evt.touches[0].pageY;
}.bind(wrapper);
wrapper.ontouchend = function(evt) {
//console.log(this);
this.oldX = undefined;
this.oldY = undefined;
}.bind(wrapper);
};
var getabs = function(node) {
var p = node;
var result = { x:0, y:0 };
while (p) {
result.x += p.offsetLeft;
result.y += p.offsetTop;
p = p.offsetParent;
}
return result;
};
var page = document.querySelector('div.page');
page.style.padding = '5px';
var table = document.querySelector('table.layout-hbox');
//mainカラムの中身を全部先頭に出す。
var el = document.querySelectorAll('td.layout-body > *');
for (var i = 0; el && i < el.length; i++) {
page.appendChild(el[i]);
}
//toc
var e = document.querySelector('div.toc');
if (e) {
e.style.cssFloat = 'none';
e.style.width = 'auto';
e.style.margin = 0;
}
//spacer除去
var el = document.querySelectorAll("table.layout-hbox td.spacer");
for (var i = 0; el && i < el.length; i++) {
el[i].parentNode.removeChild(el[i]);
}
//search
var e = document.querySelector('div.search');
if (e) {
page.appendChild(e);
e.style.cssFloat = 'none';
e.style.textAlign = 'left';
}
var e = document.querySelector('form#dw__search');
if (e) {
e.style.cssFloat = 'none';
e.style.textAlign = 'left';
}
//カラムを下へ
var el = document.querySelectorAll("table.layout-hbox > tbody > tr > td");
if (el && el[2]) {
for (var i = el[2].childNodes.length - 1; i >= 0; i--) {
var item = el[2].childNodes.item(i);
page.appendChild(item);
item.style.width = '';
}
}
if (el && el[0]) {
for (var i = el[0].childNodes.length - 1; i >= 0; i--) {
var item = el[0].childNodes.item(i);
page.appendChild(item);
item.style.width = '';
}
}
//お問い合わせは最後へ
var e = document.querySelector('div#bar__topright');
if (e) {
page.appendChild(e);
e.style.cssFloat = 'none';
}
//top bar
var e = document.querySelector('div#bar__top');
if (e) {
if (e) {
var wrapper = document.createElement('div');
e.parentNode.insertBefore(wrapper, e);
wrapper.appendChild(e);
wrapper.style.overflow = 'hidden';
wrapper.style.whiteSpace = 'nowrap';
addscroller(wrapper);
}
//bottom bar
var e = document.querySelector('div#bar__bottom');
if (e) {
var wrapper = document.createElement('div');
e.parentNode.insertBefore(wrapper, e);
wrapper.appendChild(e);
wrapper.style.overflow = 'hidden';
wrapper.style.whiteSpace = 'nowrap';
addscroller(wrapper);
}
var e = document.querySelector('div#bar__bottomright');
if (e) {
e.style.cssFloat = 'none';
}
//pre
var el = document.querySelectorAll('pre');
for (var i = 0; el && i < el.length; i++) {
addscroller(el[i]);
}
//layout-tree
var el = document.querySelectorAll('table.layout-tree');
for (var i = 0; el && i < el.length; i++) {
var wrapper = document.createElement('div');
el[i].parentNode.insertBefore(wrapper, el[i]);
wrapper.appendChild(el[i]);
wrapper.style.overflow = 'hidden';
wrapper.style.whiteSpace = 'nowrap';
addscroller(wrapper);
}
//img.media
var el = document.querySelectorAll('img.media, img.mediacenter');
for (var i = 0; el && i < el.length; i++) {
var wrapper = document.createElement('div');
el[i].parentNode.insertBefore(wrapper, el[i]);
wrapper.appendChild(el[i]);
wrapper.style.overflow = 'hidden';
wrapper.style.whiteSpace = 'nowrap';
addscroller(wrapper);
}
//レイアウトテーブルを削除
table.parentNode.removeChild(table);
});
小一時間ほどの少ない手間で、PC向けWebサイトをスマートフォンに対応させることができた。
この方法は、よほどデザインの凝ったサイトでなければかなり有効である。
かといって、レイアウトの組み換えはサイト単位に個別に実装する必要があり、スクリプトを汎用化させるのは難しい。
スマートフォン対応していない各サイトも同様のスクリプトを組み込んで欲しい。
|
|
|