サイト構築で画像関連機能

ウォーターマークをいれた画像を半自動で用意する

Gist

ウォーターマークのベースはさすがに自動生成できるレベルにはなかったので、Inkscapeで作成した。
縦と横の二種類を用意している。

fig/にはオリジナルサイズの、thumb/にはサムネイルサイズの画像を配置するが、この時にcompositeを使ってウォーターマークを合成している。

また、幅1600pxを越える画像はリサイズしている。

@figbaseuriの不完全さ

PureDocにもわずかな変更を加えたが、これはattrを排除するためにすぎない。

大きいのはParser::PureDocにおける

        # Other settings for PureDoc
        begin
        if config[:purebuilder_config][:puredoc_tune].kind_of? Proc
          config[:purebuilder_config][:puredoc_tune].call(::DOC)
        end
        rescue
          STDERR.puts "!!ERROR in PureDoc TUNE:" + $!
        end

という変更だろう。

これによって、@config[:puredoc_tune]を使って各PureDocオブジェクトに対して設定が可能になった。
これはMarkdownドキュメントに対しては無効となる。

Gist

「各article要素を取得してループ→各要素に対して各figure要素を取得してループ→イベントリスナー追加」という単純な構造ではある。

ライトボックス用に用意されたimg要素のsrcを変更し、さらに最大幅と最大高をウィンドウサイズに合わせてから表示する、という処理が追加され、ちゃんと機能するものになった。

figure要素に入っていないものはサムネイルの構造を持っていないとみなす方式。

新 Aki SI&Eサイト構築と、納得できないCSS解釈

作り直してるよという話はしていたが、ついに全面刷新となったAki SI&Eの作成に着手した。

昨日1日でlightboxプログラムを作り、さらにメニューボタンアニメーションを作った。

Lightboxアプリケーションは作った時点で1kBを切っており、相当軽量な内容になっていた。
JQueryなどは使っていない。

(function() {
  if (! document.addEventListener ) { return false; }
  
  var wrapper = document.getElementById("WrapWindow") /* ModalWindow */
  var fadingTimer = false /* IntervalTimer */
  var alpha = 0.0 /* ModalWindows's alpha number */

  /* draw content */
  var displayContent = function() {
  }
  
  /* fading out (interval callback) */
  var fadeout = function() {
    if (alpha < 0.8) {
      alpha = alpha + 0.05
      wrapper.style.backgroundColor = "rgba(0,0,0," + alpha + ")"
    } else {
      clearInterval(fadingTimer)
      fadingTimer = false
      displayContent()
    }
  }
  
  /* set this for event callback */
  var setLightboxTrigger = function(e) {
    wrapper.style.visibility = "visible"
    fadingTimer = setInterval(fadeout, 30)
  }

  /* Return from lightbox */
  wrapper.addEventListener("click", function(e) {
    if (fadingTimer) {
      clearInterval(fadingTimer)
    }
    wrapper.style.backgroundColor = "transparent"
    wrapper.style.visibility = "hidden"
    alpha = 0.0
  }, false)

  
  document.getElementById("SideNotes").addEventListener("click", setLightboxTrigger, false)


  
})()

基本的な作りはごく単純だ。
htmlbodyheight: 100%;を持っていて、

<section id="WrapWindow">
</section>

#WrapWindow {
  visibility: hidden;
  z-index: 10000;
  background-color: #000; /* for RGBa Unsupported browseres */
  background-color: rgba(0,0,0,0);
  min-height: 100%;
  min-width: 100%;
  position: fixed;
  top: 0px;
  bottom: 0px;
}

となっている。これにより見えていないし触れることもできないが見えている画面より手前に全体を覆うブロックがあり、これがvisibleになることで全体を覆って操作不能にする。

プログラム全体を関数で書こうことで、全体でアクセスできるプロパティを外側に伝播しないように閉じ込めることができる。「クロージャを作ることで変数をローカル化し直ちに呼び出す」というテクニックは、オライリーのJavaScriptで紹介されている。

グローバルな値としてfadingTimeralphaが定義されている。
fadingTimersetInterval()オブジェクトを格納するためのものだ。これをどこかにとっておかないとclearInterval()することができずに困ってしまう。

