CSS 實現優惠券的技巧

在實際 Web 開發過程當中,總會遇到各類各樣的佈局。有公司同事問我這樣一種佈局有沒有什麼好的實現方式,就是一種在活動充值頁很是廣泛的優惠券效果,以下css

圖片

還有這樣的css3

圖片

考慮到各類可能出現的場景,抽象出如下幾種案例,一塊兒來看看實現吧web

圖片

1、最佳實現方式

首先,碰到這類佈局的最佳實現確定是mask遮罩。關於遮罩,能夠看一下CSS3 Mask 安利報告。這裏簡單介紹一下chrome

基本語法很簡單,和background的語法基本一致canvas

.content{
  -webkit-mask: '遮罩圖片' ;
}
/*完整語法*/
.content{
  -webkit-mask: '遮罩圖片' [position] / [size] ;
}

這裏的遮罩圖片和背景的使用方式基本一致,能夠是PNG圖片SVG圖片、也能夠是漸變繪製的圖片,同時也支持多圖片疊加api

遮罩的原理很簡單,最終效果只顯示不透明的部分,透明部分將不可見,半透明類推svg

圖片

事實上,除了根據透明度(Alpha)來做爲遮罩條件,還能夠經過亮度(luminance)來決定,好比白色表示隱藏,黑色表示可見。不過目前只有 Firefox 支持

因此,只要能繪製以上各類形狀,就能夠實現了。wordpress

2、內凹圓角

優惠券大多有一個很明顯的特色,就是內凹圓角。提到圓角,很容易想到radial-gradient?fileGuid=kDGWvXGxTXG6KrrQ)。這個語法有點複雜,記不住不要緊,能夠看看張老師的這篇10個demo示例學會CSS3 radial-gradient徑向漸變工具

.content{
  -webkit-mask: radial-gradient(circle at left center, transparent 20px, red 20px); 
}

圖片

這樣就繪製了一個半徑爲 20px 的透明的圓,不過代碼層面還有不少優化的空間。佈局

  1. 在實現邊界分明的漸變時,後面顏色的位置只須要小於等於前面顏色的位置就好了,好比0
  2. 透明顏色能夠用16進制縮寫好比#0000來代替不透明的部分隨便用一個顏色就好,我喜歡用red,主要是這個單詞比較短
  3. 還有漸變的位置默認是居中的,因此第二個center能夠去除,left 能夠用0來表示
測試發現移動端對 16 進制支持不加,因此仍是 須要採用 transparent 或者 rgba 的形式

進一步簡化就獲得了

