ウェブサイトでSVGを配置して、cssでドロップシャドウを付ける話

以前の投稿では、SVGの色をcssを使って変更する方法についてお話ししました。今回は、SVGに影(ドロップシャドウ)を追加する方法に焦点を当てたいと思います。

divにドロップシャドウを付ける場合は、以下のようにcssのfilterプロパティでdrop-shadow関数を使用することができます。

.divShape {
  display: block;
  width: 500px;
  height: 500px;
  background: #222;
  filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4)); 
}

前回のカスタムシェイプの場合、この方法ではドロップシャドウが適用できません。

この場合、擬似要素を使用します。::before擬似要素をカスタムシェイプに適用し、その親であるdivにドロップシャドウを追加します。

このようにすることで、カスタムシェイプのdivにドロップシャドウを効果的に付けることができます。

.svgShape {
  position: relative;
  width: 606px;
  height: 514px;
  filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4)); 
}

.svgShape::before {
  display: block;
  height: 100%;
  content: "";
  background: linear-gradient(45deg, black, transparent);
  mask-size: contain;
  mask-image: url('/img/sample.svg');   
}

ウェブサイトでSVGを配置して、cssで色を変更する話

SVGをウェブページに追加する最も簡単な方法は、<svg>タグをインラインで直接記述するか、<img>要素を追加してsrc属性でSVG画像を参照することです。
SVGファイル直接に使用すると、SVGの色を変えたい時は少しややこしいです。(編集ソフトを使用して、書き直す必要があります。)
(<img> 要素を使用してインポートした場合、CSSだけで色を変更することはできません。)

単色を変えたい場合:
css実装例:

#svgID path{   
  fill: red; 
}

このようにすればcssでpath要素の色を簡単に変更できるだと思いますが、グラデーションをかけたい場合はSVGファイル自体を修正しなければなりません。そこでもう一つの方法を紹介します。

DIV要素をカスタムシェイプに:

SVGインラインで直接記述するより、DIV要素の形をSVGにすれば、色々カスタマイズができます。今回は外部SVGを参照して、cssで色をグラデーションにします。

divといえば、多くの人のイメージには長方形や正方形しかありません。しかしdivを他の形にすることができます。この時はmask-imageを使います。
(単純にdivの形を変えたい場合はclip-pathも出来ますが、今回の主旨と違いますので詳細は割愛させていただきます)

HTML実装例:
<div class=”svgShape”></div>
css実装例:
(widthとheightはsvgのサイズに合わせてください)

.svgShape {
  width: 500px; 
  height: 500px;
  background: linear-gradient(45deg, black, transparent);
  mask-image: url('/img/sample.svg');
}


このように実装すれば、divはsvgの形に変えられ、色はcssでカスタマイズできます。
実装例:

refrence:

https://developer.mozilla.org/ja/docs/Web/CSS/mask-image

CSSのfont-synthesisとtext-renderingが原因でAndroidで太字にならない

Viteで新規にプロジェクトを作るとapp.cssに font-synthesistext-rendering が指定されています。

:root {
  ...
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  ...
}

これらのプロパティがあると、 Android Chrome で見たときにfont-weightで700以上を指定しても太字にならない場合があります。

font-synthesis は、フォントに太字やイタリックの字体が含まれていない場合にブラウザが合成してよいかどうかを制御するもの。

text-rendering は、合字やカーニングの処理を行うか否かを制御し、読みやすさと速度のどちらを優先するか決めることができます。

これら2つの両方もしくはどちらかと、おそらく font-family によるフォント指定の組み合わせによって太字書体が使える環境にも関わらず太字にならないことがあるようです。

基本的に欧文フォントのためのプロパティなので、日本語環境では、少なくとも現段階では使わないほうが無難なようです。

CSSでフォントサイズの変数名にSI接頭辞を使ってみたらどうだろう

これは今に始まったことじゃないですが、JSにしろCSSにしろ、変数名ってめちゃくちゃ悩むんですよね。

今日はCSSのフォントサイズを変数化する際にSI接頭辞を使ってみたらどうだろうか、という提案をさせていただきたい。

フォントサイズの値の特徴として、下記のようなものがあると思います

  • 数値型
  • 基準となる値があり、それより小さいものと大きいものに分けられる
  • 値そのものより、他の値より大きいのか小さいのかが重要(イメージできるので)
  • せいぜい5〜8種類程度になるはず

要するに 数値型で相対的な大きさがなんとなく想像できるような変数名 だと良い変数だと思うわけです。

そこでこちらをご覧ください

$font-size-micro: 12px;
$font-size-milli: 14px;
$font-size-base: 16px;
$font-size-kilo: 18px;
$font-size-mega: 24px;
$font-size-giga: 32px;

基準である16pxをベースに、それより小さいものをミリやマイクロ、大きいものをキロ・メガ・ギガとすることで、相対的な大きさを想像することができる変数名とすることができたと思います

試しにこの変数名を、あえて分かりにくいセレクタで使ってみるとこんな感じになります。

.headline {
  font-size: $font-size-kilo;
}
.date {
  font-size: $font-size-milli;
}
.value {
  font-size: $font-size-giga;
}

