由小見大!不規則造型按鈕解決方案

chokcoco發表於2023-02-17

今天,有個群友在群裡提問,使用 CSS 能否實現下述這個圖形:

emmm,中間這個酷似三次貝塞爾曲線的造型,使用 CSS 不太好實現。我的建議是切圖實現,然而群友要求一定要用 CSS 實現。

雖然麻煩,但是這個圖形勉強也是能用 CSS 實現的。本文就將探討一下上述圖形的純 CSS 實現方式,並且從中進行一定的擴充套件延伸。

嘗試實現

這個圖形其實與我們的 Chrome Tab 按鈕非常類似,像是這樣:

不一樣之處在於,Chrome 的側邊其實是垂直的豎線,而上述的需求,側邊是一條斜線。

首先,我們快速看看這個 Chrome Tab 的互動應該如何實現:

我們對這個按鈕形狀拆解一下,這裡其實是 3 塊的疊加:

只需要想清楚如何實現兩側的弧形三角即可。這裡還是藉助了漸變 -- 徑向漸變,其實他是這樣,如下圖所示,我們只需要把黑色部分替換為透明即可,使用兩個偽元素即可:

程式碼如下:

<div class="outside-circle"></div>
.outside-circle {
    position: relative;
    background: #e91e63;
    border-radius: 10px 10px 0 0;

    &::before {
        content: "";
        position: absolute;
        width: 20px;
        height: 20px;
        left: -20px;
        bottom: 0;
        background: #000;
        background:radial-gradient(circle at 0 0, transparent 20px, #e91e63 21px);
    }
    &::after {
        content: "";
        position: absolute;
        width: 20px;
        height: 20px;
        right: -20px;
        bottom: 0;
        background: #000;
        background:radial-gradient(circle at 100% 0, transparent 20px, #e91e63 21px);
    }
}

即可得到:

上述的所有圖形的完整程式碼,你可以在這裡看到:CodePen Demo -- CSS Various Button Shapes | CSS 各種造型按鈕

那麼,問題來了,我們有沒有辦法,透過上述圖形,得到側邊兩條線是斜線的效果呢?

有了右邊的圖形,想要得到我們最終的效果不就手到擒來了麼?像是這樣:

那麼,怎麼實現呢?其實也非常好做,這裡利用了 CSS 3D 旋轉,形成了一種視覺上的景深效果,來實現側邊由豎直到斜邊的轉化。

看看程式碼,其實就兩行程式碼,在上述 outside-circle 的圖形基礎上:

  1. 設定一個適當的 perspective
  2. 設定一個恰當的旋轉圓心 transform-origin
  3. 繞 X 軸進行旋轉

程式碼非常簡單,我們其實只需要這樣:

.outside-circle {
    position: relative;
    background: #e91e63;
    border-radius: 10px 10px 0 0;
    transform: perspective(40px)  rotateX(20deg) ;
    transform-origin: 50% 100%;

    &::before { ... }
    &::after{ ... }
}

核心在於這兩句:

  • transform: perspective(40px) rotateX(20deg)
  • transform-origin: 50% 100%

製作一個動畫,會更好理解一點:

是的,再複述一次,這裡利用了 CSS 3D 旋轉,形成了一種視覺上的景深效果,來實現側邊由豎直到斜邊的轉化。

利用這個技巧實現梯形

通常,我們可以利用這個技巧,製作梯形,像是這樣:

.trapezoid{
    position: relative;
    width: 160px;
    padding: 60px;
}
.trapezoid:before{
    content:"";
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    transform:perspective(40px) scaleY(1.3) rotateX(5deg);
    transform-origin: bottom;
    background: deeppink;
}

效果如下:

還原題圖效果

好,理解了之後,還原題圖效果就很簡單了。我們只需要實現一邊的效果,再將整個圖形左移,利用父容器的 overflow: hidden 裁剪掉左邊部分,保留右邊即可。

完整的程式碼如下:

<div class="g-container">
    <div class="g-inner"></div>
</div>
.g-container {
    position: relative;
    width: 300px;
    height: 100px;
    background: #2cb2e0;
    border: 1px solid #277f9e;
    border-radius: 10px;
    overflow: hidden;
}
.g-inner {
    position: absolute;
    width: 150px;
    height: 50px;
    background: #fee6e0;
    bottom: 0;
    border-radius: 0 20px 0 20px;
    transform: perspective(40px) scaleX(1.4) scaleY(1.5) rotateX(20deg) translate(-10px, 0);
    transform-origin: 50% 100%;
    &::before {
        content: "";
        position: absolute;
        right: -10px;
        width: 10px;
        height: 10px;
        background: inherit;
        mask: radial-gradient(circle at 100% 0, transparent, transparent 9.5px, #000 10px, #000);
    }
}

這樣,我們就完美的實現了題目的效果:

完整的線上示意,戳這裡:CodePen Demo -- Unregular Border

最後

本文的目的更多的是介紹一種可行的小技巧,實際中實現上述的效果可能有更好的方法,譬如切圖?有更好的解法的,歡迎補充指正。

好了,本文到此結束,希望本文對你有所幫助 ?

更多精彩 CSS 技術文章彙總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

相關文章