.content{
  -webkit-mask: radial-gradient(circle at 0, #0000 20px, red 0); 
}

不錯,又少了好幾個B的流量~ 能夠查看在線實例codepen 優惠券實現1

3、優惠券效果

上面是一個最基本的內凹圓角效果,如今來實現下面幾種佈局,好比兩個半圓的,根據上面的例子,再複製一個圓不就能夠了?改一下定位的方向

.content{
  -webkit-mask: radial-gradient(circle at 0, #0000 20px, red 0), radial-gradient(circle at right, #0000 20px, red 0); 
}

圖片

這時發現一個圓都沒有了。緣由其實很簡單,以下演示,兩層背景相互疊加,致使整塊背景都成了不透明的,因此 mask 效果表現爲所有可見。

圖片

解決方式有2個,分別是:

  1. 把兩個凹角的地方錯開,這裏能夠經過修改尺寸和位置,同時還須要禁止平鋪
.content{
-webkit-mask: radial-gradient(circle at 0, #0000 20px, red 0), radial-gradient(circle at right, #0000 20px, red 0);
-webkit-mask-size: 51%; /*避免出現縫隙*/
-webkit-mask-position: 0, 100%; /*一個居左一個居右*/
-webkit-mask-repeat: no-repeat;
}

圖片

動態演示以下,這樣就不會互相覆蓋了

圖片

能夠查看在線實例codepen 優惠券實現2

  1. 使用遮罩合成mask-composite,這個可能不太熟悉,簡單介紹一下

標準屬性下mask-composite有 4 個屬性值(Firefox支持)

/* Keyword values */
mask-composite: add; /* 疊加(默認) */
mask-composite: subtract; /* 減去,排除掉上層的區域 */
mask-composite: intersect; /* 相交,只顯示重合的地方 */
mask-composite: exclude; /* 排除,只顯示不重合的地方 */

這個可能有些很差理解,其實能夠參考一些圖形軟件的形狀合成操做,好比 photoshop

圖片

-webkit-mask-composite與標準下的值有所不一樣,屬性值很是多,看下面

-webkit-mask-composite: clear; /*清除,不顯示任何遮罩*/
-webkit-mask-composite: copy; /*只顯示上方遮罩,不顯示下方遮罩*/
-webkit-mask-composite: source-over; 
-webkit-mask-composite: source-in; /*只顯示重合的地方*/
-webkit-mask-composite: source-out; /*只顯示上方遮罩,重合的地方不顯示*/
-webkit-mask-composite: source-atop;
-webkit-mask-composite: destination-over;
-webkit-mask-composite: destination-in; /*只顯示重合的地方*/
-webkit-mask-composite: destination-out;/*只顯示下方遮罩,重合的地方不顯示*/
-webkit-mask-composite: destination-atop;
-webkit-mask-composite: xor; /*只顯示不重合的地方*/

是否是一下就懵了?不用慌,能夠看到上面有幾個值是source-,還有幾個是destination-開頭的,source 表明新內容,也就是上面繪製的圖層,destination 表明元內容,也就是下面繪製的圖層(在CSS中,前面的圖層會覆蓋後面的圖層),這裏的屬性值實際上是借用了Canvas 中的概念,具體能夠查看CanvasRenderingContext2D.globalComposite

圖片

記不住不要緊,實際開發能夠逐一試驗[\捂臉]。具體差別能夠查看codepen -webkit-mask-composite 屬性值演示

圖片

瞭解這個屬性後,上面的疊加問題就很簡單了,設置只顯示重合的地方就好了

.content{
  -webkit-mask: radial-gradient(circle at 0, #0000 20px, red 0), radial-gradient(circle at right, #0000 20px, red 0); 
  -webkit-mask-composite: source-in | destination-in ; /*chrome*/
  mask-composite: intersect; /*Firefox*/
}

圖片

動態演示以下,這樣只會顯示互相重合的地方

圖片

能夠查看在線實例codepen 優惠券實現3

2個圓角的實現了,4個的就很容易了,畫4個圓就行,一樣利用遮罩合成能夠輕易實現

content{
  -webkit-mask: radial-gradient(circle at 0 0, #0000 20px, red 0), radial-gradient(circle at right 0, #0000 20px, red 0), radial-gradient(circle at 0 100%, #0000 20px, red 0), radial-gradient(circle at right 100%, #0000 20px, red 0); /*4個角落各放一個圓*/
  -webkit-mask-composite: source-in | destination-in ; /*chrome*/
  mask-composite: intersect; /*Firefox*/
}

圖片

能夠查看在線實例codepen 優惠券實現4

4、優惠券平鋪效果

上面的例子展現了2個圓角和4個圓角的效果,分別繪製了2個和4個圓,其實這是能夠經過平鋪來實現的,只須要一個圓就能夠。實現步驟以下

  1. 畫一個左中的靠邊的透明圓
.content{
  -webkit-mask: radial-gradient(circle at 20px, #0000 20px, red 0); 
}

圖片

  1. 向左平移自身的一半
.content{
  -webkit-mask: radial-gradient(circle at 20px, #0000 20px, red 0); 
  -webkit-mask-position: -20px
}
/*也能夠縮寫爲*/
.content{
  -webkit-mask: radial-gradient(circle at 20px, #0000 20px, red 0) -20px; 
}

圖片

效果就出來了,是否是很神奇?其實就是利用到了默認的repeat特性,這裏用一張動圖就能明白了

下面 紅色邊框內表示視區範圍,也就是最終的效果,這裏爲了演示,把視線以外的 平鋪作了半透明處理,移動表示 position 改變的過程

圖片

能夠查看在線實例codepen 優惠券實現5

一樣原理,4個圓角也能夠採用這種方式實現

.content{
  -webkit-mask: radial-gradient(circle at 20px 20px, #0000 20px, red 0); 
  -webkit-mask-position: -20px -20px;
}
/*也能夠縮寫爲*/
.content{
  -webkit-mask: radial-gradient(circle at 20px 20px, #0000 20px, red 0) -20px -20px; 
}

圖片

實現原理演示以下

圖片

能夠查看在線實例codepen 優惠券實現6

6個圓角就須要改一下平鋪尺寸了。

.content{
  -webkit-mask: radial-gradient(circle at 20px 20px, #0000 20px, red 0); 
  -webkit-mask-position: -20px -20px;
  -webkit-mask-size: 50%;
}
/*也能夠縮寫爲*/
.content{
  -webkit-mask: radial-gradient(circle at 20px 20px, #0000 20px, red 0) -20px -20px / 50%; 
}

圖片

實現原理演示以下

圖片

能夠查看在線實例codepen 優惠券實現7

若是繼續縮小背景圖的尺寸,還能夠獲得最後的效果

.content{
  -webkit-mask: radial-gradient(circle at 10px, #0000 10px, red 0); 
  -webkit-mask-position: -10px;
  -webkit-mask-size: 100% 30px;
}
/*也能夠縮寫爲*/
.content{
  -webkit-mask: radial-gradient(circle at 20px 20px, #0000 20px, red 0) -10px / 100% 30px; 
}

圖片

實現原理演示以下,其實就平鋪

圖片

能夠查看在線實例codepen 優惠券實現8

5、反向鏤空疊加

有些狀況下可能單一的一層漸變繪製不了很複雜的圖形,這就須要用到反向鏤空技術了,其實就是上面提到過的遮罩合成,這裏再運用一下

  1. 先把上面的實現拿過來
.content{
  -webkit-mask: radial-gradient(circle at 20px 20px, #0000 20px, red 0) -20px -20px / 50%; 
}

圖片

  1. 直接在這個基礎上打一排小洞
.content{
  -webkit-mask: radial-gradient( circle at 50%, red 5px, #0000 0) 50% 50% / 100% 20px, radial-gradient(circle at 20px 20px, #0000 20px, red 0) -20px -20px / 50%;
  -webkit-mask-composite: destination-out;
  mask-composite: subtract; /*Firefox*/
}

圖片

注意這裏用到了-webkit-mask-composite: destination-out表示減去,只顯示下方遮罩,重合的地方不顯示

圖片

能夠查看在線實例codepen 優惠券實現9

也能夠放在兩邊,改一下position就能夠了

.content{
  -webkit-mask: radial-gradient( circle at 5px, red 5px, #0000 0) -5px 50% / 100% 20px, radial-gradient(circle at 20px 20px, #0000 20px, red 0) -20px -20px / 50%;
  -webkit-mask-composite: destination-out;
  mask-composite: subtract; /*Firefox*/
}

圖片

能夠查看在線實例codepen 優惠券實現10

6、邊框遮罩

有些同窗以爲徑向漸變太複雜,實在是寫不出來,能不能用圖片代替呢?其實也是可行的。這裏說的邊框遮罩指的是mask-border, 目前還在 W3C 草案當中,不過有一個替代屬性-webkit-mask-box-image

圖片

語法和概念和border-image很是類似,關於border-image可參考這篇文章border-image 的正確用法,這裏主要了解一下用法和效果

.content{
  -webkit-mask-box-image: '遮罩圖片' [<top> <right> <bottom> <left> <x-repeat> <y-repeat>]
}

好比有一張這樣的圖片

圖片

SVG代碼長這樣,不少工具均可以導出來,實在不會能夠直接找設計同窗(也可採用.png格式

<svg xmlns="http://www.w3.org/2000/svg" width="60.031" height="60.031" viewBox="0 0 60.031 60.031"><path d="M40 60.027H20.129A20.065 20.065 0 0 0 .065 40H0V20.127h.065A20.066 20.066 0 0 0 20.131.061v-.065H40v.065a20.065 20.065 0 0 0 20.027 20.064V40A20.063 20.063 0 0 0 40 60.027z" fill-rule="evenodd"/></svg>

這裏須要轉義一下,可藉助張老師的SVG在線合併工具

.content{
  -webkit-mask-box-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60.031' height='60.031' viewBox='0 0 60.031 60.031'%3E%3Cpath d='M40 60.027H20.129A20.065 20.065 0 0 0 .065 40H0V20.127h.065A20.066 20.066 0 0 0 20.131.061v-.065H40v.065a20.065 20.065 0 0 0 20.027 20.064V40A20.063 20.063 0 0 0 40 60.027z' fill-rule='evenodd'/%3E%3C/svg%3E") 20;
  /*這裏的20表示四周保留20像素的固定區域,剩餘部分平鋪或者拉伸*/
}

而後就實現了這樣一個形狀,一樣是自適應的

圖片

能夠查看在線實例codepen -webkit-mask-box-iamge 實現1

再好比有一張這樣的圖片

圖片

.content{
  -webkit-mask-box-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60.031' height='60.031' viewBox='0 0 60.031 60.031'%3E%3Cpath d='M55.186 30.158a4.965 4.965 0 0 0 4.841 4.959V40A20.063 20.063 0 0 0 40 60.027H20.129A20.065 20.065 0 0 0 .065 40H0v-4.888c.054 0 .1.016.158.016a4.973 4.973 0 1 0 0-9.945c-.054 0-.1.014-.158.015v-5.074h.065A20.066 20.066 0 0 0 20.131.058v-.065H40v.065a20.065 20.065 0 0 0 20.027 20.064v5.07a4.965 4.965 0 0 0-4.841 4.966z' fill-rule='evenodd'/%3E%3C/svg%3E") 20;
}

能夠獲得這樣一個形狀,兩側的半圓被拉伸了

圖片

這時只須要設置平鋪方式-webkit-mask-box-image-repeat ,這個和border-image-repeat是同樣的概念,有如下 4 個值

-webkit-mask-box-image-repeat: stretch; /*拉伸(默認),不會平鋪*/
-webkit-mask-box-image-repeat: repeat; /*重複*/
-webkit-mask-box-image-repeat: round; /*重複,當不能整數次平鋪時,根據狀況拉伸。*/
-webkit-mask-box-image-repeat: space; /*重複,當不能整數次平鋪時,會用空白間隙填充*/

幾種平鋪方式的差別以下

圖片

這裏咱們能夠採用round或者repeat

.content{
  -webkit-mask-box-image: url("...") 20;
  -webkit-mask-box-image-repeat: round;
}

圖片

能夠查看在線實例codepen -webkit-mask-box-iamge 實現2

7、總結和說明

以上一共介紹了12種繪製優惠券的案例,應該能夠解決掉絕大部分這類佈局的問題,這裏總結如下幾點

  1. CSS mask必定是這類佈局最完美的實現方式
  2. 須要CSS radial-gradient繪製圖形的技巧
  3. 儘量採用repeat來重複相同的元素
  4. 多種形狀疊加時須要靈活運用mask-composite
  5. 也能夠採用圖片來代替CSS漸變,須要使用mask-border

關於兼容性,其實不考慮 IE 都沒有什麼大問題,最後的 mask-border 目前只兼容 chrome 內核,移動端可放心使用

感謝閱讀,但願能對往後的工做有所啓發。

相關文章
相關標籤/搜索