anti scroll

ブラウザと小説の新しい関係を模索する

nehan.jsで始めるfunctional stylesheet入門

いつも思うんですけど、

  • CSSセレクタのパスを書いてスタイルを設定する
  • 同じものをjavascriptで取得してイベントを設定する

って二度手間じゃないですか?

どっちもDOMノードを指定して、何かの値を設定するってことですよね。

設定するものがスタイルかイベントかってだけの違いです。

なのに、CSSの作法とjsの作法をそれぞれ別々に覚えて設定するっていうのは、設定がそれぞれ別のファイルに散らばってしまってわかりにくいし、なによりマークアップの変化に弱そうです。

なので一緒に書けたら楽だなあ、などと僕は思うのですが、nehan.jsではまさにそういうことができます。

スタイルとイベントを同時に設定してみる

例えばこんな風に設定できます。

Nehan.setStyles({
  ".nehan-fade-in":{
    "color":"green",
    "oncreate":function(dom){
      $(dom).fadeTo("slow", 1.0);            
    }
  }
});

ポイントとなるのは、oncreateなるコールバックです。

.nehan-fade-inで指定されているノードが実際に作成されるタイミングをoncreateでフックし、フェードインの処理を追加しています。

ちなみにクラス名やId名を「nehan-」で始めるというのはnehan.jsの仕様です。 nehan.jsの外の世界で組版されるものとスタイルを衝突させないための仕様です。

関数でスタイルを分岐

次に、functional stylesheetらしく、マークアップ名で色を分岐してみましょうか。

Nehan.setStyles({
  ".nehan-fade-in":{
    "color":function(ctx){
      var markup = ctx.getMarkup();
      switch(markup.getName()){
      case "h1": case "h2" case "h3": return "red";
      case "h4": case "h5" case "h6": return "blue";
      default: return "green";
      }
    },
    "oncreate":function(dom){
      $(dom).fadeTo("slow", 1.0);            
    }
  }
});

cssプロパティのcolorに指定されている値が関数になっていることに注意してください。

関数を指定した場合は、returnで返したい値を出力します。

独自の文法を作ってみよう!

nehan.jsにはoncreateの他にonloadというコールバックも用意されています。

onloadは「そのセレクタに該当するスタイルを全て読み終わり、これから組版計算を開始する直前」をフックするコールバックです。

言葉にすると複雑なようですが、ようするに具体的な組版計算が開始される前に、マークアップの内容やらCSSの値を書き換えてしまうことで、別の組版結果を導くためのものです。

何の役に立つかというと、例えば独自のマークアップ文法を定義するときに便利です。

TIPというタグを作ってみる

ここでは、クリックするとマークアップで囲まれた内容がポップアップするタグtipを考えてみます。

例えばこんなマークアップをしたら、

<tip title='nehan.js'>名前の由来は「ネイティブ組版」</tip>

その結果として

  • 画面にはtipタグの中身ではなく、title属性に設定された文字列を表示させたい
  • その文字列をクリックしたら、中身の説明文がポップアップするようにしたい

とします。

これを実現するには、

  • tipタグの組版が始まる直前をフック
  • コンテンツの内容をdatasetに退避
  • タイトル属性の内容をコンテンツに上書き
  • oncreateにてtipタグがつくるDOM要素を受け取り、onclickで退避させておいた元コンテンツをポップアップさせる処理を書く

みたいにすれば良さそうです。

実際に実装してみましょう。

Nehan.setStyles({
  "tip":{
    "display":"inline",
    // このタグの組版を開始する直前をフック
    "onload":function(ctx){
      var markup = ctx.getMarkup();
      var title = markup.getAttr("title", "no title"); // title属性を取得。ない時は"no title"が返る
      var content = markup.getContent();
      markup.setContent(title); // 中身をタイトル属性の値に置き換える
      markup.setData("content", content); // contntをdata属性(dataset)に保存しておく
    },
    "oncreate":function(dom){
      $(dom).click(function(){
        alert($(this).data("content")); // onclickで、保存しておいたdata属性をalert
      });
    }    
  }
});

上記は最低限の処理しか書いていませんが、例えば「title属性が入っていない時は無効だから何もしない」みたいな処理を加えても良いと思います。

こうやって好きなように自分のローカルな組版文法を定義し、その振る舞いをプログラマブルに制御できる、というのは通常のウェブ開発では体験できないことだと思いますし、なにより楽しいです。

結論

やはりスタイルも関数で書けると、制作者の意図が伝わりやすい気がします。

これらのスタイル指定を一つのファイルにまとめておけば、自分の作った特殊なタグ機能を他者にプラグインとして公開することも容易です。

面白い機能が作れた人は、是非教えてください。