CSSのみでリアルな蛍光マーカーを表現する

Pen highlighter

はじめに

文字列を強調するために、蛍光ペンでなぞったような効果を出すことがありますが、今やCSSのグラデーション(linear-gradient)を使うのが定番になってますね。今回紹介するのもご多分に漏れずlinear-gradientを用いますが、少しこだわってより本物っぽく仕上げてみます。まずは実際のデモを見てみましょう。

蛍光ペンマーカー効果のサンプル その1

わたくしといふ現象は仮定された有機交流電燈のひとつの青い照明です

(あらゆる透明な幽霊の複合体)

風景やみんなといつしよに せはしくせはしく明滅しながら

いかにもたしかにともりつづける因果交流電燈のひとつの青い照明です

ひかりはたもち その電燈は失はれ

これらは二十二箇月の 過去とかんずる方角から

紙と鉱質インクをつらね(すべてわたくしと明滅しみんなが同時に感ずるもの)

ここまでたもちつゞけられたかげと

ひかりのひとくさりづつそのとほりの心象スケツチです
— 宮沢賢治 心象スケッチ『春と修羅』

解説

例えば、最初の水色マーカーのCSSは基本的には以下のようになっています。よくみかける蛍光マーカーは、最初の指定linear-gradientだけですね。

.markerLightblue {
  text-shadow: 0 3px 5px rgba(163, 226, 252, .6);  /* 微妙ににじんだ感じを出すため(さほど明示的ではない) */
  line-height: normal;  /* このnormalの指定が、可変文字サイズ取得やクロスブラウザのために重要! */
  font-weight: bold;
  background: linear-gradient(rgba(0,0,0,0) 60%, rgba(163, 226, 252, .6) 0);
}
.markerLightblue::before, .markerLightblue::after {
  display: inline-block;  /* 高さを持たせるためにインラインブロックに */
  content: "\A";     /* 改行を入れて高さを発生させる */
  white-space: pre;  /* 改行を入れて高さを発生させる */
  width: 0.41em; /* この数字が出てくる理由は後述 */
  clip-path: inset(1px 0); /* はみ出し部分をトリミング */
  transform-origin: bottom left;  /* トランスフォームの起点を左下隅に。重要! */
  transform: skewX(-20deg) translateX(-0.41em);  /* 「平行四辺形」の幅の分ずらす */
  background: linear-gradient(rgba(0,0,0,0) 60%, rgba(163, 226, 252, .6) 0); /* 本要素と同じ指定 */
}
.markerLightblue::after {
  filter: blur(.03em);  /* 終端のにじみの演出 */
  transform: skewX(-20deg); /* マーカー右端の平行四辺形の移動は不要 */
  background: linear-gradient(rgba(0,0,0,0) 60%, rgba(163, 226, 252, .95) 0); /* 背景色の透明度を少し濃い目に */
}

拡大したスクリーンショットを下に示します。

蛍光マーカーの両端に平行四辺形を追加しています

強調したい文字列の背景色として、linear-gradientだけの指定だと細長い長方形のマーカーになりますが、擬似要素の::before::afterを用いて、マーカーの両端にペン先の傾きを表現するように工夫してます。この手の技法で擬似要素を使うときは、本要素にposition: relativeを指定し、擬似要素自体は position: absoluteにして位置を微調整するような紹介がされることも多いように思いますが、それだと長い文字列で折り返し・改行が発生した際にうまく意図したとおりには動いてくれないので(改行発生時の挙動がブラウザ間で結構違う)、あえてそういう絶対座標系は回避するよう工夫しています。

上記サンプルでは、1行目にtext-shadowを用いて、いわゆるドロップシャドウ効果を出していますが、これは効かせているのが分からない程度の弱いエフェクトでして何となく「にじみ」を表現しているだけですのでなくても構いません。

一見複雑そうなCSS指定に見えますが、マーカーの色にあたる部分であるrgba(163, 226, 252, .6)をお好きな色に変えれば、後はそのまま使い回し出来ます。

蛍光ペンマーカーのサンプル その2

上記の指定方法は、改行にも対応しますので、どんなに長いマーカーで数行にわたるものでも大丈夫です。

あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
— 宮沢賢治 『ポラーノの広場』

より詳しい解説

さて、上のCSSソースでは擬似要素の幅width0.41emとなっており、何とも中途半端な数値になっています。どこから出てきた数値かは以下の図形的な考察からです。まぁ図形の変形や移動なのでガチガチに数学的に詰めていけば意図した通りの挙動が得られるわけです。

上の図にあるように、「平行四辺形」の角度αは、ここでは70度という指定にしています(90-70=20がskewXの指定角度になります)。それぐらいの角度がリアルっぽいと個人的に思っただけです。で、ここからが重要な点ですが、上図にあるように、文字列を含む行の高さはLine-heightで明示的に指定することが可能ですが、インライン要素で、例えば背景色が反映される領域の高さというのは、CSSで明示的に指定することは現状不可能です(content area of inline-boxのheightに相当)。ボックス要素ではCSSでの明示的な指定が出来るのですが、インライン要素では不可能なのです。理由は、content area of inline-boxの高さは、指定するフォントファミリーに依存しかつ各ブラウザの解釈次第だからです。

では、どうすればよいかというとline-height: normalという指定を本要素に指定します。World Wide Web Consortium(W3C)のCSS 2.1によれば

normal
Tells user agents to set the used value to a “reasonable” value based on the font of the element. The value has the same meaning as . We recommend a used value for ‘normal’ between 1.0 to 1.2. The computed value is ‘normal’.

ということなので、line-height: normalという指定により、各ブラウザはインライン要素に対して1.0~1.2emに相当する高さを提示します。デベロッパーツールの「Computed」タブで確認できますが、大体どのブラウザも1.125em辺りです(同じブラウザでもフォントサイズにより微妙に可変ですが大体この辺り)。

というわけで、「平行四辺形」の幅は、1.125em/tan(α)で指定することができ、skewX(20deg)なら、1.125em/tan(70deg)~0.41emが出てくるという訳です。

蛍光ペンマーカーのサンプル その3

実際の挙動を体験できるように、CodePenでのデモも載せておきます。分かりやすいように、ボーダーラインの指定を入れています。ボーダーで囲まれた領域が、フォント及びブラウザ依存のcontent area of inline-boxに相当します。

See the Pen
Marker 0
by Masayuki (@-martin)
on CodePen.

参考リンク

display: inlineな属性を持つ要素の高さについてCSSでは正確な指定は出来ないということはちょっと意外でしたが、調べ物をする過程で以下のリンクは大変参考になったので載せておきます。

  1. Deep dive CSS: font metrics, line-height and vertical-align
  2. MDN Web Docs – line-height
  3. stackoverflow: Inline elements and line-height
  4. Font size is useless; let’s fix it

CSSによる蛍光マーカー表現は、上記で紹介した以外にもいくつか思いついたのがあるのでそのうち紹介しますね。

■ 了

|