イベントが発生した時にfadingTimerが真か偽か、によって判断を変えることができる。
fadingTimerが真の状態で呼ばれる可能性があるのは、#WrapWindowに対するクリックイベントだけだ。
なぜならば、fadingTimerがセットされる前に透明なだけでvisibilityはvisibleになっているので、クリックイベントは必ず#WrapWindowが取る。もちろん、なんらかのブラウザの不備でクリックされる可能性はないではないが。
では、「これから真になる、まだ偽の状態で発生するか」というと、真になる関数が走った時点で、JavaScriptはシングルスレッドなので、真になるまで他のイベントを発生させても実行されないので関係ない。
操作に対するフリーズタイムを短くするためにsetTimeout()を使うこともあるくらいだ。

文字列(evalされる)の登録でなくコールバック関数の登録をするためには、intervalで呼ばれるコールバックで繰り返し使われる値を覚えておくことができないので、これはコールバック関数に対してグローバルでなくてはいけない。
そのための値がalphaだ。

1.0になれば終了なのでその時点でclearIntervalだが、まだインターバルタイマーが動作している状態で#WrapWindowがクリックされる可能性はある。これが真の場合だ。

では、その場合どうするかというと、インターバルタイマーの状態に関わらずオーバーレイを消す。そのため、インターバルタイマーが働いていればclearIntervalしてしまう。

なお、最後に追加しているイベントは本番用ではなくテスト用だ。

CSS

今回の目玉のひとつが、main, article, section, header, footer, asideといった「HTML5への対応」だ。
私のサイトにある大量のdivを少しでも減らしたいからなのだが、HTML5への対応は様々なメリットがある。
一方でレガシー環境を切り捨てることになりそうだったので慎重に対応してきたが、NN 4.6相当でも動作しそうな見通しがたったので採用となった。

それはともかく、納得できない振る舞いに随分悩まされた。

        <div id="SideContent">
      	<section>
             <nav id="Toc" class="toc marginbox_main contentbox">
               <h1>目次</h1>
               <ul>
                 <li>ページナビゲーション</li>
               </ul>
             </nav>
        ...
        </section>
        </div>

div, section, nav、あるいはそれらが内包する全てのテキストに対してfont-sizeの相対的変更(80%など)をすると、ボックスが上下とも縮まり、左カラムと位置が揃わなくなる。
インスペクタで見ると、table-cell要素の#SideContentの位置は正しいが、sectionのマージン上辺と#SideContentの上辺の間に隙間ができる。

また、中に入っているボックスの上マージンを削ると、ボックスの高さがそれだけ減ってその分上に隙間が空く。
配置は関係ないらしく、またこれはpaddingが設定されている場合のみ発生する。
paddingを設定したボックスに内包されるブロック要素のmarginをいじるのは、高さを意識する必要がある場合は厳禁ということか。

        <section id="MainArticle">
          <article class="marginbox_main contentbox">
            <h1>記事のタイトル=章</h1>
                ...
          </article>

このh1のマージンを設定するとその分articleが下がる。
h1より上にボックスを置くとボックスは伸びるが、その分右カラムが下げられてしまう。

恐らくは「h1を特別扱いしている」のだろうと思う。
だが、このためにh1を修飾することが非常に難しい。

結局position: relativeにしてずらした。上以外のmarginについてはこうした問題はない。

PureBuilder2を使ったリニューアル(1)

PureBuilder1のサイトがPureBuilder2で動作するように調整すると共に、PureBuilder2の機能を検証する作業を開始した。
現在はサイトの更新が滞っているので、それが完了すれば効率的に更新できるようになる。

ただ、従来は設定ファイルにロジックを組み込む形だったため、変更点は大きく、そのまま持ってくるというわけにはいかない。
そもそも、PureBuilder1が十分なツールでなく、ツールをサイトごとに書いて完成というものだったのが問題なのだが。

まず、PureDocドキュメントはそのまま持ち込むことができる。
従来の.rebuild_rulesファイルや、ReasonSetにおけるglobal.rcファイルに変えて、.purenuilderrc.rbを用意することとなる。

おおよそそれでいいのだが、既にrcファイルで組み込んでテンプレートで利用していたような情報は.purebuilderrc.rbファイルに組み込まなくてはいけない。
また、これによって従来環境変数で処理していた物を、DOC.pbenvを使うように整合性をとらなくてはいけない。

