「簡易的な」 役物詰めを行います。 前回のぶら下がり処理を応用し、 出来るだけコンパクトな設定で実装します。
コンパクト故、 簡易的になります。
役物詰めとは
基本的に、 日本語のフォントは縦横が同サイズの正方形です。 それは役物 (括弧や句読点や中点) も同様で、 正方形の中に字形とアキ (空白) が共存しています。
よって、 役物が表示される際は適度なアキが予め確保されているため、 可読性が高くなります。
しかし、 役物が連続するとアキも連続してしまうため、 文字間が必要以上に開き、 間延びした文章になってしまいます。
こういった連続する役物や、 行頭・行末に表示される役物のアキを調整することを役物詰めといいます。
役物詰めを行うことにより、 文字間のアキが引き締まり可読性が高まりますが、 詰めすぎると却って読み辛くなる場合もあります。
この辺りは執筆者の好みや、 出版社のルール (ハウスルール?) に拠ってくると思われます。
詰め方
ネガティブマージン
真っ先に思いつくのはネガティブマージンでしょうか。 例えばこんな感じ。
html
<p>
<span class="thx_opening_bracket"> 「</span>
寿司 ○
<span class="thx_closing_bracket">」 </span>
<span class="thx_mid_dot">・</span>
<span class="thx_opening_bracket"> 「</span>
○ 将棋
<span class="thx_closing_bracket">」 </span>
</p>
css
.thx_closing_bracket + .thx_mid_dot {
margin-left: -0.5em;
}
.thx_mid_dot + .thx_opening_bracket {
margin-left: -0.5em;
}
が、 これはダメです。 このままではダメです。 理由は二つあります。
このままではダメ
理由その壱
css の記述が膨らんでしまいます。 仮に、 約物の種類を 「開き括弧」・「閉じ括弧」・「句読点」・「中点」 の4つとした場合、 その組み合わせは 4x4=16 通りの記述が必要になります。
まぁ、 それでも、 16 通りならそれほどは多くないので許容範囲内ですが、 次の理由が重要です。
理由その弐
行頭・行末の判定ができません。 文章頭ならまだなんとかなりますが、 行頭・行末は表示される環境に拠って異なるため、 jQuery での処理などが必要になります。
では、 どうするか。 行頭・行末のアキをどの様に調整するか。 そうです。 アレです。
半角スペースです。
半角スペースで調整
前回の処理と同様に、 「それ以外」 を正規表現で検索・置換する際に半角スペースを付与します。 先程の例題の場合、 この様になります。
html
<p>
<span class="thx_clps_spc"> </span>
<span class="thx_opening_bracket"> 「</span>
<span class="thx_fwid"> 寿司 ○</span>
<span class="thx_closing_bracket">」 </span>
<span class="thx_clps_spc"> </span>
<span class="thx_clps_spc"> </span>
<span class="thx_mid_dot">・</span>
<span class="thx_clps_spc"> </span>
<span class="thx_clps_spc"> </span>
<span class="thx_opening_bracket"> 「</span>
<span class="thx_fwid">○ 将棋 </span>
<span class="thx_closing_bracket">」 </span>
<span class="thx_clps_spc"> </span>
</p>
こうする事で、 行頭・行末の半角スペースは勝手に吸収されます。
連続する半角スペースは単一の半角スペースで表示されるため、 必要以上にアキが生じません。
他には新たに .thx_fwid が登場していますが、 これは css で調整を行う際、 隣接指定の 「+」 が正しく挙動する様に付加してあります。
あとは、 css で役物に対して 「font-feature-settings: "halt";」 と半角幅を指定し、 中黒のみ前後に半角スペースが発生しているため微調整をして完成です。
ちなみに、 この半角スペースのクラス名、 thx_clps_spc は、 この挙動がマージンの相殺 (Collapsing Margins) に似ている事から命名しています。
css
/* 全角化 */
.thx_fwid {
font-feature-settings: "fwid";
}
/* 相殺スペース */
.thx_clps_spc {
-webkit-user-select: none;
user-select: none;
}
.chrome .thx_clps_spc {
font-family: sans-serif;
font-feature-settings: "hwid";
}
.gecko .thx_clps_spc {
font-family: Kosugi;
line-height: 0;
}
.safari .thx_clps_spc {
font-family: Kosugi;
line-height: 0;
}
/* 括弧 */
.thx_opening_bracket,
.thx_closing_bracket {
font-feature-settings: "halt";
}
/* 中黒 */
.thx_mid_dot {
font-feature-settings: "halt";
}
.thx_clps_spc + .thx_mid_dot {
margin-left: -0.25em;
}
.thx_mid_dot + .thx_clps_spc {
margin-left: -0.25em;
}
カスタマイズ方法
前回の 「ぶら下がり」、 及び元となった 「和欧間スペース」 機能を含めたソースコードになります。
php
//html をテキストとタグに分解
function html_split_text_tag( $html ) {
//alt 内の 「>」 を文字参照に
if ( preg_match_all( '{alt="[^\"]*>}uis', $html, $match ) ) {
foreach ( $match as $value ) {
$alt_amp = preg_replace( '{(>)}is', '>', $value );
$html = str_replace( $value, $alt_amp, $html );
}
}
//html をテキストとタグに分解・ペアリング
$tag_match = '{(<.*?>)}uis';
$pairing = array_chunk(
preg_split(
$tag_match,
$html,
-1,
PREG_SPLIT_DELIM_CAPTURE
),
2
);
// ペア補充 (notice 対策)
$count = count( $pairing );
$pairing[ $count - 1 ] = array( ' ', ' ' );
return $pairing;
}//html_split_text_tag( $html )
// 半角スペース用に Kosugi をエンキュー
function enqueue_kosugi_space() {
wp_enqueue_style( 'google-webfont-style', '//fonts.googleapis.com/css?family=Kosugi&text= ' );
}
add_action( 'wp_enqueue_scripts', 'enqueue_kosugi_space' );
// 簡易的な日本語組版
function thx_typesetting( $the_content ) {
//html をテキストとタグに分解
$pairing = html_split_text_tag( $the_content );
// ペアリングを span しながら結合
$the_content = '';
foreach ( $pairing as $value ) {
$str = trim( $value[0] );
$tag = $value[1];
if (
( '</style>' === $tag )
||
( '</rt>' === $tag )
||
( '</li>' === $tag )
) {
$the_content .= $str;
} else {
$the_content
.= preg_replace_callback_array(
[
// 欧文の検索
'#' .
'[ !-;=-~\p{Ll}]+' .
'#uis' => function ( $match ) {
return
'<span class = "thx_wao_spc"> </span>' .
'<span class = "thx_pwid">' .
$match[0] .
'</span>' .
'<span class = "thx_wao_spc"> </span>';
},
// 句読点の検索
'#' .
'[、。,. ]' .
'#uis' => function ( $match ) {
return
'<span class = "thx_punc_wrap">' .
'<span class = "thx_punctuation">' .
$match[0] .
'</span>' .
'</span>' .
'<span class = "thx_clps_spc"> </span>';
},
// 中点の検索
'#' .
'[ ・:; ]' .
'#uis' => function ( $match ) {
return
'<span class = "thx_clps_spc"> </span>' .
'<span class = "thx_mid_dot">' .
$match[0] .
'</span>' .
'<span class = "thx_clps_spc"> </span>';
},
// 括弧の検索
'#' .
'[ ({[〔「『【〈《]' .
'#uis' => function ( $match ) {
return
'<span class = "thx_clps_spc"> </span>' .
'<span class = "thx_opening_bracket">' .
$match[0] .
'</span>';
},
'#' .
'[)}]〕」』】〉》 ]' .
'#uis' => function ( $match ) {
return
'<span class = "thx_closing_bracket">' .
$match[0] .
'</span>';
'<span class = "thx_clps_spc"> </span>' .
},
// 欧文と役物以外を全角処理に
'#' .
'[^ !-~\p{Ll}、。,. ・:; ({[〔「『【〈《)}]〕」』】〉》 ]+' .
'#uis' => function ( $match ) {
return '<span class = "thx_fwid">' . $match[0] . '</span>';
},
],
$str
);//$the_content .= preg_replace_callback_array()
}//else ( '</style>' === $tag )
$the_content .= $tag;
}//foreach ( $pairing as $value )
return $the_content;
}//thx_typesetting( $the_content )
add_filter( 'the_content', 'thx_typesetting', 21000 );
add_filter( 'the_category_content', 'thx_typesetting', 21000 );
css
/* 禁則処理と両端揃え */
body {
line-break: strict;
text-align: justify;
}
/* 全角化 */
.thx_fwid {
font-feature-settings: "fwid";
}
/* プロポーショナル化 */
.thx_pwid {
font-feature-settings: "pwid";
}
/* 和欧間スペース */
.thx_wao_spc {
font-family: Kosugi;
font-size: 0.5em;
line-height: 0;
-webkit-user-select: none;
user-select: none;
}
code .thx_wao_spc {
display: none;
}
/* 相殺スペース */
.thx_clps_spc {
-webkit-user-select: none;
user-select: none;
}
.chrome .thx_clps_spc {
font-family: sans-serif;
font-feature-settings: "hwid";
}
.gecko .thx_clps_spc {
font-family: Kosugi;
line-height: 0;
}
.safari .thx_clps_spc {
font-family: Kosugi;
line-height: 0;
}
code .thx_clps_spc {
display: none;
}
/* 句読点 */
:not(code)>.thx_clps_spc + .thx_punc_wrap {
margin-left: -0.5em;
}
.thx_punc_wrap {
position: relative;
display: inline-block;
}
.chrome .thx_punc_wrap + .thx_clps_spc {
font-feature-settings: "fwid";
}
.gecko .thx_punc_wrap + .thx_clps_spc {
font-size: 2em;
}
.safari .thx_punc_wrap + .thx_clps_spc {
font-size: 2em;
}
.thx_punctuation {
position: absolute;
font-feature-settings: "halt";
line-height: 1em;
}
code .thx_punc_wrap .thx_punctuation {
position: relative;
font-feature-settings: "fwid";
bottom: initial;
}
.chrome .thx_punctuation {
bottom: -0.1em;
}
.gecko .thx_punctuation {
bottom: -0.15em;
}
.safari .thx_punctuation {
bottom: -0.15em;
}
/* 中黒 */
:not(code)>.thx_mid_dot {
font-feature-settings: "halt";
}
:not(code)>.thx_clps_spc + .thx_mid_dot {
margin-left: -0.25em;
}
:not(code)>.thx_mid_dot + .thx_clps_spc {
margin-left: -0.25em;
}
/* 括弧 */
:not(code)>.thx_opening_bracket,
:not(code)>.thx_closing_bracket {
font-feature-settings: "halt";
}
まとめ
簡易さ故の問題点
半角スペースを利用することにより、 役物へのスタイル指定を大きく減らす事が可能になりますが、 問題点もあります。
例えば、 コレ → 「、、、」
連続する句読点を詰めるために、 css で
:not(code)>.thx_clps_spc + .thx_punc_wrap {
margin-left: -0.5em;
}
としていますが、 改行位置によってはこの様になってしまいます。
また他にも、 半角スペース故の問題点もあります。
半角スペースは改行可能な位置であるため、 括弧などが連続した場合に禁則処理が効かなくなってしまいます。
役物を詰めるためとは言え、 禁則処理が効かなくなってしまうのは美しくないので、 もう少し煮詰めます。 長くなりましたので、 今回はココまで。
次回、 詰むや、 詰まざるや。
コメント