巧用 CSS 實現(xiàn) Deepseek 都無法實現(xiàn)的復雜怪狀按鈕 - 內凹平滑圓角
本文,我們將探討另外一個非常有意思的圖形 -- 內凹平滑圓角:
有點類似于 Chrome Tab 按鈕造型,此圖形我們在 使用 CSS 輕松實現(xiàn)高頻出現(xiàn)的各類奇形怪狀按鈕[2] 討論過如何解決實現(xiàn)。
常見于這樣的設計中:
內凹平滑圓角實現(xiàn)上的難點
上面提到的 Chrome TAB 圖形,常見的解決方案如下:
但是內凹平滑圓角實現(xiàn)上的難點在于 -- 內凹部分要求是透明的!
什么意思呢?思考上面的圖形,如果紅色部分要求是整個透明,而白色部分進行顏色填充,試想一下,是不是比較難實現(xiàn)呢?
巧妙通過 mask 圖形拼接實現(xiàn)內凹平滑圓角
好的,如果不考慮透明這個因素,要拼接出內凹平滑圓角其實并不困難。
下面我通過一個動畫,給出內凹平滑圓角的拼接過程:
<div class="inner-curve-1">
<div class="g-rect"></div>
</div>
@property --ca {
syntax: '<color>';
inherits: false;
initial-value: #000;
}
@property --cb {
syntax: '<color>';
inherits: false;
initial-value: #ce03f1;
}
@property --cc {
syntax: '<color>';
inherits: false;
initial-value: #ce03f1;
}
.inner-curve-1 {
width: 300px;
height: 100px;
background: radial-gradient(circle at 50% -10px, var(--cc), var(--cc) 40px, #3f51b5 calc(40px + 0.5px), #3f51b5);
animation: colorChange 6s infinite linear;
.g-rect {
position: absolute;
width: 300px;
height: 20px;
left: 0;
top: -15px;
background: linear-gradient(90deg,var(--ca), var(--ca) 93px, transparent 93px, transparent calc(300px - 93px), var(--ca) calc(300px - 93px), var(--ca));
z-index: -1;
animation: colorChange 6s infinite linear;
}
&::before,
&::after {
content: "";
position: absolute;
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--cb);
top: -15px;
left: 72px;
animation: colorChange 6s infinite linear;
}
&::after {
left: unset;
right: 72px;
}
}
@keyframes colorChange {
0% {
--ca: #000;
--cb: #ce03f1;
--cc: #ce03f1;
}
70%,
100% {
--ca: #3f51b5;
--cb: #3f51b5;
--cc: #fff;
}
}
我們能得到這么一個有意思的變換效果,本質上還是不同形狀圖形的拼接,動畫示意下,應該非常好理解:
當然,這里為了讓大家更好的理解,利用了幾個元素(算上偽元素),并且,實際最后白色的部分并非透明的!
重點來了,利用多重 mask 實現(xiàn)裁剪拼接
如果我們希望白色部分一整個是透明的,可以如何處理呢?這里就需要運用上 mask,通過在一個元素內部進行裁剪、拼接,最終得到一個鏤空的內凹平滑圓角:
<div class='inner-curve-2'></div>
.inner-curve-2 {
--r: 20px;
--s: 40px;
--a: 20deg;
--_m:0/calc(2*var(--r)) var(--r) no-repeat
radial-gradient(50% 100% at bottom,#000 calc(100% - 1px), transparent);
--_d:(var(--s) + var(--r))*cos(var(--a));
width: 300px;
height: 100px;
mask:
calc(50% + var(--_d)) var(--_m),calc(50% - var(--_d)) var(--_m),
radial-gradient(var(--s) at 50% calc(-1*sin(var(--a))*var(--s)),
transparent 100%,#000 calc(100% + 1px)) 0 calc(var(--r)*(1 - sin(var(--a)))),
linear-gradient(90deg,#000 calc(50% - var(--_d)), transparent 0 calc(50% + var(--_d)),#000 0);
mask-repeat: no-repeat;
}
效果如下:
并且,它是真實的支持鏤空的。我們將上面兩種方式實現(xiàn)的鏤空的內凹平滑圓角,放在一個漸變背景下,就能看出差別:
上述兩種方式的完整代碼,你在這里可以看到:CodePen Demo -- 內凹平滑圓角 - inner curve[3]
此方法,最早見于 CSS Shape - Inner Curve/Notch[4],如果覺得的對于上述的 CSS 變量有點難以理解,可以通過上述鏈接[5],實現(xiàn)角度大小的在線編輯:
AI 挑戰(zhàn)
那么,這種復雜度的圖形,現(xiàn)在的 AI 模型能夠實現(xiàn)嗎?我們嘗試一下,分別把樣式造型傳給 豆包 與 deepseek。
豆包實現(xiàn)
豆包顯然沒這個能力,最終的實現(xiàn)一看就知道是錯誤的。
將代碼貼到 IDE 上,展示為一個矩形:
deepseek 實現(xiàn)
再試一下 deepseek。由于 deepseek 不支持不帶文字的圖片,且上傳圖片后補支持聯(lián)網搜索,我們只能盡可能的描述清楚需求:
deepseek 需求描述:使用 HTML +CSS 實現(xiàn)一個內凹的平滑圓角圖形,類似中文漢字中的凹字,但是凹陷部分是平滑曲線,在凹字上方的四個拐角,都是平滑曲線。整個凹字內部填充為一個顏色,其余部分皆為透明色。
deepseek 思考過程:
好的,我現(xiàn)在需要幫用戶用HTML和CSS實現(xiàn)一個內凹的平滑圓角圖形,類似“凹”字,但凹陷部分是平滑曲線。整個內部填充顏色,其余透明。首先,我得考慮如何構造這樣的形狀。
常見的 CSS 形狀制作方法有幾種:使用邊框、偽元素、clip-path,或者 SVG。因為需要內凹的曲線,可能 clip-path 或徑向漸變比較合適。但 clip-path 的瀏覽器支持可能有問題,特別是如果需要更復雜的路徑的話?;蛘?,可以考慮使用多個元素疊加,通過overflow:hidden 來隱藏部分區(qū)域。
用戶要求凹陷部分是平滑曲線,所以可能需要貝塞爾曲線或者圓形切割。比如,可以用一個大的矩形,然后在中間用兩個圓形來切割出凹陷的效果?;蛘呤褂脧较驖u變來創(chuàng)建凹陷的陰影效果,但可能不夠精確。
另一個思路是使用偽元素。主元素是一個矩形,然后使用 ::before或 ::after 偽元素來創(chuàng)建凹陷的部分。比如,主元素設置背景色,然后用偽元素覆蓋中間部分,形成凹陷。但這樣需要偽元素的形狀是圓形或橢圓,并且通過定位來覆蓋中間區(qū)域,同時設置mix-blend-mode 或者背景剪切,但可能比較復雜。
或者,使用 CSS 的 mask 屬性,通過遮罩來創(chuàng)建透明區(qū)域。這可能更靈活。比如,創(chuàng)建一個矩形,然后用徑向漸變作為 mask,中間部分透明,周圍不透明,這樣顯示出來的就是中間凹陷的形狀。但需要注意瀏覽器兼容性。
或者,使用 SVG 內聯(lián),直接繪制路徑,這樣更精確,但用戶可能希望純 CSS 實現(xiàn)。
再仔細想,clip-path 屬性可以用多邊形或圓形來剪切元素。比如,可以定義一個矩形的 clip-path,然后在中間挖一個圓形的區(qū)域。但 clip-path 目前不支持排除操作,無法直接挖洞??赡苄枰M合多個形狀。
另一種方法是使用 CSS 漸變。比如,在元素中間放置一個徑向漸變,從透明到顏色,這樣中間看起來是凹陷的。但這樣可能只是顏色漸變,而不是真正的形狀凹陷。
或者,使用多個 box-shadow 來模擬凹陷效果,但可能不夠精確。
綜合考慮,可能使用偽元素疊加的方法。主元素是一個矩形,設置 overflow:hidden,然后內部有一個偽元素,定位到中間,用更大的尺寸和背景色,然后通過 border-radius 和 transform 來 創(chuàng)建凹陷效果。或者,主元素是一個圓角矩形,然后偽元素是一個圓形,覆蓋在中間上方,通過背景色和位移來形成凹陷。
例如,主元素是一個矩形,背景色為紅色,然后偽元素是一個更大的圓形,背景色為透明,通過 border 來顯示周圍的部分,但這樣可能不太容易。
或者,使用兩個元素疊加:外部容器是一個矩形,內部有一個圓形元素,通過overflow:hidden和定位,讓內部元素遮蓋中間部分,形成凹陷。但這樣需要外部容器背景透明,內部元素背景色,中間被遮蓋的部分透明,可能比較復雜。
或者,使用 CSS 的 mask-composite 屬性,但兼容性可能不好。
deepseek 實現(xiàn)效果
Wow,從我的角度,看上面的分析,deepseek 的思考能力已經超強了,并且能夠將 CSS 中一些比較高階的屬性 clip-path、mask、mix-blend-mode 進行組合使用,實屬不易!
最終,看看 deepseek 給出的解法:
<div></div>
div {
position: relative;
margin: auto;
width: 200px;
height: 100px;
}
/* 主體顏色層 */
div::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: #2196F3;
clip-path: path('M0 10 Q0 0 10 0 H190 Q200 0 200 10 V40 Q180 50 200 60 V90 Q200 100 190 100 H10 Q0 100 0 90 V60 Q20 50 0 40 V10');
border-radius: 8px;
}
/* 平滑過渡層 */
div::after {
content: '';
position: absolute;
width: calc(100% - 4px);
height: calc(100% - 4px);
top: 2px;
left: 2px;
background: #2196F3;
clip-path: path('M2 12 Q2 2 12 2 H188 Q198 2 198 12 V38 Q178 50 198 62 V88 Q198 98 188 98 H12 Q2 98 2 88 V62 Q22 50 2 38 V12');
filter: blur(1px);
opacity: 0.8;
}
最終效果如下:
已經非常接近了,當然,內凹上方的曲線并非平滑連接。但是,如此復雜的圖形,dp 已經可以通過思考過程,給我們實現(xiàn)它提供非常多的參考。假以時日,這種圖形化問題,對于大模型而言,應該也都不在話下了。
最后
好了,本文到此結束,一個非常有意思的通過 CSS 拼接/裁剪/遮罩方式得到內凹圓角的技巧,希望本文對你有所幫助。
參考資料:
[1]巧用 CSS 實現(xiàn)高頻出現(xiàn)的復雜怪狀按鈕 - 鏤空的內凹圓角邊框: https://github.com/chokcoco/iCSS/issues/271。
[2]使用 CSS 輕松實現(xiàn)高頻出現(xiàn)的各類奇形怪狀按鈕: https://github.com/chokcoco/iCSS/issues/152。
[3]CodePen Demo -- 內凹平滑圓角 - inner curve: https://codepen.io/Chokcoco/pen/ExqzaXd。
[4]CSS Shape - Inner Curve/Notch: https://css-shape.com/inner-curve/。
[5]上述鏈接: https://css-shape.com/inner-curve/。
[6]Github -- iCSS: https://github.com/chokcoco/iCSS。