このデバッグ作業に伴って、Purebuild Allに.rebuild_all_timeを無視して全てを対象とする-cを追加した。

そして、問題になったのがプロフィール部分だ。

これまで、プロフィールは単独のRubyスクリプトだった。rebuild_rulesから呼ばれることを爽亭しているため、設定は環境変数を通じて受け取ってはいるが、ドキュメントの生成、テンプレートへの埋め込み、そしてファイルの出力までプロフィール自体で行っていた。

しかし、これをそのままにできるわけではない。
設計上、これをPureDocであるとみなした処理したほうが早い。
だが、問題として、設定はあくまでもドキュメントを生成したあとに使えるようになっているため、ドキュメント内で使うことができない。PureDocを拡張してPureBuilder向けスクリプトにすることがかなり難しいのだ。

DOC内の@bodyStringまたはArrayという扱いだったが、実際にStringだと参照時に@body.joinを呼ぶためエラーになってしまう。この点については、PureDocのほうを修正することとなった。

こうした拡張がいまいちしづらいことを考えると、修正が必要かもしれない。
また、既存のPurebuildスクリプトを用いるのではなく、DSLによってビルドを指示できる仕組みも追加すべきだろう。

SIサイトの細かなモバイル対応

概要

特にサイトのデザインをいじる気はなかったのだが、 写真を使ったページを縮小した時に画像がはみだしてしまう、という問題があり、 モバイルフレンドリーの観点から修正を実行した。

だが、実際はかなり根が深かった。 結局、PureDocの改修を含む大掛かりな作業になってしまったのだ。

配置方法

私のサイトは見た目はシンプルだが、実際は結構複雑なことをしている。 特にSIサイトに関しては、かなり難しいことを実験している面がある。

SIサイトの難しさは、やはり「レスポンシブデザインで右カラムが上にくる」ということにある。

CSSで指定する場合、左右に並べるのは必ずしも左が先でなくても配置できるが、これを上下にする場合は基本的には「先にくるものが上」になる。 そのため、SIサイトではサイドバーである右カラムがHTML上は「先に」書かれている。

だが、左カラムが先にこない、ということは、左右に並べるために

display: table-cell

が使えないということを意味する。

となると使用できる方法はかなり限られてくるのだが、 しかも高さが一定でない上に、「チェックのボーダー」は親要素の背景になっているため、absolute配置を利用して並べてしまうと、要素の高さが維持されない。 また、両方とも高さが固定でない以上、ネガティブマージンを使う方法も取れない。 floatを使う方法が、事実上唯一だと思われた。

実際に、この問題は試行錯誤の末、既にfloatを使う方法を用いている。 だが、それでもうまくいかない部分があった。

widthとpaddingとmarginの関係

基本的にはwidthをまず確保し、そこにpaddingとborder-widthとmarginを足す。 全体幅を指定したい要素に関しては、それらを0にした入れ子要素を用意するのが無難だ。

しかし、100%の幅を用意したい場合、width: 100%を指定すると、必然的に親ボックスからはみだすことになる。 なぜならば、この時点でコンテンツの幅は親ボックスいっぱいまで確保されていて、その外に足すことになるからだ。

ところが、paddingに相対値を指定すると、paddingはwidthに含まれるのが普通。

つまり、padding: 1em;とした時は、ボックスの外に1emを足すことはしない。 paddingのボックス相対(主に%)を使用する場合、親ボックスはその要素のようだ。 つまり、paddingに25%を指定すると、ボックスの内側50%にコンテンツボックスが生成される。

だが、paddingは相対値は普通にあるが、marginはレイアウトボックスではあまりない。 border-widthに至ってはまずない。

そのために、widthの相対値がとても使いにくい。 UIデザインはスケーラブルな時代になってきているはずなのだが、ウェブの場合、結局スケーラブルな値ではなく、 スタティックなピクセル値を自分で計算して書いて、それに対してスケールするという美しくないことになっている。 しかも、その中にピクセル値に対して曖昧な物理絶対値(特にフォントのポイント指定)を含むのでぐっちゃぐっちゃだ。