フォントサイズの大小が明確になるだけで、随分と要素の重要度がCSSを見ただけで伝わるのではないかと思うわけです。

しかも、この程度のSI接頭辞ならエンジニアではなくても、なんなら小学生でも直感的にわかるという嬉しさ。

中間サイズの追加に弱いという欠点はあるものの、デザインシステムがカチッとしている状況であれば、十分使えるのではないでしょうか。


ちなみに、これを考えているときに思いついた別案ですが、むしろ日本語で曖昧な変数名作っちゃえばもっとわかりやすくて汎用的になるのではと思ったりしました

$font-size-結構小さい: 12px;
$font-size-ちょっと小さい: 14px;
$font-size-基準: 16px;
$font-size-ちょっとデカい: 18px;
$font-size-まあまあデカい: 24px;
$font-size-相当なデカさ: 32px;
$font-size-アホほどデカい: 64px;

これなら中間サイズが追加されても表現次第でどうにでもなるので最強です。優れたエディタなら補完もしてくれるので表記ゆれなんて気にしなくて良い。日本語すごい!

文字を思い通りの大きさと位置で表示するCSS

基本的に文字というものは、大文字・小文字など文字の種類によって目に見える大きさ(高さ)が異なります。

例えばCSSで font-size を100pxに指定した場合でも、文字がピッタリ100pxで表示されるわけではありません。

これをCSSで思い通りに指定する方法を調べてみました。

(欧文フォントの場合)

欧文フォントの基礎知識

アルファベットでは、文字の下端( y などの下に飛び出る小文字を除く)となるベースラインを基準に、デザイン上の指標となる高さがいくつか存在します。

  • アセンダ:ベースラインから bd など小文字で上に飛び出る部分の上端までの距離
  • ディセンダ:ベースラインから jy など下に飛び出る文字の下端までの距離
  • エックスハイト:ベースラインから x など、小文字の上端までの距離
  • キャップハイト:ベースラインから大文字の上端までの距離。アセンダより少し下に位置することが多い

※こちらの図がわかりやすいです http://w3.kcua.ac.jp/~fujiwara/infosci/font.html

例えば Arial のメタデータを解析してみると、下記の値を発見できます

  • ascender: 1854
  • descender: 434
  • sxHeight: 1062
  • sCapHeight: 1467

数字の大小はさておき、これらの値でまず意識しなければならないのは単位です。

実はこの数字、単位はピクセルでもミリメートルでもありません。
各フォントが em-square という基準値を決め、それに対する相対値として定義されています。

これもメタデータを見てみると発見できます

  • unitsPerEm: 2048

要するに Arial の場合は、2048を基準に、それよりどのくらい大きいのか、小さいのか、という相対的な数字なのです

文字サイズ16pxのxの大きさ

そしてこの em-square こそがCSSの font-size と直接関わってくる部分。

例えば font-size: 16px; とする場合、xの高さは

var xHeight = (1062 / 2048) * 16px

約8.3pxとなります。

また、逆算的にキャップハイトが100pxになるためのfont-sizeは

var fontSize = 100px / (1467 / 2048)

約139.6pxになります。

font-size は、実は スケール感をふんわり指定しているだけ で、必ずしもその大きさで文字が表示されるわけではない、ということが分かって頂けたかと思います。

文字の表示位置とline-height

ここまでで表示したい大きさのfont-sizeは見いだせるようになったと思いますが、実際にこれをウェブのレイアウトで使うためには、表示位置も制御できねば意味がありません。

em-squareascender などの値はあくまで距離の数値なので、そのまま位置算出に使うことはできなさそうです。

CSSでインライン要素の表示位置といえば vertical-align ですが、これはベースラインを揃えたりなど、わりとアバウトな配置の指示しかできませんし、 line-height の設定値次第で文字の表示位置は大きく変わります。

line-height に関して言えば、実はデフォルト値である normal は、下記の計算式で算出されているみたいです

var lineHeight = (ascender + descender + lineGap) / unitsPerEm

lineGap は、他の値と同じようにフォントのメタデータとして記録されていて、例えばArialは 67 です。フォントによっては0なこともあります。

ascender + descender が文字の表示しうる範囲ですが、lineGapはその半分の数値がascenderの上とdescenderの下に割り振られるような表示になります。

上記の式をArialのメタデータで計算してみると、結果は 1.1499 になります。約1.15です。

実際に下記のようなCSSを使ってp要素の高さをDevToolsで見てみると、115pxになってるのが確認できるはずです。

p {
  font-family: 'Arial';
  font-size: 100px;
  line-height: normal;
}

ということは、 line-height: normal を指定してJSで高さを取得し、他のメタデータからBaselineの位置を算出することで最終的にはCapHeightやxHeightなどの表示位置も計算できるはずです。

var baselineY = lineHeight - (lineGap / 2 + descender) / unitsPerEm
var xHeightY = baselineY - sxHeight / unitsPerEm
var capHeightY = baselineY - sCapHeight / unitsPerEm

結論は、CSSでフォントを深く掘るのはつらいということです