お久しぶりです。先日月曜日に研修が終わり、配属された部署で1週間を過ごしたわけですが、唯一よくわかったことは……この部署は決して新人が配属されてはいけない部署だということ……! 来週に早速日本を横断する感じの出張、来月には地球を縦断する感じの出張を……長期で……。ぬくぬく内勤ライフを期待してたのになんだこの世界をまたにかけるアドベンチャーっぷりは。光回線でインターネットに接続できる環境とよく動くPCとそれと毎日3時間の自由時間、それだけで、いいのに……!!
先日の『文字列を常にボックス中央(middle)に配置するJavaScript関数』に続きKIGで使う予定の関数を作りましたので、公開します。今回は『文字列を縁取りするJavaScript関数』。
これまで画像に縁取りをつけたり文字列に擬似的に影をつけるJavaScriptの関数は数多く存在してきたものの、何故か文字列を縁取りする関数は作成されたという話を聞いたことがありません。何故か・と言っても、JavaScriptで操作するCSSにそういったプロパティ(設定)がないから、という単純な話ではあります。ですが、webで文章を表示させるときに文字列を縁取りできると見栄えが良くなるのは間違いありません。それをなんとかして実現できたら……きっと素敵です。
そんなわけで、取り組んでみました。以下前回と同じようにサンドボックス(お試し場)をご用意しました。テキストエリアに文字列を打ち込んで、どこか適当なところをクリックしてみてください。
左の図のように動作することを想定しています。IE7、Opera9.27、Firefox2.0.0.12での動作は確認済みです(IE6は面倒なので未確認、Firefox3[beta4]は自動アップデートで2にダウンデートされてしまったので未確認)。
と、まぁ画像をご覧いただければおわかりいただけるように、かなり微妙なデキとなっています。画像の右側の部分は期待する動作をPhotoshopで加工して描いたものです。実際の動作結果は左側。縁というより陰影ですね。以下ソースコードです。
HanStrings = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,-+=:;/!?\'\"\\#$%&()|';
ZenStrings = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,-+=:;/!?’”¥#$%&()|';
function RimStrings(StringsColor,RimColor,StringsLayer,TargetLayer){
if(!StringsColor){
StringsColor = '#f2f2f2';
}
if(!RimColor){
RimColor = '#333333';
}
if(!StringsLayer){
var StringsLayer = document.getElementById('JS_StringsLayer');
if(StringsLayer.value){
Strings = StringsLayer.value;
}else{
Strings = StringsLayer.innerHTML;
}
}
if(!TargetLayer){
var TargetLayer = document.getElementById('JS_TargetLayer');
}
TargetLayer.style.visibility = 'hidden';
var LayWidth = Number(TargetLayer.style.width.replace('px',''));
var FontSize = Number(TargetLayer.style.fontSize.replace('px',''));
var LetterSpacing = Number(TargetLayer.style.letterSpacing.replace('px',''));
var LineHeight = Number(TargetLayer.style.lineHeight.replace('px',''));
var FontWidth = FontSize + LetterSpacing + 2;
var Capa_OneLineChar = Math.floor(LayWidth / FontWidth);
var DisplayStrings = '<ol id="StringList" style="position:relative;text-align:left;margin:0;padding:0;">';
var StringsLength =Strings.length;
var i = 0;
for(i=0; i < StringsLength;i++){
var String = Strings.charAt(i);
var j = HanStrings.indexOf(String,0);
if(j >= 0){
String = ZenStrings.charAt(j);
}
var StringID = 'JS_Str_' + i;
DisplayStrings += '<li id="' + StringID + '" style="list-style:none;position:absolute;font-weight:900;margin:0;padding:0;white-space:pre;">' + String + '<span style="position:relative;font-weight:100;">' + String + '</span></li>';
}
DisplayStrings += "</ol>";
TargetLayer.innerHTML = DisplayStrings;
for(i=0; i < StringsLength;i++){
var NowLine = Math.floor((i+1) / Capa_OneLineChar);
var NowCol = (i+1) % Capa_OneLineChar;
var StringID = 'JS_Str_' + i;
var DisplayString = document.getElementById(StringID);
var RimString = DisplayString.getElementsByTagName('span');
DisplayString.style.top = NowLine * LineHeight + 'px';
DisplayString.style.left = NowCol * FontWidth + 'px';
DisplayString.style.color = StringsColor;
RimString[0].style.fontSize = Math.ceil(FontSize * 0.9) + 'px';
RimString[0].style.left = -1 * FontSize - 1 + 'px';
RimString[0].style.top = -2 + 'px';
RimString[0].style.color = RimColor;
}
TargetLayer.style.visibility = 'visible';
}
/* この記事のソースにベタ打ちしているので、実際の利用方法などはそちらを参考にどうぞ。 */
処理としてはテキストエリアに書き込んだ文字列を読み込んで1文字ずつ分解し、それをposition:absoluteで絶対配置していくという少々強引な手を使っています。類似の方法として1文字ずつ分解せず段落を丸ごと移動させる、text-indentでスマートに移動させる、といったものがありますが、それだと細かい調整ができないのでpositionプロパティを使った方法をとってみました。
しかしまぁ、うまく配置させたところでキレイに見えなければ意味がありません。今回表示用に使ったフォントはメイリオですが、MS Pゴシックだとさらに微妙な結果に。要するにフォント自体をキレイに見せられないことにははじまらない=現時点では結構どうしようもないわけですね。
現時点でありうる手段としては、文字を1つだけ重ねるのではなく複数、少しずつ色と位置をずらしながら表示させる、というものくらいしか思いつきません。ただやはりフォントごとに文字のカタチの特徴が違うので、調整がとても面倒くさそうです。英数字だけならば文字体をArialあたりで固定して、あらかじめArial向けに加工した画像を50パターン作っておけば済む話なんですけど~。日本語だと最低でも1,000文字を作らないといけませんので、まぁかなり面倒です(バッチ処理させれば作成自体はラクでしょうけれども、表示にもたつきそう)。
また、IEだけの表示に絞るのならばIE独自の拡張CSS・フィルターを使うことで少しは前進できそう。filter: shadow();[陰影をつける] filter: blur();[ぼやかす] filter: glow();[光彩をつける]といったあたりを使えばそれっぽくなりそうですが……一昔前のWordのワードアート機能を見ているようでやはり微妙です。
結論 : かなり難しい
キレイに縁取って表示させるのはかなり困難で、できるとしてもかなり面倒であるようです。大昔に規格化されたにもかかわらず未だに存在感の薄いCSS2のtext-shadowプロパティがIE7(8もたぶん)でもOpera9でもFirefox2(3もたぶん)でも対応されていない現状を考えると、うまく文字列を縁取る表示方法というのは当分のあいだ登場することはないものと思います。と、何年も前から言われ続けている結論にあらためて辿りつきましたとさ。そんな無為な一日。
[追記] まさかのバージョンアップ → Photoshopの境界線チックに文字を縁取るJavaScript関数
2008年08月31日 0時更新
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
|---|---|---|---|---|---|---|
| « 04月 | - | 06月 » | ||||
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