結局は全てスタティックなピクセル値に書きなおした。

  • #MainContainerはW850+PAD50+MGNautoで950pxボックス
  • #TopPanはwidth838+border6の850pxボックス。HTMLに直接指定されていたPADは除去。
  • サイズ調整は入れ子のh1要素による指定に変更
  • #LeftPageは590pxでPADauto, MGNは0
  • #SideBarは225pxで左に35pxのMGN。PADは0で、#LeftPageと合わせて850pxボックス
  • つまりカラムの間のボーダーは、サイドバーのMGNが持っている

なぜ画像のmax-widthが効かないのか

厄介なのが画像だ。 画像は既にwidthやheightのボックス相対指定でスケールするようになっている。 一般的にはmax-width: 100%を用いるのだろう。

だが、そもそもの発端はmax-width: 100%が効かない、ということだった。

なぜ効かないのか。実はGeckoでは親要素がピクセル値を持っていなければ画像のwidth/height系プロパティを無視するのだ。 例えば親要素がボックス相対値であっても、その親要素はスタティックなピクセル値ならば問題ない。 例えば幅600pxのボックスに入れ子にされた幅100%のボックスの中であるならば、 画像は600pxに対する幅になる。これは、max-*のプロパティでも効く。

だが、親ボックスがピクセルで固定されたボックスに入れ子にされていても、max-*プロパティで決定されていると効かない。

これがBlinkだと問題ない。例え相対widthの中のmax-widthで決定されたボックスの中であれ、max-width: 100%;を指定すればちゃんと効く。 モバイルでGeckoを使っている人は恐らく少数派なので、あまり問題ない、とも考えられる。

だが、単純なテストを行うと、そのような問題は出ない。 例えば

<html>
<head></head>
<body>
<div style="width: 50%">
<p>
<img src="file:///home/aki/share/pic/vlcsnap-2015-05-12-02h05m49s780.png" style="max-width: 100%;" />
</p>
</div>
</body>
</html>

のようなだ。そこで色々試したのだが、

  • inline-blockの中では画像のwidthは効かない。これはGeckoでは効かないがBlinkでは効く
  • block要素の中ではfloatされている要素は高さを持たないが、inline-blockの中では持つ。これはGecko/Blink共通

ということが分かった。

多分だが、これは明確な仕様にはなっていない。曖昧な部分なのだろう。 仕様に準拠した「論理的な記述」からはかけ離れているが、実際の挙動に合わせて意図した通り動かすため、 #UnderContainerを950pxを超える場合はinline-blockに、950px以下ではblockになるようにした。

その他の修正

Webfontの修正

SIではなくReasonSetのほうで使用しているwebフォントのロゴたいぷゴシックだが、OTFのほうがグリフはかなり多いのだが、かなり空白グリフがある。

空白グリフというのは結構な問題だ。というのは、通常、グリフがない文字についてはフォールバックされ、他の代替フォントを使用して表示する。 そのため「表示されないから読めない」ということは避けられるのだが、空のグリフが存在していると結局空白を表示してしまうため、文字が表示されないため見えない。

空のグリフは削除してしまうのが望ましい。 これを問題にしたのは、「精悍」の「悍」の字が出なかったためだ。

これをcockscombさんのGitHubコード を使用して修正した上で再生成してこの問題を修正した。

PureDocの修正

PureDocのPuredoc::XHTPureDoc.stdメタメソッドがオプショナルなパラメータを正しく解釈しなかったため、修正した。

これはPuredoc::XHTPureDoc.getoptionsメソッドが戻り値をちゃんと指定していなかったためである。

原稿のGitリポジトリ

原稿はCodebreakで草稿も含めて公開しているが、 久しぶりに更新した。若干歴史にも改変を加えたが、ゴミの除去が主だ。

プロフィール

プロフィールに部活の履歴を追加し、 項目としてBiographyを加えた。

サイト/サーバーに関する作業

HTTPSの無効化

HTTPでのアクセスを推奨しつつHTTPSのアクセスを可能にしていたのだが、証明書エラーを気にする方が多いので、そもそもHTTPSアクセスを無効にした。

HTTP推奨、HTTPS対応、SSL証明書無効というのは、実はUFJ銀行と同じなのだが(amakai.netの証明書を使用している。ゆうちょ銀行も似た方法。ちなみに、三井住友とりそなはNot Foundを返すようになっている。みずほはHTTPSが稼働していない)、どうしても警戒するらしい。

