ウェブサイトの、コンテンツの境界線が波線・波模様(ウェーブ)のデザインの場合、どうコーディングするか迷います。

こういったデザインのコーディング方法について、今まではコンテンツと同じ色の波模様の画像を、透過PNGで用意していました。しかし、この方法では色の数だけ画像を用意する必要があり、デザイン変更の度に手間がかかります。
そこで今回、一例として汎用性を重視したコードを考えてみました。コンテンツの色に関係なく、共通のSVG1枚だけの使い回しで対応できるよう、マスクを活用したCSSのデモコードを以下に提示します。
ここがポイント!
- コンテンツの色を問わず使い回せる(色ごとの画像やCSSの追加不要)
- 単色だけではなく、グラデーションや背景画像が設定されたコンテンツにも対応可能
- CSSで制御するので、レスポンシブ対応等のメンテナンス性が高い
※CSSのmaskプロパティはローカルでは動かない(クロスドメインのブロック)ので、検証はサーバー環境下(もしくはバーチャルホスト)で行ってください。
デモ
HTML / CSS / 波画像 ※本筋に関係のないコードは省略
<section>section</section>
<section class="mask-image">section</section>
<section class="mask-image">section</section>
.mask-image {
--height: 20px;
mask-image:
url(img/wave.svg),
linear-gradient(to bottom, transparent 0%, transparent var(--height), #000 var(--height), #000 100%);
mask-size: 240px;
margin-top: calc(-1 * var(--height));
}
波画像:wave.svg サイズ:240px ✕ 20px(例)
準備するもの
波模様の画像
まず、マスク用の波模様の画像(※以下、波画像)を用意します。IllustratorやFigmaなどを使って制作してください。
このサンプルは横方向に無限リピート出来るよう、両端をシンメトリーな形状で作りました。フォーマットはSVG
です。
波画像:wave.svg サイズ:240px ✕ 20px(例)
※ここでは見やすいように背景色に黒を付けていますが、実際の背景データは透明です。
ちなみに、今回のコーディング方法なら、実はSVGではなく透過PNGでも目的は達成出来るのですが、せっかくならどんな高解像度ディスプレイにも対応できるベクター形式の強みを活かしたいので、特段の理由がなければSVGで良いと思います。
今回のデモで使う波画像
- サイズ:
240×20px
※横にリピートできるように両端のデザインを合わせる - フォーマット:SVG(または透過PNG)
CSS(マスク適用部分)
次に波画像のマスクを適用する部分のCSSです。
先ほど用意した240×20px
の波画像に対して、今回は以下のようなコードを構築しました。
.mask-image {
--height: 20px;
mask-image:
url(img/wave.svg),
linear-gradient(to bottom, transparent 0%, transparent var(--height), #000 var(--height), #000 100%);
mask-size: 240px;
margin-top: calc(-1 * var(--height));
}
デモコードの仕組みの解説
ここからは提示したデモコードの仕組みを1行ずつ解説していきます。
① まず波画像の高さを変数化する
--height: 20px;
まず波画像の高さの値は、この後で何回も使用するので、最初に変数化しちゃいます。これで複数回使用する際の修正を容易にします。
ちなみに「波画像の高さがそのままコンテンツの境界線の高さ」となります。
② mask-image を複数指定してマスクの重ね掛け
mask-image:url(img/wave.svg),linear-gradient(to bottom, transparent 0%, transparent var(--height), #000 var(--height), #000 100%);
ここからがややこしい。
このテクニックのポイントは、2つの異なるマスクをカンマ区切りで組み合わせることです。
1つ目のマスク(波画像)
mask-image: url(img/wave.svg);
まず、波画像「wave.svg」をmask-image
に適用することで、コンテンツの背景が波模様にマスクされます。

しかし、このままではそれ以外の部分も、全てマスク化されてしまうため、次のステップで調整します。
2つ目のマスク(グラデーションを使った透過処理)
linear-gradient(to bottom, transparent 0%, transparent var(--height), #000 var(--height), #000 100%);
次にlinear-gradient
を使い、マスクの適用範囲を調整します。この linear-gradient
の指定について1つずつ解説します。
linear-gradient(to bottom,
transparent 0%, transparent var(--height),
#000 var(--height), #000 100%
);
linear-gradientの中身(わかりやすいように改行)
to bottom
上から下方向にグラデーションを適用する。
transparent 0%, transparent var(--height)
開始位置(0%)からvar(--height)
まではtransparent
(透明)を指定します。結果、波画像の領域はマスクが適用されず何も影響を受けません(そのまま表示される)。
#000 var(--height), #000 100%
var(--height)
から下の領域は #000
(黒色)で塗りつぶします。
尚、一例として#000
(黒色)にしましたが、#000
という色自体に意味は無いので別に何色でも良いです。
mask-image
は「透明度」に基づいてマスク処理を行うので、transparent
か、それ以外か、ということが重要。
transparent
の箇所にはマスクが適用されず、色を指定した箇所は完全にマスクされる領域になります。それにより波画像のvar(--height)
から下の領域だけが完全に透明化されるということです。
mask-image:url(img/wave.svg),linear-gradient(to bottom, transparent 0%, transparent var(--height), #000 var(--height), #000 100%);
2つのマスクを設定した完成コード
③ mask-size で波画像のサイズを指定
mask-size: 240px;
mask-size
を画像と同じサイズに指定することで、波画像が意図したサイズで繰り返し表示されます。
※mask-repeat
のデフォルト値はrepeat
なので、特に指定せずとも横方向に無限にリピートされます。
補足
画像サイズを変更する場合は、--height
の値も合わせて調整
デモではmask-size
の値は、画像のサイズと一致させたものの、ちゃんと縦横の比率が合っていれば、サイズは任意に変更可能です。画像がSVGならばベクター形式なので、レスポンシブ時に波のサイズを変えたい場合などに重宝します。
@media (max-width:750px) {
.mask-image {
--height: 10px;
mask-size: 120px;
}
}
例:レスポンシブ等でサイズ変更
④ 波画像の高さの分だけ、コンテンツを持ち上げて重ねることで、境界線が完成
margin-top: calc(-1 * var(--height));

波模様が境界線に沿うように、波画像の高さ分だけネガティブマージンで上に持ち上げます。
これにより、コンテンツ同士が波画像の高さ分だけ重なり、コンテンツの境界線が完成します。コンテンツ側にはposition:relative;
を指定し、階層関係(z-index
)が正しく表示されるよう、必要に応じて調整してください。
⑤ (任意)波画像の高さの分だけ、paddingを指定する
padding-block: var(--height);
これはデザイン次第ですが、波画像の高さの分だけ、上下にpaddingを指定すれば、コンテンツの編集可能領域が明確になってわかりやすいです。まあ、これについてはお好みで。
完成デモ
<section>section</section>
<section class="mask-image">section</section>
<section class="mask-image">section</section>
.mask-image {
--height: 20px;
mask-image:
url(img/wave.svg),
linear-gradient(to bottom, transparent 0%, transparent var(--height), #000 var(--height), #000 100%);
mask-size: 240px;
margin-top: calc(-1 * var(--height));
}
まとめ
以上、SVG+CSSでmask-imageを活用した、コンテンツの区切りを波模様にするテクニックでした。
この方法を使えば、コンテンツの色、グラデーション、背景画像に関係なく、共通のSVG(またはPNG)を使ったclass
を使い回すことが可能になります。
コンテンツの順番が入れ替わったり、追加されたりしても、いちいち波画像の追加やCSSの調整を加える必要はありません。そのまま同じclass
で対応可能です。
参考にしてください。