PukiWiki/自作スキン/解説

pukiwiki.skin.php に手を加えて自作スキンをつくる(2022-10-01、追記:2024-10-10)


PukiWikiのスキンを自作したい人に向けて、
私が作ってみたスキンを例にメモします。



はじめに(スキンとは、なにか?)

他のCMSやWikiだとテンプレートとか、フレームワークとか、デザインサンプルとか、とにかく画面全体の見栄えを設定するやつです。
PukiWikiではスキンって呼びます。

文章やら画像やらの「コンテンツ」は自力で用意するわけですが、それらをどこにどう配置するのか、文字の色や大きさをどうするのか、とかをPukiWikiがやってくれます。

おおざっぱに言えば、
配置や順番を制御しているのは skin/pukiwiki.skin.php
色や大きさを制御しているのは skin/pukiwiki.css

言い換えると、
PHPでごりごりHTML構文を書くのが skin/pukiwiki.skin.php
そのHTMLから呼ばれるスタイルシートが skin/pukiwiki.css です。

本来は上記の2ファイルを中心にカスタマイズするわけですが、
今回私が用意したサンプルスキンでは skin.php の中で、JavaScriptを使ってスタイルシートも上書きする処理を入れています。
だから色設定からスマホ対応まで全部ふくめて1ファイルです。

「$COLOR_~」変数の値を変えて、Webブラウザで再読み込みすれば、すぐにホームページ全体の雰囲気を変えられるというのが私のスキンの利点です。*1

実際のサンプルはこちら


色の変更が容易なので、配色の雰囲気のテストに使うのも便利かもしれません。
(いろいろ試したあとに、その数値を自分のスキンやスタイルシートに反映する、とか)。

時間に合わせて色を変える処理とかも入れられます(後述「hrタグ(水平線)を点灯させる」)。

いろいろ試して遊んでみて下さい [smile]

pukiwiki.skin.php について

まず、公式の解説が分かり易いです。

https://pukiwiki.sourceforge.io/dev/?スキン/技術資料/1.4.4