問題は、現代的なブラウザはスキームなしだとHTTPSから試してしまう上に、無効な証明書に対してセキュリティソフトが警告を出すこともあるためだ。

私の個人サイトだけなら別にいいのだが、仕事のほうのサイトでは受注に響く可能性が高い。そのため、そもそもHTTPSを無効化するという措置をとった。HTTPSは技術要求的な意味合いが強く有効にしてきたが、証明書の問題はコストの問題となるため、かなり難しい。もちろん、その構築が複雑である、という問題もある。

MozillaとEFFが、無料で簡単にHTTPSを使えるようにするためのものを用意しているらしいので、それに期待するしかない、といったところか。SSL証明書に関する悪質な利権主義が私は大嫌いだ。一部の人たちが「私達が認証局です」と名乗り、その身内か大金を払ったところが認証局となり、認証してほしかったら金を払えという。SSLの認証の仕組み自体が、利権を生むために作ったものだとしか思えないひどいものだ。

だからSSL証明書をとることは、金銭的にだけでなく、心理的にもかなり嫌だ。

PCの基礎知識の講座up-to-date

彼女にPCに関する知識をつけてもらわないといけないので、全然な人が日々覚えていくことで私の実務に使える知識が身につく講座をスタート。

メールで送っているものを転載している。

http://reasonset.net/chienomi/essay/articles/steady-study.html

CSS

CSSを更新したのだが、気づいたことがある。pre-wrapに設定されている場合などで、「折り返した行をインデントする」ということができない。だからおそらくはJavaScriptで論理行に交互に色付けすることが一般的になっているのだろうと思うが、それはあまり好みではない。

wrapされた行を指定するセレクタ、あるいは要素中の論理行を表すセレクタが欲しい。

サイトの大幅手直し

ウェブサイトに直すべき点が大量にあったためにかなり手をいれることになった。

CSSグラデーション、デザインの修正

まずベンダープレフィクスを用いたCSS3のグラデーションを入れた。

