DigiPress

Highly Flexible WordPress Theme

メニュー

[CSS]背景に依存せず角丸のボーダーをグラデーションで表現する方法

[CSS]背景に依存せず角丸のボーダーをグラデーションで表現する方法

CSS でグラデーションの枠線を表現する方法としてよく挙げられるのが、border-image-source でグラデーションを指定した以下のようなコードです。

よくある CSS
.border{
  display: inline-block;
  padding: 20px;
  /* 4px幅のボーダー */
  border: 4px solid blue;
  /* ボーダー領域の画像ソース(linear-gradient でグラデーションで表示) */
  border-image-source: linear-gradient( 135deg, blue, green );
  /* ボーダー領域の画像の分割数(グラデーションとボーダーを合わせる)  */
  border-image-slice: 1;
}

しかし、border-image-source を利用した場合、border-radius を指定してもボーダーが角丸になりません

角丸ボーダーでグラデーションを表現する方法としてよく見かけるものは、div 等で要素をラップしたり疑似要素(::before, ::after)を利用してラッパー要素を background-image でグラデーション背景にして、ラッパー要素より中心に縮小したインナー要素は background-color表示エリアの背景色と同じ色で塗りつぶしてラッパーとインナーの差分でグラデーションボーダーを表現するというもの。

ただし、この方法ではグラデーションボーダー要素が表示されるコンテンツエリア内の背景が単色でない場合や、背景画像を表示しているような場合は、ボーダー内の背景色が視覚的に浮いてしまい、汎用性は全くありません

そこで、ここではページの背景状態(背景色、グラデーション、背景画像)に依存せず、要素の内部背景は透過して角丸のアウトライン(枠線)のみがグラデーションで表示される汎用性の高い CSS を考えてみます。

完成例

See the Pen Untitled by digistate (@digistate) on CodePen.

background プロパティ

まず、疑似要素に background-image でグラデーション(linear-gradient)で塗りつぶします。

ボーダーの太さは疑似要素に対して直接 border プロパティで指定します(ボーダーカラーは透過)。

アウトラインのCSS
border: 4px solid transparent; /* ボーダーカラーは透過(transparent) */

上記で指定したボーダーの領域も含めてグラデーションで塗りつぶすため、background-image で指定したグラデーション背景を適用する基準位置(background-origin)と範囲(background-clip)に border-box を指定します。

グラデーション背景のCSS
background-image: linear-gradient(135deg, blue, green);  /* グラデーション背景 */
background-origin: border-box;  /* 背景の基準位置はボーダーも含める */
background-clip: border-box;  /* 背景の適用範囲はボーダーも含める */

これらを background プロパティのみ(ショートハンド)でまとめて指定した場合は以下のようになります。

background: linear-gradient(135deg, blue, green) border-box border-box;
表示例

mask プロパティ

続いて mask プロパティを利用してマスクレイヤーを表示し、ボーダーの太さ(border-width)より内側を切り抜くことでグラデーションボーダーを表現します。

具体的には、マスクレイヤーは mask-image プロパティで linear-gradient にてベタ塗りのレイヤーとして2つ定義します。
そして mask-clip プロパティにて2つのレイヤーの描画領域について、1つ目はボーダーより内側の境界まで(padding-box)とし、2つ目はボーダー領域を含めた要素全体の外周まで(border-box)を定義します。
最後に、レイヤーの合成方法を定義する mask-composite プロパティに exclude を指定することで、2つのレイヤーの重なっていない部分(ボーダー領域)を描画領域の対象として合成します。

Chromium 系のブラウザは exclude ではなく destination-out をベンダープレフィックス付きで指定します。
-webkit-mask-composite: destination-out

切り抜き用の CSS
// Chromium
-webkit-mask-image: linear-gradient(#fff 0 0), linear-gradient(#fff 0 0); /* 2つのマスクレイヤー */
-webkit-mask-clip: padding-box, border-box; /* レイヤーごとの描画領域の範囲 */
-webkit-mask-composite: destination-out; /* レイヤーが重なっていない領域を描画対象 */

// FireFox
mask-image: linear-gradient(#fff 0 0), linear-gradient(#fff 0 0);
mask-clip: padding-box, border-box;
mask-composite: exclude;

ショートハンドでまとめた場合は以下のようになります。

-webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
-webkit-mask-composite: destination-out;
mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
mask-composite: exclude;

先述の background プロパティとこの mask プロパティを組み合わせることで内部を透過した状態で角丸のグラデーションボーダーを表現できます。

全体の CSS
.button{
  position:relative;
  display:inline-block;
  padding:24px 28px;
}
  
.button::before{
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: 50px;
    border: 5px solid transparent;
    background: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%) border-box border-box;
    -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
    -webkit-mask-composite: destination-out;
    mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
    mask-composite: exclude;
  }
表示例
Share / Subscribe
Facebook Likes
Tweets
Hatena Bookmarks
Pinterest
Pocket
Feedly
Send to LINE