你該知道的《css揭祕》--形狀篇
關於以下內容,我們假設結構層的變更是不允許的。
我們也儘量不去新增額外的HTML,以做到樣式層與結構層的分離,如若實在沒有其他的可能性,才退而求其次來增加額外的HTML。
自適應橢圓
製作一個自適應的橢圓是形狀篇中最簡單的圖形了,簡直不能再簡單了。眾所周知,製作與圓相關的圖形,用到的屬性就要 border-radius
了。我們知道,border-radius
可以單獨指定水平和垂直半徑,使用斜槓 (/) 來分開,兩個值相等可以製作一個圓弧,如果不相等,便是一個橢圓弧了。
.demo{
border-radius: 100px / 75px;
}
複製程式碼
其實border-radius是一個簡寫屬性,我們有兩種方式可以為元素的每個角指定不同的值。
第一種簡寫方式
.demo{
border-radius:10px 20px 30px 40px / 50px 60px 70px 80px;
/* 斜槓(/)前代表水平半徑,後代表垂直半徑,順序分別為左上角開始,順時針走向,所以這段程式碼表示左上角(10px/50px) 右上角(20px/60px)右下角(30px/70px)左下角(40px/80px) */
}
複製程式碼
第二種是分開寫的方式
.demo{
border-top-left-radius:10px/50px;
border-top-right-radius:20px/60px;
border-bottom-right-radius:30px /70px;
border-bottom-left-radius:40px/80px;
}
複製程式碼
如果生成一個自適應的橢圓就很簡單了,只要每個角的水平半徑為寬的50%,垂直半徑為高的50%,就ok了。 程式碼簡寫為:
.ellipse{
border-radius:50%;
}
複製程式碼
平行四邊形
平行四邊形也是頁面中常出現的一種圖形,我們可能很容易就想到,使用skew()將矩形傾斜一定角度即可。
.parallelograms{
transform: skew(-45deg);
/*...... */
}
複製程式碼
可惜效果不如人意,文字也跟著傾斜了,這時候很容易想到,藉助一層dom結構,再把內部文字傾斜回來。
<div class="parallelograms">
<div>二十首情詩與絕望的歌</div>
</div>
複製程式碼
.parallelograms{
margin: 50px auto;
max-width: 200px;
padding: 10px;
line-height: 30px;
text-align: center;
color:#fff;
background-color: #58a;
transform:skew(-45deg);
}
.parallelograms div{
transform: skew(45deg);
}
複製程式碼
很好,效果不錯,但是卻新增額外的 HTML 元素。我們不做過多討論。
接下來我們討論第二種方式,使用 偽元素來實現,這時候就體現了偽元素的好處。 關於偽元素的內容可參考我的另一邊文章你所不知道的css
思路:我們可以把偽元素作為第一種方法中的輔助結構層,把所有樣式(背景、邊框等)應用到偽元素上,然後再對偽元素進行變形,得到我們的平行四邊形形狀,而正式內容不受影響,然後把偽元素定位z-index
設為-1,便可漏出正文的內容。
.parallelograms{
margin: 50px auto;
max-width: 200px;
padding: 10px;
line-height: 30px;
text-align: center;
color:#fff;
position: relative;
}
.parallelograms:before{
content:'';
position: absolute;
left:0;
top:0;
right:0;
bottom:0;
background-color: #58a;
transform:skew(-45deg);
z-index: -1;
}
複製程式碼
提醒: 這個技巧不僅對 skew()
變形來說很有用,還適用於其他任何變形樣式, 當我們想變形一個元素而不想變形它的內容時就可以用到它。
菱形圖片
看到這個圖形狀,是不是馬上想起上一小節平行四邊形的製作,一樣的道理,需要把圖片用一個
包裹起來,然後對其應用相反的rotate()
變形樣式:
<div class="diamond">
<img src="https://avatars1.githubusercontent.com/u/8121621?v=4" alt="..." />
</div>
複製程式碼
.diamond {
margin:30px auto;
width: 100px;
height: 100px;
transform: rotate(45deg);
overflow: hidden;
border: 1px solid red; /*為了更好的展示問題*/
}
.diamond img {
max-width: 100%;
transform: rotate(-45deg);
}
複製程式碼
奈何,天不遂人願!問題在於 max-width:100%
中的100%是指width的100%,也就是400px,而正方形旋轉後最長邊為對角線,是 根號2倍的width,自然圖片的寬度不夠了,我們可以使用 scale() 變形樣式來把這個圖片放大。找到問題後,我們修復它,
.diamond {
margin:30px auto;
width: 100px;
height: 100px;
transform: rotate(45deg);
overflow: hidden;
border: 1px solid red; /*為了更好的展示問題*/
}
.diamond img {
max-width: 100%;
transform: rotate(-45deg) scale(1.42);
}
複製程式碼
這個方法需要一層額外的 HTML 標籤,這是我們不做優先考慮的。同時有一個最大的問題就是,只能處理正方形圖片,否則就會失效。
在上節中我們使用過偽元素的技巧,同樣可以用在這裡,程式碼如下:
.diamond{
margin:30px auto;
width: 100px;
height: 100px;
overflow: hidden;
position: relative;
transform: rotate(45deg);
}
.diamond:before{
content:'';
position: absolute;
left: 0;
right:0;
top:0;
bottom:0;
transform: rotate(-45deg) scale(1.42);
background: url(https://avatars1.githubusercontent.com/u/8121621?v=4);
background-size: cover;
}
複製程式碼
原理與上面藉助結構層是一樣的,所以面臨同樣的問題,只能處理正方形圖片。
接下來我們使用一種更為好用的方法來解決不是正方形的圖片。(裁切路徑方案)
丟擲程式碼:.diamond{
/*......*/
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
複製程式碼
clip-path
屬性是從svg中借鑑過來的,裁切路徑允許我們把元素裁剪為我們想要的任何形狀。polygon()函式允許我們用一系列(以逗號分隔的)座標點來指定任意的多邊形。
該方法同樣可以實現上個章節中的平行四邊形,以下章節中的切角、梯形等等任意形狀,只需要按順序排列座標點即可,以下章節不再做過多展示,自己可以多多嘗試。
切角效果
切角效果,很容易想到的就是我的上篇文章 你該知道的《css揭祕》--背景與邊框篇 中的條紋背景製作中用到的線性漸變 linear-gradient()
我們很輕易的可以實現一個角被切掉的效果,程式碼如下:
.bevel-corners{
background: #58a; /*linear-gradient不支援的情況下,作為程式碼回退機制*/
background:linear-gradient(-45deg, transparent 15px, #58a 0);
}
複製程式碼
接下來使用兩層漸變背景實現兩個角被切掉。
首先分析一下,預設情況下, 這兩層漸變都會填滿整個元素,因此它們會相互覆蓋。需要讓它們都縮小一些,於是我們使用background-size
讓每層漸變分別只佔據整個元素一半的面積,並且
background-repeat
設為
no-repeat
。
程式碼如下:
.bevel-corners{
background: #58a;
background:
linear-gradient(-45deg, transparent 15px, #58a 0) right,
linear-gradient(45deg, transparent 15px, #58a 0) left;
background-size:50% 100%;
background-repeat:no-repeat;
}
複製程式碼
同樣的原理,我們把每層漸變改為整個元素的四分之一,則四層漸變色,可以實現四個角被切掉。
程式碼如下:.bevel-corners{
background:#58a;
background:
linear-gradient(-45deg,transparent 15px, #58a 0) bottom right,
linear-gradient(45deg,transparent 15px, #58a 0) bottom left,
linear-gradient(135deg,transparent 15px, #58a 0) top left,
linear-gradient(-135deg,transparent 15px, #58a 0) top right;
background-size:50% 50%;
background-repeat:no-repeat;
}
複製程式碼
繼續增加難度,實現 弧形切角, 原理都一樣,換湯不換藥,只需將線性漸變改為徑向漸變即可。
實現程式碼如下:.scoop-corners{
background: #58a;
background:
radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right,
radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
}
複製程式碼
簡單的餅圖
實現最後一個圖形--餅圖(綠色為餅圖,棕色來顯示比率)
基於 transform 的解決方案
思路:把圓形的左右兩部分指定為上述兩種顏色,然後用偽元素覆蓋上去,通過旋轉來 決定露出多大的扇區。
20%的餅圖程式碼如下:
.pie {
width: 100px;
height: 100px;
border-radius: 50%;
background: yellowgreen;
background-image:linear-gradient(90deg, transparent 50%, #655 0);
}
.pie:before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
transform: rotate(.2turn);
}
複製程式碼
當旋轉超過50%之後,餅圖就變成了下圖這樣,
然後我們可以讓旋轉的偽元素的顏色反一下,變成棕色既可以實現50%-100%比率的餅圖,
60%的餅圖程式碼如下:
.pie:before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: #655;
transform-origin: left;
transform: rotate(.1turn);
}
複製程式碼