/* headline level2 decoration */
h2 {
width: 100%;
background: -moz-linear-gradient(left -65deg, #fff, #acf);
background: -webkit-gradient(linear, left top, right bottom, from(#fff), to(#acf));
}

これはAki SI&Eのほうのもの。これを使い、サイトロゴは透過画像として(新規に作成した)、背景にグラデーションを入れた。画像はフォアグラウンドのイメージ

/* Header container (Top position of Main container) */
#Header {
background: #fff;
padding: 0 1.3em;
max-height: 125px;
}

#SITE_REASONSET #Header img.sitebanner {
margin-right : 40%;
width: 50%;
}

#SITE_REASONSET #Header {
background: -moz-linear-gradient(left -65deg, #f0f8ff, #acf);
background: -webkit-gradient(linear, left top, right bottom, from(#f0f8ff), to(#acf));
}

SI&Eのほうはメインコンテナが950pxとっているのに切り替えを750pxにしていたのでこれも修正。

Aki SI&Eのほうはキャプチャのスタイルを変更。

h1 {
border-top : double 5px;
border-bottom: double 5px;
color: #39f;
margin-left: -1em;
margin-right: -1em;
margin-top: -0.8em;
text-align: center;

}

マイナスのmarginはあまり見ない気がする。このようなデザインはほとんど見ることはないが、なかなかパッとみてすっきりと見えて目を引く良いデザインだと思う。このために、テキストインデントのマイナスは消した。テキストインデントのマイナスは一行目にのみ適用されるらしい(brで改行すればその都度適用されるのだろうが、折り返しには適用されない)。

サイトバーウィジットの変更

AKi SI&Eが先行で変更され、それがReasonSetに反映され、さらにReasonSetで追加された機能がAki SI&Eのほうに入った。

<!-- Sub column -->

<!-- Menu -->

-*- Menu -*-

<%= ENV["SUBCOLUMN_CONTENT"] || "" %>

<!-- Notes if any -->
% unless DOC.notes.empty?

-*- Notes -*-
    % DOC.notes.each do |note|

  1. <%= note %>
  2. %end

% end

<!-- Navigation links with PureDoc and PureBuilder template -->
% if DOC.meta["link"] && ( DOC.meta["link"]["next"] || DOC.meta["link"]["content"] || DOC.meta["link"]["prev"] || DOC.meta["link"]["start"] )|| ENV["reasonset_link_content"] || ENV["reasonset_link_start"]

-*- Referrances -*-

% end

<!-- / Sub column -->

このために、これまでSubCloumnコンテナ直下にメニューがあったが、それとcontent_boxクラスを分離して、同クラスのdiv要素を追加している。

/* White background */
.content_box {
background-color: #fff;
}

/* Padding for continuous content box. */
.content_box + .content_box {
margin-top: 11px;
}

Aki SI&Eのほうはもう少し手の込んだものになっている。

#SideBar .container {
padding : 1.28em;
}

#SideBar .container:last-child {
margin: 0;
}

CSS3の:last-child擬似プロパティを使うことで最後が間延びしてしまうことを防ぎながら、要素を分離してチェックをみせるようにしている。

注釈をサイドバー内にも表示するようにした他、内容的にはこれまでコンテンツ側にあったACCSのserial articleのreferranceをサイドバーに表示するように変更した。

レイアウト方法の変更

これでサイドバーが長くなったのだが、なぜかこれではメインコンテナが短縮されてしまう。あくまでメインカラムの高さに合わせるのだ。構造としては

なのでこの挙動は謎だが、MozillaでもBlinkでも同様の挙動を示す。

floatすると一見うまくいくようだが、逆にサイドカラムの高さに合わせてしまい、メインカラムが突き抜けてしまう。また、幅もきちんと規定しなくてはいけない。

結局、3者全てinline-blockにしてしまえば高さは正しく確保される。ただし、これでは2つのカラムはmarginがとられないためぴったりくっついてしまう。

そこでこれをmargin, padding, border-widthが全て0のコンテナとし、paddingは別のブロックで確保する。paddingは設定してもよかったのかもしれないが、このほうが管理しやすい。

エッセイ用のほうが先行して開発されたので、構造が甘かった。ReasonSetはもう少し安定しているが、やはり作りなおしたほうが良いと思われる。ちなみに、ReasonSetが安定しているのは、高さが規定されているためでもある。

ここまでしたのだが、inline-blockで幅を%指定だとGeckoでは見られるが、Blinkでは上下にレイアウトされてしまう。ピクセル指定にすれば大丈夫だが、relativeにした上でレイアウトし、さらにfloatすれば%指定でもBlinkで正常に表示される。

ACCSの修正

まず、TOC機能がエラーになるようになっていた。以前はRuby2.0でやっていたが、2.1になったからだろうか?どうも、クラスが違うオブジェクトを持つArrayを比較しようとしている、ということらしい。文字列しか格納しないように思うのだが、一応to_s

essaies.push [ sortitem.to_s, fp.to_s, meta["title"] ]

TOCに戻るリンクが間違っていた。これは、設定ファイルがreasonset_link_contentsとしているのに、テンプレートはreasonset_link_contentとしているという単純な理由だった。これは、HTMLのlink要素に対応するのでcontentsが正しい。ちなみに、Essayにはその機能がそもそも含まれていなかった。

そして、ACCS記事間のリンクが機能しない。Talkin’ About(Aki’s Palace)との違いが見つからず、一体…と思ったのだが、grepしてみるとその設定はrbutilに含まれており、chienomiが専用で使っている。chienomiのリンクが機能していたので、当然Talkin’ Aboutでも機能しているものと思い込んでいたが、実際はTalkin’ Aboutでは機能しないわけだ。単に記事がひとつしかないので気づかなかっただけだ。

基本的にはACCS記事内でそのスクリプトをロードすれば機能するのだが、ロードすべきスクリプトが存在しない。chienomiのものはパスがハードコーディングされている。そのため、それを修正したバージョンを用意した。

また、「最初の記事」だが、

export reasonset_link_start="si/$wd_element/${artdir:+${$(print $artdir/*.pdoc):r}.html}"

となっていた。Talkin’ Aboutでは機能していたが、これは記事がひとつしかないからだ。つまり、複数のファイルがあると、それが連なった文字列(スペース区切り)の最後だけpdocをhtmlに変えることになってしまう。

当然、先頭のファイル名のみをとり出さなくてはいけない。(#q[1])で機能しなかったので、

export reasonset_link_start="si/$wd_element/${artdir:+${$(print -l $artdir/*.pdoc | head -n 1):r}.html}"

と変更した。単純な方法だが、そこまで繰り返し呼び出すわけではないので、head(1)を呼び出す程度どうということはないだろう。

ノートインデックスの作成

ノートのインデックスを作るため、まずPureDoc側を修正。その機能をスーパークラスに追加。

### Notes ###
# Add note text to an array
def addnote(note)
@notes.push note
end

attr :notes

サブクラスで呼び出し

# Note
def n(text, ¬e)
puredoc_element(:n) do
note = note.call
addnote note
'%s</pure:note>' % [esc!(note), esc(text) ]
end
end

ちなみに、HTMLクラスタイプだけノートとテキストが逆になっていた。どちらが正しいのかよくわからなくなっている。仕様を規定すべきだろう。

そして今修正した。

def n(note, &text)
puredoc_element(:n) do
addnote esc!(note)
'%s</pure:note>' % [esc!(note), esc(text.call) ]
end
end

これでノートインデックスの作成が可能になった。だが、これに対応した表示が本文に必要だ。これはCSSに任せる。

body {
counter-reset : notes;
}

/* Note element */
.puredoc_note:after /*, puredoc|note:after */ {
vertical-align: super;
font-size: 80%;
content : "\002020" counter(notes);
counter-increment: notes;
text-decoration: none;
}

content中の文字参照はどうするのだろう、と思ったら、16進数にした上でクォート内で

HTML * CSS 美しいフレームをもつカラムスタイルレイアウトの難しさ

私のサイトをみるとわかるのだが、ボーダーが画像になっている。これをどうやって作るのか、というとごくごく単純で、背景画像を持つdiv要素に入れ子で白背景のdiv要素をおいているだけだ。ちなみに、外側のdiv要素にpaddingを設定するのが正しいやり方だ。

ところが、これで左右カラムを置き、しかもその中にブロック要素をおこうとするとかなり難しい。floatを使って配置すると、内側のブロック要素は親要素のブロックを突き抜けてくっついてしまうのだ。普通なら左右カラムはくっついて配置されて構わないものだから、このような挙動は気にしないのだが、今回の場合、左右カラムの間に空間を作ってボーダーを表示したいため、工夫がいる。

とりあえず、まずは縦に並ぶブロックを分けろ、だ。左右カラムはブロックの中に入れて左右分割すべきだ。でないととても苦労する。

さて、問題の比較的単純な解決策はfloatを使い、左右それぞれにfloatし、かつ重ならないようにwidthを設定する方法だ。だが、私はfloatを使う方法があまり好きでない。なんらかの理由で重なってしまうと後に書いたブロックは後ろにいってしまうという、表示への影響が大きいからだ。

そのため、私がとった方法は

  1. static配置では中のブロックに対してabsoluteが使えないので外のコンテナはrelativeで配置
  2. 右に配置されるサイドバーコンテナを先に書く
  3. サイドバーコンテナはabosluteで配置。widthz-indexを設定
  4. メイン部分コンテナはrelativeで配置。同様にwidthz-indexを設定
  5. サイドバーコンテナ、メイン部分コンテナ共に内側に入れ子のコンテナを配置(白背景)
  6. 外のコンテナのwidthpaddingでボーダーを適切にする。つまりギリギリにしないほうが良い
  7. サイドバーコンテナにmax-height、メイン部分コンテナにmin-heightを設定。サイドバーコンテナはoverflow: auto

簡単な話なのに複雑、と感じただろうか。実はそう簡単ではない。確実に正確な位置に配置しようとすると、floatしないならabsoluteで置くしかない。ところが、そうしようとするとstaticのまま親コンテナが配置されていてはいけない。

サイドバーコンテナを先にするのも理由はあるが、別に好みだとは言える。

widthの設定はもちろんかさならないように、またボーダーのサイズを調整するためで、z-indexは万一重なった時のためだ。

入れ子にするのは白背景とボーダー調整のためだが、この方法ではなくてもできる。

さて、なぜ両方absoluteにしないかというと、そうするとこのブロックは高さ0であるとみなされ、下側のボーダーが出ない(下にフッターを配置した場合、それも出ない)。そのため無限に長くなるメインのほうをrelativeにしているのだが、そうすると本文よりもサイドバーが長くなるときに支障が出る。そこで、サイドバーの最大長を制限すると共に、本文の最低長を要求することで、サイドバーのほうが長くならないようにしている。

別に「すごく難しい」という話ではないのだが、これはなかなか出てこない話だ。というのは、かなり技術的なことをしているが、それは構造的、意味的なものではなく、完全にデザインのための記述だ。デザインのための技法というのは技術者にはなかなか身につかない。そして、デザイナーがデザインを実現するための技術もそうそう思いつかない。ボーダーに画像を使いたいと言われた時、エンジニアがそのような機能はないのでできない、と言ってしまう可能性もある。今回やっていることはどちらかというとデザイナー主体のことで、デザイナーがそれを実現するための技術的知識があるか?というところが問われる。

このようなデザインは非常に個人サイト的で、商業サイトではトレンドもあるためこのようなデザインを採用することはない。というよりも今は非常にDHTML流行りなので、そもそもアクセシビリティ自体がナンセンスのように言われることも少なくないし、こうした指向がないために見かけないのかもしれないが、アクセシビリティとデザインを両立し、独自性があり、かつ習慣に基づくなじみやすさを満たす、というこうした技法は、そうしたサイトをみないだけに抜け落ちるポイントになっているのではないか?と思う。

今回は他の方法もあるにはあるのだが、これが最もアクセシビリティが高い方法だと思う。個人的には、最新のウェブブラウザでなければ見られないようなサイトは好きでない。

なお、現状公開しているサイトはこの仕様になっていない。現在テンプレートを修正したところだからだ。恐らく、本体ウェブサイトではなく、商業ページのほうが先にこのレイアウトを採用するだろう。現在の本体ウェブサイトは類似のデザインを採用しているが、バグがある。


/* Skin CSS for general essay.
* This is used by essays independent from the site.
*/

/* Top definition */
body {
background: #fff url("//reasonset.net/img/wp/heartline.gif") repeat-y 15% 0% scroll;
font-size: 10pt;
color: #39f;

}


/* Main Container. Over all container. */
#MainContainer {
width : 950;
margin : 0 auto;
background: #e0f0ff url("//reasonset.net/img/wp/check_bp.png") repeat scroll;
font-family: "Rounded-X M+ 2c","Migu 1C","M+IPA+2VM circle","Gen Jyuu Gothic Normal","VL P Gothic", "Hiragino Maru Gothic", "Meiryo",sans-serif; /* define Japanese Font */
position: relative;
padding: 45px;
}

/* For overwrite font-family for English document. */
#MainContainer {

font-family: serif;

}

