Web制作者は要チェック! SVGとCSSを使用したUIコンポーネントの実装テクニック
Post on:2022年2月3日
SVGを使用してUIコンポーネントを構築すると、実装がより簡単により分かりやすくなります。SVGとCSSを使用したUIコンポーネントの実装テクニックを紹介します。
SVGなのでカラーやサイズも簡単に変更でき、軽量で、レスポンシブにも完全対応です。
Building UI Components With SVG and CSS
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
SVGはアイコンやイラストだけでなく、わたし達デベロッパーが忘れがちなパワーをたくさん持っています。CSSと比較して、SVGを使用することが理にかなっているユースケースはたくさんあります。
たとえば、円形のローディングアニメーションを実装したり、画像にマスクを適用したりすることが挙げられます。CSSで実装できないわけではありませんが、使用するテクニック(マスクなど)に応じてクロスブラウザの問題と戦うのが困難になることがあるため、SVGを使用すると時間と労力を節約できます。
SVGが優れている点は、レスポンシブでパフォーマンスも高く、HTMLとCSSで簡単に実装できることです。
この記事では、SVGをHTMLやCSSとともに使用してさまざまなUIコンポーネントを構築するユースケースを解説したいと思います。
では、さっそく始めましょう!
1. SVGで切り抜きを実装
このアバターは、FacebookのCSSを勉強していたときに見つけたものです。メッセンジャーではアバターの右下にバッジを付けることができ、バッジのためのスペースを確保するために切り取られています。
アバターには、バッジのスペースを確保するために右下が切り取られている
CSSでホワイトのボーダーを追加することで実現できます(応急処置として)。しかし、これをさらに発展させて動的なSVGコンポーネントにしてみませんか?
1 2 3 |
.badge { border: 2px solid #ff; } |
ボーダーが使えるのに、なぜSVGを使うのか、と思われるかもしれません。まあ、これに正しいも間違いもないのですが。しかし、他よりも優れた解決策があります。数学の授業で、先生がある問題にはさまざまな解決方法があり、そのうちの1つが柔軟性の点で優れていると言ったのを覚えていますか? それと同じです。
ボーダーがうまく機能しない例を挙げておきます。
- ダークモード: ホワイトのボーダーが黒っぽい背景の上になります。
- ホバー時: 背景が変化するので、ホワイトのボーダーが奇妙に見えます。
下記の画像では、バッジの周りのホワイトのボーダーが、ダーク背景とホバー状態とでどのように干渉してしまうのかに注目してください。
上: デフォルト、中: ダーク背景、下: ホバー状態
ホバー時はボーダーのカラーを変更することでいちおう解決できますが、それは最良の解決策とは言えません。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.card__badge { border: 2px solid #ff; } .card:hover .card__badge { border-color: lightgrey; } @media (prefers-color-scheme: dark) { .card__badge { border-color: #454545; } } |
SVGを使用し、右下のバッジを切り抜くことで、より良い方法で解決することができます。この実装で、どのような背景でもうまく機能します。
SVGで右下のバッジを切り抜く
アバターを含めるためにSVGの<image>
要素を使っています。バッジを切り取るために<circle
要素を作成し、1つはホワイトでもう1つはブラックにします。
マスクでは、ブラックに塗りつぶされた要素はすべて非表示になり、ホワイトの要素は表示されます。ブラックの円は右下に配置し、半径は18
にしました。
デザインツールでは、これを減算と呼びます。大きな円から小さな円を引き算したものです。
実際の動作は、デモページでご覧ください。
See the Pen
Avatar - SVG Mask by Ahmad Shadeed (@shadeed)
on CodePen.
このテクニックについてより詳しく学びたい人は、下記をご覧ください。
実装の仕組みが分かれば簡単!画像の一部を切り取るカットアウトを実装するCSSとSVGのテクニック
2. SVGでセクションの見出しを実装
私はあるクライアントのプロジェクトで、SVGとCSSを組み合わせてセクションの見出しをデザインし、実装しました。そのブランドはセキュリティに関連しているため、このようなスタイルが適していると思います。
SVGでセクションの見出しを実装
このコンポーネントは、短いテキストと長いテキストで機能する必要があり、テキストが長すぎる場合は、レイアウトを崩すことなく複数行に折り返す必要があります。これを構築するために、私は次のようにしました。
- まず、固定部分(右側)をコピーして、インラインのSVGとして追加する。
- CSSでテキスト下の線と、最初と最後の小さな丸を実装する。
- レイアウトはFlexboxで構築し、無駄な配置をしないようにする。
実装の仕組み
基本的なHTMLとCSSは、下記の通りです。
1 2 3 4 5 6 |
<h2 class="c-section__title"> <span>CSS is awesome</span> <svg xmlns="http://www.w3.org/2000/svg" width="128" height="34.5" viewBox="0 0 128 34.5" preserveAspectRatio="none"> <path fill="none" stroke="#d8d8d8" stroke-width="2" d="M127 1H33.5L1 33.5"></path> </svg> </h2> |
1 2 3 4 5 6 7 |
.c-section__title { max-width: 700px; width: fit-content; display: flex; margin-left: auto; margin-right: auto; } |
基本的な構造
次に、<span>
要素にボーダーを追加して、SVGに接続された線を模倣します。
テキストの下にボーダーを追加して線を繋げる
しかし、ここでSVGと線がつながっていないことに気づきました。Flexboxを使用しているので、その問題を修正するのは簡単です。flexアイテムをflex-end
に揃えるだけです。
1 2 3 4 5 6 7 8 |
.c-section__title { max-width: 700px; width: fit-content; display: flex; align-items: flex-end; margin-left: auto; margin-right: auto; } |
次に、絶対位置指定の擬似要素を使用して、最初と最後に円を追加します。
See the Pen
Section Title by Ahmad Shadeed (@shadeed)
on CodePen.
SVGを使用することの優れている点は、SVGのパスを点線にして、アニメーション化できることです。そのためには、SVGで書き出されたパスがアウトライン化されていないことを確認する必要があります。
1 |
<path d="M127 1H33.5L1 33.5" fill="none" stroke="#d8d8d8" stroke-width="2"></path> |
Jake Archibaldの記事からこのテクニックを学びました。 アイデアは、パスの長さを取得したいということです。
デベロッパーツールでSVGを調べて、<path>
要素を選択すると、末尾の横に== $0
があることに気がつきます。これを選択したまま、コンソールに移動して、以下のスクリプトを記述します。
1 2 |
$0.getTotalLength() // 139.46 |
$0
は下記のようなことをせずにDOMから要素を選択する簡単な方法です。
1 2 |
let sectionPath = document.querySelector('#path'); console.log(sectionPath.getTotalLength()); |
それはこの例のコンテキスト内での簡単なヒントでした。
長さが決まったら、あとはやりたいことが何でもできます。たとえば、ホバー時にアニメーションさせることもできます。
1 2 3 4 5 6 7 8 9 |
.c-section__title--dashed path { stroke-dasharray: 139; stroke-dashoffset: 0; transition: 0.7s; } .c-section__title--dashed:hover path { stroke-dashoffset: 139; } |
See the Pen
Section Title - Animated by Ahmad Shadeed (@shadeed)
on CodePen.
あるいは単純に、点線にすることもできます(その場合、パスの長さを知る必要はありません)。
点線に変更
3. SVGでリンクの下線を実装
SVGを使用して、クリックするのが楽しくなるリンクの下線を実装することができます。私は数年前に、ランダムにパスを生成し、ホバー時にそれを再描画するスクリプトを作成しました。
SVGでリンクの下線を実装
このアイデアは各リンクにSVGを挿入することで、下記のようになります。
1 2 3 4 5 6 7 8 |
<svg width="400" height="35" xmlns="http://www.w3.org/2000/svg"> <path id="pathItem" d="M5 5 Q 30 15 170 5" stroke="black" fill="transparent" stroke-width="7" stroke-linecap="round"/> </svg> |
このマジックは、d
属性の値を変更することで起こります。パスが実際にどのように描画されるかをビジュアルでご覧ください。
パスがどのように描画されるか
実際の動作は、デモページでご覧ください。
See the Pen
Underline.js by Ahmad Shadeed (@shadeed)
on CodePen.
テクニック的の詳細については、私の記事Custom Underlines with SVG、またはUnderliner.js -GitHubをご覧ください。
4. SVGでテープを実装
あるクライアントのプロジェクトに携わっているとき、CSSを使用してどこにでも配置でき、1つのCSS変数(カスタムプロパティ)のみで色を変えることができる動的な方法で、セクションにテープを加える実装が必要でした。
SVGでテープを実装
Adobe Illustratorで、テープをレイヤーに分けてみました。
- The base: 塗りつぶしの色
- Transparent black: 暗い部分
- Transparent white: 明るい部分
テープの構造
SVGのコードを見てみましょう
1 2 3 4 5 6 7 |
<svg> <defs> <g id="tape" fill="currentColor"> <!-- path contents --> </g> </defs> </svg> |
fill="currentColor"
があることに注目してください。currentColor
キーワードは、CSSのcolor
プロパティから値を継承するため、1つのプロパティだけで動的に色を変更することができます。
ベタ塗りのベース、そして明るい部分と暗い部分の2つのレイヤーがあるため、色を変更すると、見た目が異なるテープができます。
1つのプロパティを変更するだけで、簡単に色を変更できる
さらに良いことに、SVGをテンプレートにし、SVGの<use>
要素を使用すると、SVGを複製せずにテープを再利用することができます。
1 2 3 4 5 6 7 8 9 10 11 12 |
<svg style="display: none;"> <defs> <g id="tape" fill="currentColor"> <!-- path contents --> </g> </defs> </svg> <!-- テンプレートからテープを使用する例 --> <svg class="tape" style="--angle: 10deg; color: red; --size: 120px;" aria-hidden="true" focusable="false" viewBox="0 0 123 47"> <use href="#tape"></use> </svg> |
<use>
要素でテープを追加していることに注目してください。これの何がいいかというと、CSSの変数をインラインスタイルとして使用できることです。
CSSは次のようになります。
1 2 3 4 |
.tape { width: var(--size); transform: rotate(var(--angle)); } |
実際の動作は、デモページでご覧ください。
See the Pen
SVG Tape by Ahmad Shadeed (@shadeed)
on CodePen.
終わりに
SVGを使用してUIコンポーネントを構築すると、作業がより簡単に、より分かりやすくなります。UIコンポーネントの中には、100%完璧なユースケースやSVGではないものもあるかもしれませんが(例:アバターの切り抜き)、それは取り組むプロジェクトのコンテキストによって異なります。
SVGとCSSの使用が優れている他のユースケースはありますか? もし何かあれば、@shadeed9までお願いします。
sponsors