DBIx::Handler と mysql_enable_utf8 と utf8mb4 ― 2013年06月10日 21時52分
Perl で MySQL サーバーに接続するとき、DBIx::Handler
を使っています。
my $handler = DBIx::Handler->new(
$dsn, $username, $password,
{
RaiseError => 1,
RootClass => 'My::DBI',
mysql_enable_utf8 => 1,
},
);
しかし、これだと "𠮷" (U+20BB7
、いわゆる「つちよし」) など BMP 外の文字を保存しようとしたとき、テーブルの文字コードが utf8mb4
であっても "????" (疑問符 4 文字) に化けてしまいます。
ググったところ、mysql_enable_utf8 => 1
を指定した時点で DBD::mysql
が接続時の文字コードを utf8
にしてしまうのが問題だそうです。(cf. おそらくはそれさえも平凡な日々: DBD::mysqlでmysql_enable_utf8しつつutf8mb4使いたいとき)
接続時に文字コードを utf8mb4
に指定しなおせばいいとのことですが、DBIx::Handler
ではどうするのだろうとソースコードを眺めていたところ、new
メソッドの第 5 引数の存在を知りました。
my $handler = DBIx::Handler->new(
$dsn, $username, $password,
{
RaiseError => 1,
RootClass => 'My::DBI',
mysql_enable_utf8 => 1,
},
{
on_connect_do => ['SET NAMES utf8mb4'],
},
);
これで BMP 外の文字も文字化けせず保存・取得できるようになったのですが、この第 5 引数は (DBIx::Handler
0.07 時点では) 文書化されていないので、使っていいものか心配です。
Callbacks
を使っても期待通り動作するようなので、そちらのほうがよかったりするのでしょうか。
my $handler = DBIx::Handler->new(
$dsn, $username, $password,
{
RaiseError => 1,
RootClass => 'My::DBI',
mysql_enable_utf8 => 1,
Callbacks => {
connected => sub {
$_[0]->do('SET NAMES utf8mb4');
return;
},
},
},
);
(SET NAMES
をつかってはいけないという話もありますが、追いきれていません。)
長い英単語を途中で折り返したいときの CSS の指定方法 ― 2013年06月18日 09時32分
ヨーロッパ系の言語では基本的に単語の途中に折り返しを入れません。しかし、幅の狭い領域に長い英単語を記述するときや、笑いを表す「www…www」のように欧文文字を表現に組み込むときなど、欧文文字同士の合間で折り返したいと思うかもしれません。そのような折り返しの制御を CSS で行うにはどうすればよいのでしょうか。
- 2013 年 6 月時点の結論
word-wrap: break-word
を使うとどうなるのかword-break: break-all
を使うとどうなるのかword-wrap: break-word
とword-break: break-all
を両方使うとどうなるのか- なぜ
word-break: break-all
ではなくword-wrap: break-word
を勧めるのか - どこに
word-wrap: break-word
を指定するのか position: aboslute
やdisplay: inline-block
との組み合わせdisplay: table-cell
との組み合わせdisplay: flex
との組み合わせwhite-space: pre
やwhite-space: nowrap
との組み合わせword-wrap
というプロパティ名- 参考文献
2013 年 6 月時点の結論
word-wrap: break-word
を使ってください。word-break: break-all
は使わないでください。display: table-cell
やdisplay: inline-block
と組み合わせるときは、明示的な最大幅の指定が必要かもしれません。
word-wrap: break-word
を使うとどうなるのか
単語 (欧文文字の連続) の途中で折り返さないと行ボックスの幅からあふれてしまうときのみ、その単語の途中で折り返します。単語の途中で折り返しが発生するのは、その単語の幅が行ボックスの幅より大きいときのみです。単語の幅が行ボックスの幅より小さければ、その単語全体が次の行に送られることはあっても、その単語の途中で折り返されることはありません。
word-wrap: break-word
を指定した例。単語 supercalifragilisticexpialidocious の途中で折り返される。
word-break: break-all
を使うとどうなるのか
任意の文字間での折り返しが許容され、言語に関わらず一切の禁則処理が無効になります。英単語の途中で行ボックスの幅からあふれそうになれば、あふれる直前で折り返されます。開き括弧の直後や閉じ括弧の直前、句読点の直前でも折り返されます。
word-break: break-all
を指定した例。単語 such 及び supercalifragilisticexpialidocious の途中で折り返される。
word-wrap: break-word
と word-break: break-all
を両方使うとどうなるのか
word-break: break-all
を使った時点でどの文字の間でも折り返しが起こりうるので、word-wrap: break-word
による折り返し発生条件に到達しません。つまり、両方指定するのは word-break: break-all
だけの指定と実質変わりません。
なぜ word-break: break-all
ではなく word-wrap: break-word
を勧めるのか
禁則処理をできるだけ活用し、また単語途中での折り返しを可能な限り避けるためです。ヨーロッパ系の言語で単語途中での折り返しがあると、ひとつの単語がふたつの単語のように見えてしまいます。日本語でも句読点が行頭に来ていれば違和感を持つ人が多いでしょう。
どこに word-wrap: break-word
を指定するのか
word-wrap
プロパティも word-break
プロパティもその値は継承します。言い換えれば、その効果は子孫要素にも及びます。ですから、これらのプロパティは (HTML 文書であれば) body
要素か html
要素に指定しておけば十分でしょう。
position: aboslute
や display: inline-block
との組み合わせ
ときとして長い単語が折り返されず、word-wrap: break-word
が効いていないように思えるかもしれません。その単語の祖先要素に position: absolute
や float: left
、float: right
、display: inline-block
が指定されていると、このような状況が起こりえます。
これらのプロパティ・値を指定された要素 (で width
プロパティの計算値が auto
のとき) は、その内容の幅によって自身の幅を決めるのであり、自身の幅を先に決めて内容の幅をそれに合わせるのではありません。このとき、その要素の幅は shrink-to-fit width (内容に合うように縮んだ幅) であるといいます。shrink-to-fit な幅を算出するときに word-wrap
プロパティの影響は考慮されないので、単語途中での折り返しは発生しません。
(「考慮されない」といいましたが、内容の幅を決めようというときには行ボックスの幅も定まっていないので、「折り返さないと行ボックスの幅からあふれてしまう」という判断ができません。「word-wrap: break-word
の影響を考慮しようにも考慮できない」というのが実際のところでしょう。)
こうした要素に対しては、width
プロパティに auto
以外の値を指定することで shrink-to-fit な幅ではなくなります。あるいは、max-width
プロパティを指定するのもひとつの手です。いずれにしても行ボックスの最大の幅が定まり、単語の長さがその幅からあふれるときは、その単語の途中で折り返されるようになります。
display: table-cell
との組み合わせ
display: table-cell
を指定した要素 (セル) も shrink-to-fit な幅の要素と同様、内容の幅によって自身の幅が決まります。しかし、こちらは width
プロパティを指定しても単語の途中での折り返されるようになるとは限りません。CSS 2.1 の自動テーブルレイアウトアルゴリズムにおいて、セルの width
プロパティの値が最小セル幅として扱われるからです。
(ここで「CSS 2.1 の自動テーブルレイアウトアルゴリズム」と呼んでいるのは CSS 2.1 仕様で定義されているものですが、ブラウザにそのアルゴリズムの利用が強制されているわけではありません。実際に用いられるテーブルレイアウトアルゴリズムはブラウザごとに異なりえます。)
セル内でも word-wrap: break-word
による単語途中での折り返しを実現させるためには、セルに max-width
プロパティを指定するか (ただし、この方法は IE 8 で機能しないことがあるようです)、セルの子孫要素 (であり、かつ単語の祖先要素でもあるもの) に width
プロパティを指定して幅を明示する必要があります。
display: flex
との組み合わせ
flexbox レイアウトとの組み合わせでも折り返しが効かないように思えることがあるそうです。
white-space: pre
や white-space: nowrap
との組み合わせ
IE 8 以降では、word-wrap: break-word
と white-space: pre
の効果が重なると、なぜか (まるで word-break: break-all
を指定したかのように) 任意の文字間で折り返しが発生しうるようです。どこでも折り返されるようになるのは white-space: nowrap
と組み合わせたときも同じで、こちらは nowrap
といっているのに折り返しが発生することになります。(white-space: pre-wrap
、white-space: pre-line
のときは問題ありません。)
white-space: nowrap
の使い方として、text-overflow: ellipsis
を組み合わせ、行ボックスからはみ出した文字列を省略表示にすることがあります。
h1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
しかし、IE 8 以降 (少なくとも IE 10 まで) では、祖先要素に word-wrap: break-word
が指定されているとこの省略表示が効かず、内容がひとつの行ボックスに収まりきらなければ複数行で表示されます。white-space
プロパティに値 pre
または nowrap
を指定するときは、word-wrap
プロパティの値を初期値に戻しておいたほうがいいでしょう。
h1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: normal;
}
word-wrap
というプロパティ名
この記事の執筆時点の CSS3 Text 草案では、word-wrap
プロパティは overflow-wrap
プロパティに改称しています。とはいうものの、互換性のため word-wrap
というプロパティ名でも受け付けることになっています。現状のブラウザ実装状況を鑑みるに、word-wrap
という名前を使うか、word-wrap
と overflow-wrap
を併記するかがよいと思います。
最近のコメント