/* Top banner */
#TopBan {
margin : 0px 0px 18px 0px;
font-size: 300%;
padding: 1.3em;
position: relative;
}

#UnderContainer {
position: relative;
}

/* Main content container */
#LeftPage {
position: relative;
top: 0px;
left: 0px;
z-index: 1000;
/*   margin: 30px; */
padding: 0;
background-color: transparent;
/*   border: blue 1px solid; */
width: 650px;
}

#SideBar {
padding: 0;
/*   border: blue 1px solid; */
position: absolute;
right: 0px;
top: 0px;
width: 250px;
z-index: 200;
}

/* Any container. */
.container {
background-color: #fff;
padding : 4em;
/*   border: red 1px solid; */
margin: 0;

}

/* paragraph */
p:first-letter {
text-indent: 1em;
}

p {
line-height: 1.2;
letter-spacing: 0.25em;
}

/* headline to left */
h1,h2,h3,h4,h5,h6 { text-indent: -1.3em; }



<html>
<head>
<link rel="stylesheet" type="text/css" href="./puredoc.css" />
<link rel="stylesheet" type="text/css" href="./puredoc_skin.css" />
<link rel="stylesheet" type="text/css" href="./gen-essay-skin.css" />

</head>
<body>
<div id="MainContainer">

<div id="TopBan" class="container">
Site title.
</div>
<div id="UnderContainer">

<div id="SideBar">
<div class="container">Sometext</div>
</div>
<div id="LeftPage">
<div class="container">
<h1>H1 title</h1>
<h2>h2 title</h2>
<p> p1</p>
<p>p2</p>
</div>

</div>
</div>
</div>



</body>
</html>