因爲是截圖,大小有些失真
看到這個圖,思考一下,就能明白,其實就兩個難點:css
- 左邊的鋸齒狀是如何實現
- 中間的凹陷是如何實現
上述兩個難點解決了,相信有css基礎的都能寫出這個組件。react
.sawtooth { /* 相對定位,方便讓before和after僞元素絕對定位偏移 */ position: relative; background:#e24141; width:400px; height:170px; } .sawtooth:before, .sawtooth:after { content: ' '; width: 0; height: 100%; /* 絕對定位進行偏移 */ position: absolute; top: 0; } .sawtooth:before { /* 圓點型的border */ border-right: 10px dotted white; /* 偏移一個半徑,讓圓點的一半覆蓋div */ left: -5px; } .sawtooth:after { /* 圓點型的border */ border-left: 10px dotted white; /* 偏移一個半徑,讓圓點的一半覆蓋div */ right: -5px; } <div class="sawtooth"></div>
效果以下:less
這個就是在開頭和最後畫了一個點狀邊框
,而後平移邊框,讓邊框的一部分覆蓋原來的邊框,利用圓點的顏色和背景色同樣的特色,製做鋸齒效果。若是不平移邊框效果以下:工具
.sawtooth:before { /* 圓點型的border */ border-right: 10px dotted white; /* 偏移一個半徑,讓圓點的一半覆蓋div */ left:0; } .sawtooth:after { /* 圓點型的border */ border-left: 10px dotted white; /* 偏移一個半徑,讓圓點的一半覆蓋div */ right: 0px; }
看了上圖實現原理是否是一目瞭然了。但這也有一些缺點:
1.鋸齒的顏色必須和背景色同樣
2.沒法畫鋸齒朝裏的方式
用徑向漸變建立圖像。
簡單語法:radial-gradient(circle, red 10px, blue 20px, yellow 30px);
形狀是圓(也能夠是橢圓),開始位置的顏色是red,中間顏色是blue,最後顏色是黃色。
10px表示從圓心開始10px範圍內都是紅色;
20px表示距離圓心20px的位置爲blue,而後向兩邊擴散,直到裏面10px的紅色區域,和向外30px地方的yellow區域;
30px表示從30px開始往外都是yellow。
.div{ margin:20px; height:100px; width:100px; background-image:radial-gradient(circle,red 10px,blue 20px,yellow 30px) }
- 圓心設置成透明
- 把過分顏色都設置成鋸齒的顏色
- 經過背景尺寸屬性設置背景圖的顏色,而後repeate
.div{ margin:20px; height:106px; width:140px; background-image: radial-gradient(circle at center, transparent 6px,#28ACFF 7px); background-size: 20px 15px; }
這樣一個帶圓點背景的div就出來了。而後經過設置寬度,只顯示半個圓,左邊的鋸齒就出來了。width設置成10px以下效果flex
這個實現就比較簡單了,經過絕對定位,用一個圓形元素覆蓋父元素的邊框。this
在實現時遇到一個問題,就是子元素移動過去了,可是沒法覆蓋父元素的邊框。這時,須要在組件外再套一層div,這個div設置成相對定位,而後把圓div設置成相對定義,再移動位置就能覆蓋裏面的組件div了。spa
經過上述的講解,須要實現優惠卷所須要的知識點就都講完了,下面讓咱們來實現開始效果的優惠卷吧。.net
.parentContainer { position:relative; margin:20px; overflow:hidden; } .container { display:flex; border:1px solid #ddd; border-radius:3px; width:300px; height:105px; border-left:0; } .left { width:10px; height:106px; left:-1px; border:0px solid #ddd; border-radius:3px; background-image:radial-gradient(circle at center,transparent 6px,#28ACFF 4px); background-size:20px 15px; z-index:1 } .couponName { text-align:center; border:0px solid red; line-height:106px; font-size:40px; font-family:PingFangSC-Medium; font-weight:500; color:rgba(40,172,255,1); margin-left:20px; margin-right:16px; } .subName { font-size:20px; } .topSemicircle { width:20px; height:20px; border:1px solid #ddd; border-radius:10px; position:absolute; left:80px; top:-16px; padding:0; background-color:#fff; } .bottomSemicircle { width:20px; height:20px; border:1px solid #ddd; border-radius:10px; position:absolute; left:80px; bottom:-16px; padding:0; background-color:#fff; } .dashed { border:1px dashed #ddd; margin-top:11px; margin-bottom:11px; } .right { display:flex; flex-direction:column; justify-content:center; align-items:flex-start; padding-left:10px; } .desc { font-size:10px; font-family:PingFangSC-Regular; font-weight:400; color:rgba(170,170,170,1); margin-top:10px; } <div class="parentContainer"> <div class="container"> <div class="left"></div> <div class="couponName">8<span class="subName">折</span></div> <div class="dashed"></div> <div class="right"> <div>折扣卷7.5折</div> <div class="desc">400張</div> <div class="desc">有效時間:2018.09.21-2018.10.21</div></div> <div class="topSemicircle"></div> <div class="bottomSemicircle"></div> </div> </div>
能夠把代碼賦值到下面的在線工具中看下效果
https://c.runoob.com/front-en...3d
根據本身須要再寫成react版本,就易如反掌了。
//less .parentContainer { position: relative; margin: 20px; overflow: hidden; } .container { display: flex; border: 1px solid #ddd; border-radius: 3px; width: 312px; height: 105px; border-left: 0; } .left { width: 10px; height: 106px; left: -1px; border: 0px solid #ddd; border-radius: 3px; background-image: radial-gradient( circle at center, transparent 6px, #28acff 4px ); background-size: 20px 15px; z-index: 1; } .leftInvalid { .left; background-image: radial-gradient( circle at center, transparent 6px, #aaaaaa 4px ); } .couponName { text-align: center; border: 0px solid red; line-height: 106px; font-size: 40px; font-family: PingFangSC-Medium; font-weight: 500; color: rgba(40, 172, 255, 1); min-width: 62px; margin-left: 20px; margin-right: 16px; } .couponNameInvalid { .couponName; color: #aaaaaa; } .title { font-size: 16px; font-weight: 400; color: rgba(51, 51, 51, 1); } .invalidTitle { .title; color: rgba(170, 170, 170, 1); } .subName { font-size: 20px; } .semicircle { width: 20px; height: 20px; border: 1px solid #ddd; border-radius: 10px; position: absolute; left: 98px; padding: 0; background-color: #fff; } .topSemicircle { .semicircle; top: -16px; } .bottomSemicircle { .semicircle; bottom: -16px; } .dashed { border: 1px dashed #ddd; margin-top: 11px; margin-bottom: 11px; } .right { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; padding-left: 10px; } .desc { font-size: 10px; font-family: PingFangSC-Regular; font-weight: 400; color: rgba(170, 170, 170, 1); margin-top: 10px; } //組件代碼 import React, { PureComponent } from 'react' import styles from './index.less' export default class CouponCard extends PureComponent { render() { const { valid = true, data = { id: 2323, couponDescription: '折扣卷8.5折', validDate: '2018.08.22-2018.09.12', number: 23, amount: 8.5, unit: '折', }, } = this.props const amounts = data.amount.toString().split('.') return ( <div className={styles.parentContainer}> <div className={styles.container}> <div className={valid ? styles.left : styles.leftInvalid} /> <div className={valid ? styles.couponName : styles.couponNameInvalid}> {amounts[0]} <span className={styles.subName}> {amounts[1] ? `.${amounts[1]}` : ''} {data.unit} </span> </div> <div className={styles.dashed} /> <div className={styles.right}> <div className={valid ? styles.title : styles.invalidTitle}> 折扣卷{data.amount} {data.unit} </div> <div className={styles.desc}>{data.number}張</div> <div className={styles.desc}>有效時間:{data.validDate}</div> </div> <div className={styles.topSemicircle} /> <div className={styles.bottomSemicircle} /> </div> </div> ) } }
參考連接code