您好,登錄后才能下訂單哦!
這篇文章主要講解了“CSS如何實(shí)現(xiàn)漸變提示框”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“CSS如何實(shí)現(xiàn)漸變提示框”吧!
今天來(lái)看一種十分常見(jiàn)的交互:提示框(tooltips)。通常提示框都是純色的,比如下面這個(gè)
這類(lèi)布局實(shí)現(xiàn)還不算復(fù)雜,可以用一個(gè)圓角矩形和一個(gè)小三角拼接形成,設(shè)置相同的顏色就可以了
這個(gè)并不是本文的重點(diǎn),有興趣的可以訪(fǎng)問(wèn) css-tips (codepen.io)
https://codepen.io/xboxyan/pen/MLJjWQ
有時(shí)候,為了突出強(qiáng)調(diào)產(chǎn)品的特點(diǎn)或者為了跟隨設(shè)計(jì)的潮流,設(shè)計(jì)會(huì)用上漸變背景,比如 lulu UI Edge 版本中的 Tips 組件
如果仍然采用“拼接”的方式,不可避免會(huì)出現(xiàn)銜接不上的問(wèn)題,有明顯的“割裂”感,視覺(jué)還原會(huì)大打折扣
那么,如何實(shí)現(xiàn)這類(lèi)效果呢?一起來(lái)看看吧
clip-path 可能是很多人馬上就能想到的方式。但是實(shí)際操作下來(lái),還是會(huì)遇到很多麻煩
clip-path: path 可以支持任意形狀,但是卻沒(méi)法實(shí)現(xiàn)自適應(yīng)寬高
clip-path: polygon 可以實(shí)現(xiàn)小尖角,但是無(wú)法實(shí)現(xiàn)圓角
clip-path: inset 可以實(shí)現(xiàn)自適應(yīng)圓角矩形,但是無(wú)法實(shí)現(xiàn)下方的小尖角
如何解決這個(gè)問(wèn)題呢?其實(shí)把 2 和 3 結(jié)合起來(lái)就可以了
這里需要兩個(gè)相同大小的容器,可以用 ::before 和 ::after 來(lái)代替,然后設(shè)置相同的背景色,可以通過(guò)自定義屬性定義
.tips{ position: relative; --bg: linear-gradient(45deg, #ff3c41, #ff9800); } .tips::before,.tips::after{ content:''; position: absolute; width: 100%; height: 100%; left: 0; top: 0; background: var(--bg);/*完全相同的背景*/ z-index: -1; }
為什么要用兩個(gè)相同大小的容器呢? 這是為了保證接下來(lái)漸變背景在裁剪時(shí)完全吻合
接著其中一個(gè)裁剪成圓角矩形,另外一個(gè)裁剪成小三角,然后重疊起來(lái)就可以了
.tips::before{ clip-path: inset(0 0 5px 0 round 5px); /*round 可以設(shè)置圓角*/ } .tips::after{ clip-path: polygon(calc(50% - 5px) calc(100% - 5px), calc(50% + 5px) calc(100% - 5px), 50% 100%); /* 實(shí)現(xiàn)小三角,只需要3個(gè)點(diǎn)的坐標(biāo)就可以了 */ }
可以看到提示框完全是自適應(yīng)的,實(shí)時(shí)效果如下
完整代碼可訪(fǎng)問(wèn) tooltips-clip-path (codepen.io)
https://codepen.io/xboxyan/pen/ExWLyKR
除了 clip-path ,mask 也是一種思路。如果還不熟悉 mask,可以參考這一篇
奇妙的 CSS MASK (juejin.im)
https://juejin.cn/post/6846687594693001223
這里的原理如下
利用 mask ,現(xiàn)在的問(wèn)題就轉(zhuǎn)變成了:如何通過(guò) CSS 繪制這樣一個(gè)圖形?
沒(méi)有什么圖形是 CSS 漸變 繪制不出來(lái)的,這個(gè)也不例外。首先我們把這個(gè)圖形進(jìn)行分解,這里可以分成一個(gè)圓角矩形和一個(gè)三角形,三角形比較容易,可以通過(guò) conic-gradient 或者 linear-gradient 繪制
圓角矩形就稍微有點(diǎn)麻煩了,不過(guò)還是可以分解的,如下
可以由4個(gè)徑向漸變和2個(gè)線(xiàn)性漸變合成,用代碼實(shí)現(xiàn)就是
tips{ -webkit-mask-image: /*4個(gè)徑向漸變和2個(gè)線(xiàn)性漸變*/ radial-gradient(circle at 5px 5px, green 5px,transparent 0), radial-gradient(circle at 5px 5px, green 5px,transparent 0), radial-gradient(circle at 5px 5px, green 5px,transparent 0), radial-gradient(circle at 5px 5px, green 5px,transparent 0), linear-gradient(red,red), linear-gradient(blue,blue); -webkit-mask-size: 10px 10px, 10px 10px, 10px 10px, 10px 10px, 100% calc(100% - 15px), calc(100% - 10px) calc(100% - 5px) -webkit-mask-position: left top, right top, left 0 bottom 5px, right 0 bottom 5px, left 5px, 5px top; -webkit-mask-repeat: no-repeat }
只要有點(diǎn)耐心,都可以很順利的寫(xiě)出來(lái)
但是...
太長(zhǎng)了,有很多重復(fù)的(4個(gè)radial-gradient),非常啰嗦,有沒(méi)有什么辦法優(yōu)化呢?這里有一個(gè)技巧,碰到重復(fù)有規(guī)律的東西,可以多想想 repeat,利用背景的平鋪特性,合理設(shè)置背景尺寸就可以了,如下
可以看到,背景尺寸設(shè)置成 calc(100% - 10px) 就可以達(dá)到平鋪效果,代碼實(shí)現(xiàn)就是
tips{ -webkit-mask-image: /*只需要一個(gè)徑向漸變即可*/ radial-gradient(circle at 5px 5px, green 5px,transparent 0), linear-gradient(red,red), linear-gradient(blue,blue); -webkit-mask-size: calc(100% - 10px) calc(100% - 15px),/*圓角的尺寸,高度由于還需要減去三角形尺寸,所以多了5px*/ 100% calc(100% - 15px), calc(100% - 10px) calc(100% - 5px); -webkit-mask-position: left top, left 5px, 5px top; -webkit-mask-repeat: repeat,no-repeat,no-repeat; }
是不是精簡(jiǎn)了許多?然后再把三角形的合過(guò)來(lái)就行了,可以得到如下效果
完整代碼可訪(fǎng)問(wèn) tooltips-mask-gradient (codepen.io)
https://codepen.io/xboxyan/pen/KKWRWOj
盡管做了一些優(yōu)化,上面的代碼量仍然非常可觀(guān),有沒(méi)有更加簡(jiǎn)便的方式呢?
想到了 svg...
一般情況下,svg 路徑是固定尺寸的,只能 等比縮放 ,無(wú)法做到自適應(yīng)。不過(guò)基本圖形是支持自適應(yīng)的,可以設(shè)置百分比尺寸,比如 <rect>
<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%'> <rect rx="5" width='100%' height='100%'/> </svg>
rx
可以設(shè)置矩形的圓角,當(dāng)不設(shè)置 ry
時(shí),默認(rèn)與 rx
相同
這樣一個(gè) svg 是可以自適應(yīng)的,在改變尺寸的情況下不會(huì)變形(注意觀(guān)察圓角),如下
三角形就很容易了,可以用 <polygon>
實(shí)現(xiàn)
<svg xmlns='http://www.w3.org/2000/svg'> <polygon points='0 0,10 0,5 5' /> </svg>
然后,把兩段 svg 直接用作遮罩背景就行了,可以用 mask-size 和 mask-position 分別設(shè)置 尺寸 和 位置
tips{ -webkit-mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><polygon points='0 0,10 0,5 5' /></svg>"),url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect rx='6' width='100%' height='100%'/></svg>"); -webkit-mask-size: 10px 5px, 100% calc(100% - 5px); -webkit-mask-repeat: no-repeat; -webkit-mask-position: center bottom, 0 0; }
svg 用作背景需要在前面添加 data:image/svg+xml
,并且內(nèi)容需要轉(zhuǎn)義,詳細(xì)可參考這篇文章:
學(xué)習(xí)了,CSS中內(nèi)聯(lián)SVG圖片有比Base64更好的形式
https://www.zhangxinxu.com/wordpress/2018/08/css-svg-background-image-base64-encode/
還是挺不錯(cuò)的,代碼量也不多,也比較容易理解,實(shí)時(shí)效果如下
完整代碼可訪(fǎng)問(wèn) tooltips-mask-svg (codepen.io)
https://codepen.io/xboxyan/pen/poeVrqB
再來(lái)介紹一種未來(lái)的解決方式, CSS paint 。關(guān)于 CSS paint,又稱(chēng) “CSS 界的繪圖板”,簡(jiǎn)單來(lái)說(shuō),就是用 canvas 繪圖的方式來(lái)繪制背景,canvas 幾乎什么都能繪制吧,所以這是一種更為通用的解決方案。想快速了解 CSS paint 的可以參考這一篇入門(mén)文章:
CSS屆的繪圖板CSS Paint API簡(jiǎn)介
https://www.zhangxinxu.com/wordpress/2018/11/css-paint-api-canvas/
不過(guò)目前僅支持 Chrome,兼容性如下
不過(guò)并不影響我們的學(xué)習(xí),畢竟是未來(lái)的解決方案,先看看大致的語(yǔ)法,如下
1、首先,JS 注冊(cè)模塊 registerPaint
// paint-tips.js registerPaint('tips-bg', class { paint(ctx, size, properties) { // 在這里繪制背景,語(yǔ)法和canvas類(lèi)似 } });
2、接著,JS 添加模塊 CSS.paintWorklet.addModule
if (window.CSS) { CSS.paintWorklet.addModule('paint-tips.js'); }
3、最后,CSS 中使用 paint(tips-bg)
tips{ -webkit-mask-image: paint(tips-bg); /*這里作為遮罩背景使用*/ }
下面就來(lái)繪制提示框了,如果仍然借助 mask ,那么問(wèn)題就變成了:如何通過(guò) canvas 繪制這樣一個(gè)圖形?
在 canvas 中,相對(duì)于 CSS 來(lái)說(shuō), 這類(lèi)圖形簡(jiǎn)直就是小兒科,只需要使用 lineTo 和 arc 兩個(gè)指令就可以繪制了。最關(guān)鍵的一點(diǎn)是,這里的尺寸是實(shí)時(shí)渲染的,可以通過(guò) size 來(lái)獲取
關(guān)于 canvas 學(xué)習(xí),這里推薦一下張?chǎng)涡窭蠋煹?Canvas API中文文檔,api 和 案例比 mdn 文檔清晰太多
https://www.canvasapi.cn/
繪制代碼如下(下面就是很普通的 canvas 代碼了,其實(shí)就是幾段線(xiàn)段連接起來(lái),然后填充純色)
registerPaint('tips-bg', class { paint(ctx, size) { // ctx為繪制上下文,size為容器尺寸 const { width,height } = size; // 容器尺寸 const radius = 5; // 圓角大小 const deg = Math.PI / 2; const edge = 5; // 三角形大小 const pos = width / 2; // 三角形位置 ctx.beginPath(); ctx.moveTo(radius,0); ctx.lineTo(width-2*radius,0); ctx.arc(width-radius,radius,radius,-deg,0); ctx.lineTo(width,height-2*radius-edge); ctx.arc(width-radius,height-radius-edge,radius,0,deg); ctx.lineTo(pos+edge,height-edge); ctx.lineTo(pos,height); ctx.lineTo(pos-edge,height-edge); ctx.lineTo(radius,height-edge); ctx.arc(radius,height-radius-edge,radius,deg,2*deg); ctx.lineTo(0,radius-edge); ctx.arc(radius,radius,radius,-2*deg,-deg); ctx.closePath(); ctx.fillStyle = '#000'; ctx.fill(); } });
實(shí)時(shí)效果如下
完整代碼可訪(fǎng)問(wèn) tooltips-mask-paint (codepen.io)
https://codepen.io/xboxyan/pen/JjWvxEN
另外,也可以通過(guò) CSS 變量進(jìn)行自定義,比如定義一個(gè)--r
為圓角大小,--t
為三角形大小
<tips style="--r:5;--t:5"></tips>
registerPaint('tips-bg', class { static get inputProperties() { // 定義允許的自定義屬性 return [ '--r', '--t' ] } paint(ctx, size, properties) { // properties為自定義屬性 const radius = Number(properties.get('--r')); const edge = Number(properties.get('--t')); // ... } })
可以看到繪制是實(shí)時(shí)更新的(改變圓角),無(wú)需 JS 額外處理,實(shí)時(shí)效果如下
完整代碼可訪(fǎng)問(wèn) tooltips-mask-paint-var (codepen.io)
https://codepen.io/xboxyan/pen/JjWvVMd
有時(shí)候提示框可能還會(huì)有描邊的效果,比如這樣的
這類(lèi)帶描邊的其實(shí)以上方式都不太適用,clip-path 和 mask 都無(wú)法實(shí)現(xiàn)描邊,不過(guò)有一個(gè)邊框生成方案可以參考:
有意思!不規(guī)則邊框的生成方案 (juejin.cn)
https://juejin.cn/post/6944892753402822686
可惜效果不是特別完美(略微模糊)
如果尺寸固定,那么可以直接使用 svg 方式,參考這篇文章:
用SVG實(shí)現(xiàn)一個(gè)優(yōu)雅的提示框 (juejin.cn)
https://juejin.cn/post/6926353919333531661
就目前而言,確實(shí)沒(méi)有比較好的實(shí)現(xiàn)方案(有更好的實(shí)現(xiàn)方式歡迎補(bǔ)充,我暫時(shí)想不出來(lái)了),不過(guò)如果借助 CSS paint ,那一切就都有可能了!只需要在 paint 函數(shù)中繪制邊框和背景就行了
繪制代碼如下
registerPaint('tips-bg', class { paint(ctx, size) { const { width,height } = size; // 容器尺寸 const radius = 5; // 圓角大小 const deg = Math.PI / 2; const edge = 5; // 三角形大小 const pos = width / 2; // 三角形位置 const lineWidth = 2; // 描邊寬度 ctx.beginPath(); ctx.moveTo(radius+lineWidth,lineWidth); ctx.lineTo(width-2*radius-lineWidth,lineWidth); ctx.arc(width-radius-lineWidth,radius+lineWidth,radius,-deg,0); ctx.lineTo(width-lineWidth,height-2*radius-edge-lineWidth); ctx.arc(width-radius-lineWidth,height-radius-edge-lineWidth,radius,0,deg); ctx.lineTo(pos+edge,height-edge-lineWidth); ctx.lineTo(pos,height-lineWidth); ctx.lineTo(pos-edge,height-edge-lineWidth); ctx.lineTo(radius+lineWidth,height-edge-lineWidth); ctx.arc(radius+lineWidth,height-radius-edge-lineWidth,radius,deg,2*deg); ctx.lineTo(lineWidth,radius+lineWidth); ctx.arc(radius+lineWidth,radius+lineWidth,radius,-2*deg,-deg); ctx.closePath(); const gradient = ctx.createLinearGradient(0, 0, width, 0); // 漸變背景 gradient.addColorStop(0, '#F57853'); gradient.addColorStop(1, '#F8B578'); ctx.fillStyle = gradient; ctx.fill(); ctx.strokeStyle = '#FBF8F8'; // 繪制邊框 ctx.lineWidth = lineWidth; ctx.lineCap = 'round'; ctx.stroke(); } });
tips{ /* -webkit-mask-image: paint(tips-bg); */ background: paint(tips-bg); /*不再借助mask,純js繪制背景,包括漸變*/ }
實(shí)時(shí)效果如下
完整代碼可訪(fǎng)問(wèn) tooltips-paint-stroke (codepen.io)
https://codepen.io/xboxyan/pen/QWpxdVp
以上針對(duì) tooltips 布局共介紹了3種不同類(lèi)型的實(shí)現(xiàn)方式,分別是 clip-path、mask、CSS paint。其中 mask 的實(shí)現(xiàn)重點(diǎn)其實(shí)是CSS圖形的繪制,主要有 漸變 和 svg 兩種,雖然 漸變 的寫(xiě)法稍微復(fù)雜一點(diǎn),但是最為通用,其他方式可能換一種布局就不適用了?,F(xiàn)在總結(jié)一下要點(diǎn):
可以用多個(gè)容器重疊配合 clip-path 實(shí)現(xiàn)復(fù)雜的自適應(yīng)效果
在使用 CSS 漸變繪制圖形時(shí),相同的形狀充分利用平鋪特性
svg 基本形狀支持百分比尺寸,用作背景同樣有效,可以使用多張背景來(lái)組合
CSS paint 是未來(lái)的最佳解決方式,也能輕易的實(shí)現(xiàn)描邊效果
CSS paint 唯一的缺陷是兼容性不夠好(現(xiàn)僅支持 Chrome 65+ ),但是值得學(xué)習(xí)
當(dāng)然,這些方式不僅僅是實(shí)現(xiàn)本文的布局而已,更多的是提供一種思路,下次碰到其他的“異形布局”也能馬上聯(lián)想出相應(yīng)的解決方案,而不是選擇“切圖.png”。
感謝各位的閱讀,以上就是“CSS如何實(shí)現(xiàn)漸變提示框”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)CSS如何實(shí)現(xiàn)漸變提示框這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。