最新版は 1.5.4ですが、おおまかな処理の流れは1.4.4と同じです。
(ただし 1.5.4より前の版を使っている方は脆弱性が報告されているので、最新版に更新しましょう

そして、私が手を加えた内容は

  • <table>タグで囲む
    一番上のタイトル部分で1table、
    続くナビ(新規、編集、検索とか)の部分で1table、
    MenuBar/本文/RightBar で1table、という形で囲んで色を付けました。
    囲んだ <table>タグは一部、border-radius で丸みをつけています。

  • 色を上書きする
    スタイルシートの colorと background-color を片っ端から上書きしています。
    スマホ画面の時はさらに横幅や左マージンとかも上書きします。

  • ナビボタンのアイコンを svg タグで作成
    あらかじめPukiWikiで image/top.png のようなアイコンが用意されていますが、
    今回は代わりに svg で描いてみました。*2
    記述は少々読みづらいですが、svgには読み込みが軽くて色が変更できるという利点があります*3


置き場所がしっくりこなくて「topicpath」は一旦、削っています。
必要だった方はすみません、置きたい場所に復活させてください。

あと、PHP_VERSION の記述も削ってます。こちらもよしなに*4

スマホ対応については後述。
この1ファイルで、PCとスマホ兼用のskinになります。


画面読込時に、色の上書き処理の瞬間が目立ってしまう場合
(サンプルスキンでは null_i_night.skin.php が該当)
skin/pukiwiki.css 本体のスタイルシートの背景色を変えることで回避できます。

(skin/pukiwiki.cssの20行目あたり)
body,td {
  color:black;
  background-color:white;
  (↑ここを white から blackに変える)


本来は .css で色を指定する(javascriptで上書きなんてやらない)のが作法だと思いますが、
今回は作法よりもWiki管理者側の(ラク)さ・楽しさを重視して、
あえて COLOR_ 変数で一括管理という選択肢を選びました。

もちろん、このスキンで調整できていない色も含めて、pukiwiki.cssを自分好みにカスタマイズすればもっと良いWikiやホームページが作成できます。

レスポンシブ対応? について

対応内容は以下です*5

  • User-Agentからスマホか否かを判定する
  • スマホの時は MenuBar と RightBar は非表示にする
  • 既存のスタイルシート設定を上書きする
    • それぞれの padding、margin を減らす
    • max-width を縮小する
    • preタグを横スクロール対応にする(overflow-x="auto"など)


シンプルなページならごまかせる程度には調整できた、はず、です。

これまでの「色の強引な上書き」とは少し事情が異なるのは以下、
JavaScript で画面回転に対応する場合。

document.addEventListener("DOMContentLoaded",function(){
   window.addEventListener("orientationchange", function() {
     // 縦・横が変わった時にサイズを調整しなおすのだけど・・・
     location.reload() // あきらめた
   });

スマホやタブレット端末の場合には縦画面、横画面と2つあります。
つまり、ホームページを表示済みの状態から、さらに画面を回転させた場合にも対応する必要があったりなかったりするわけです が・・・・・・途中までがんばったんですが、あきらめました*6
がんばれる方は、reload(=ページを更新しなおす) ではなくリサイズする処理を入れてみて下さい。


あと、私がすごく苦戦したのは preタグの調整です。
(PukiWikiで「行頭に半角スペースを入れた」とき、テキストをそのまま出力できる書式に使われています)

  1. preの横幅(max-with)を調整する
  2. preの自動改行を無効化(white-space=pre)と
    横スクロールの付与(overflow-x=auto)する

これを逆の順番でやっていたことに気付かずに、画面内に文字をおさめるのに失敗しました。

なぜか max-width からはみ出るのは、どうやら改行無効化の方が勝ってしまっていたようで・・・そしてpreタグが横幅を広げてしまったせいなのか、pre以外のタグまで max-width が効かなくなって・・・
もし画面の横幅調整が上手くいかない場合は、どのタグやスタイルシートを変えるかに加えて、「設定する順番」も見直してみると改善できるかもしれません。


私の場合はスタイルシート上書きで対応しましたが、
本来はやっぱり、最初からスマホ用のスキンとスタイルシートに誘導する方が正しいやり方だと思います。

本格的なホームページを目指す方は、スマホ用の skinと cssファイルの作成にぜひ挑戦してみて下さい。


メモ:svgへのマウスオーバー・イベントを拾う

JavaScriptを解析したい人に向けて、特に分かりにくそうな部分を説明します
以下は「svgで描いたアイコンの色を変えてみた」処理の話です。

(null_i_tomato.skin.php: 390行目あたり)
document.addEventListener("DOMContentLoaded",function(){
 for(var i=0; i<=99; i++){
   var es1 = document.getElementById("navi_svg" +  (i<10? "0" : "") + i);
   if(es1 == null){ break; }
   es1.addEventListener('mouseover', e => {
     var es2 = getElementByEvent(e);
     var tags = es2.getElementsByTagName("path");
     for(var i = 0; i < tags.length; i++) {
       tags[i].style.fill = tags[i].style.stroke = "$COLOR_NAVI_LINK_HOVER";
     }
   });
   (おなじく、mouseoutで色を戻す処理が続く)

イベントリスナーでマウスが触れたのを検知してpathの色を変えたいのですが、イベントはsvgでしか検知できないっぽいのです。
だから svgの子ノード -> path -> style.fillと順にたどる処理を入れました。

getElementByEvent(e) はイベントから要素を拾う自作関数ですが…たぶん、もっと単純に「e.target」を指定するだけで拾えると思います*7

正直、色を変えようが変えそこねようがリンク自体は生きているから、あまり細かいことは気にしなくても良いかもしれません。
以上、ご参考まで。

メモ:hrタグ(水平線)を点灯させる

一部のタグを点灯させる処理の例です。
(以下、実際のコードから少し整形して抜粋)

document.addEventListener("DOMContentLoaded",function(){
 
 (~中略~
   以下、null_i_tomato.skin.php: 560行目あたり)
 
   if(TimerId != 0){ clearInterval(TimerId); } // 起動済みなら前回分を停止
   TimerId = setInterval(cssTimeKeeper, 100);  // 100ミリ秒周期で登録
 }
},false); 

var TimerId=0;
function cssTimeKeeper(){ // 100ミリ周期で呼ばれる関数
    var date = new Date();
    var alpha = 0.5 + (0.5 * Math.sin(Math.PI * 2.0 * (date.getTime() / 8000)));
    var color_h = "rgb(" + $COLOR_HORIZONTAL_LINE_R255
                 + "," + $COLOR_HORIZONTAL_LINE_G255 
                 + "," + $COLOR_HORIZONTAL_LINE_B255
                 + "," + alpha.toFixed(2) + ")";
    var tags = document.getElementsByClassName("full_hr"); // <hr class="full_hr"> を対象にする
    for(var i = 0; i < tags.length; i++) { tags[i].style.borderColor = color_h; }
    (以下、省略)

Math.sin というのは…高校の数学で習う(?)あれです、サイン、コサイン、タンジェントのsinです。
PIは 3.14のやつで…とにかく sin を使って -1 から 1 の間を行ったり来たりする数値を取得しています。*8

ここでは「8秒(8000ミリ秒)周期で0から1を行ったり来たりする」変数alphaを作っています。
続く toFixed(2) は小数点第二位までを取得する関数です。

その結果をスタイルシートの 「rgb(赤, 緑, 青, 透明度)」 という書式にあてはめます。*9

ここまでやって、ようやく、hr(=横線)がちょっと点灯します。パッと見ても気づかないくらいに。

いっそ透明度だけでなく色をユワンユワン変えたい場合は、赤(R)、緑(G)、青(B)のそれぞれを変動させることもできますが……やり過ぎると目が疲れるホームページになるので、変更するならほどほどにどうぞ。

ここでは透明度変更を例示しましたが、同じ方法でsvg(絵)の内容も時間経過で変えています。
尻尾をふったり、手を振ったり、文字をスクロールさせたりが可能です。

ちなみに、
「document.addEventListener("DOMContentLoaded",」が自分の作成コードやプラグインで使用済みだったりする場合は、
私のコードの方を「window.addEventListener("load",~」とかに変えれば衝突を避けられます。

少し複雑そうに見えますが*10
つまり、時間に合わせてスタイルシートを上書きすると楽しいよ、というお話でした。

いろいろ試して遊んでみて下さい。

画像ファイル V.S. SVG?

私も最初は誤解していましたが、ものによってはSVGで描画する方が早いです。

自分でお絵かきしたことがある人は実感したと思いますが、画像ファイルってドット絵のイメージなんですよね。
絵描きさんの作業風景とかで、微修正するとき画像を拡大して直すじゃないですか。
あれです、最大まで拡大すると「絵」が「点の集合」だと分かるはずです。

すごく簡単なアイコンでも軽く数KBくらいのサイズになるのは、最低でも「点」を「数百個くらい」は打たないと絵として成立しないからです。
つまりアイコン一個表示するのに、Webブラウザが(?)数百個、ドットを打ってるわけです。

その一方でSVGだと多くても1KB未満にはなると思うので、軽さのケタが違います。
私のサンプルはあえて数字を直書きしてるので見た目が重そうですが、あれも本来はSVGを別ファイルにしてインポートする書き方にすれば、画像読み込みと同じ見た目になります。

文字フォントデータがSVGに近いイメージです。
文字サイズを変えても字体が粗くぼやけたりしないように、SVGは拡大縮小に強いのが利点です。
でも、写真や風景をSVGで表現するのは不可能です。
だからゲームアプリとかは、ここぞというシーンだけ美麗な画像をばーんと表示していると思います。
(ぜんぶ画像をバーンと入れると、ダウンロードサイズが異常な大きさになります)

ようは、どっちが良いかではなく、使いどころだと思います。

参考までに、このサイト(null-i.net)のPC版画面で、左上でふよふよ浮いたり、まばたきしたりしているアイツが、画像ファイルではなくSVGです。
(動きの滑らかさは秒間フレーム数の問題ですが、そこは自重してます)
サンプルスキンの場合は、こちらのサンプル の左上アイコン、文字のまわりを星がくるくる回ってるのがSVG描画です。
TITLE_LOGO_SPECIAL 変数をcat や dog にするとネコやイヌになります。ムダに動きを付けたからsvg の記述も長くなりました。


以下、作り手さん向けに書くと(余談です)。


私が配布しているサンプルは、オリジナルとdiff差分をとることを想定していました。
自作する際に、どの辺をいじれば良いかの参考にしてもらえるように。*11

自分でガッツリ作りたい人は、必要な部分をピックアックして参考にして下さい。
ご覧の通りサンプルには実験的に、動的に色や画像を変えるという「人によっては要らない機能」も入っていますので。
(何も直さずそのまま使っても、それなりに軽いとは思いますが)
ちゃんとリファクタリングして、可読性上げたりサイズをコンパクトにしたりしてください。

そして新しいオリジナルのPukiWikiスキンを作って、ぜひ盛り上げてください。




*1 参考まで、cssファイルを変更してもWebブラウザによっては即時反映されない場合があるようです・・・・・・colorを変えたのにぜんせん反映されなくて、しばらくの間、自分の目の方を疑っていました・・・
*2 svgはGIMP Portableを使って描きましたが、パス描画とsvgエクスポートができるフリーの画像エディタなら、どれでも作成できます。
*3 数字の羅列を見てもどんな絵なのか分からないという欠点(?)もありますが…
*4 特にバージョンを公開する場合は、必ず常に最新のものを適用するようにしましょう。古いバージョンを使ってることを表示してしまうのは脆弱性を見せているようなものなので。
*5 このメモからは割愛しますが、phpソース内では is_small_sceenという変数で管理していますので、興味がある方はこの単語で検索してみて下さい。
*6 調整箇所が漏れているのか、window.innerWidth で最新の幅が反映されない場合がありまして・・・
*7 昔はWebブラウザごとに動作が違っていた頃があったので、念のために。
*8 秒数そのままではなくsinを使うことで、色の変化に波というか、緩急がつきます。
*9 透明度にはOpacityという変数もあるのですが、こっちはWebブラウザによっては未対応なのです。
*10 それは作者のコーディング力が足りないせいです。
*11 1ファイルにしたのは遊び心ですが、参考にするコードが複数ファイルに散らばってるのは探すのが面倒くさいだろうな、という思いもありました。