灵活的椭圆
这里要注意,border-radius是个简写,它可以拆成4个部分,8个值。
border-top-left-radius
border-top-right-radius
border-bottom-right-radius
border-bottom-left-radius
可以简写到一个里面,规则和padding什么的一样。
border-radius: 50% / 50px 20px;
比如这个,就相当于:
border-bottom-left-radius: 50% 20px;
border-bottom-right-radius: 50% 50px;
border-top-left-radius: 50% 50px;
border-top-right-radius: 50% 20px;
那半个椭圆就是:
border-radius: 50% / 100% 100% 0 0;
4分之一个椭圆:
border-radius: 100% 0 0 0;
平行四边形
这里准备采用的办法是使用transform来水平拉伸矩形成为平行四边形,如果直接这样做会同时把里面的内容拉伸,解决办法就是使用一个伪元素。(如果你想使用两个元素的话。。。当我啥都没说)
#Parallelograms {
position: relative;
padding:10px;
margin:10px;
}
#Parallelograms::before {
content: ''; /* To generate the box */
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
background: #58a;
transform: skew(-45deg);
}
这里的伪元素相对生成元素使用绝对定位,并完全规定了所有位置将伪元素拉满了生成元素。然后把它扯歪。这样就不会影响到元素内的内容了。
这种做法不止适用于菱形,还适用于所有想要变形但不影响内容的操作。还可以用来在IE8中产生多重背景,之前的外方内圆也可以用这个来实现。或者使用这个来创建使用opacity属性只透明背景色。或者多重边框也可以。
菱形图片
之前一般使用图片处理软件来实现,但是这样显然不够灵活。
使用变形
<div class="picture">
<img src="img/adamcatlace.jpg" alt="..." />
</div>
.picture {
margin:50px;
width: 200px;
transform: rotate(45deg);
overflow: hidden;
}
.picture > img {
max-width: 100%;
transform: rotate(-45deg) scale(1.42);
}
这里之所以使用scale来放大img而不直接使用width,是因为在浏览器不支持transform时显示还是正常的,否则图片会被直接放大,现在这样只有支持transform的浏览器会对图片进行旋转和放大。
这个方法并不优雅,使用了新的HTML元素。如果图片不是正方的。。。那就悲剧了。。
clip-path
这是从SVG那边借鉴来的特性直接应用在元素上,把元素剪为指定的形状。
在这里使用的是多边形polygon()函数,这个函数通过规定多边形端点在元素原本矩形形状中的位置来创建。
我们之前要创建的形状这里就是polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
这里使用这个还有一个很棒的好处,这个属性是直接支持CSS动画的,只要函数相同(同是polygon),顶点数也相同,就可以应用动画。
#picture-clip-path {
-webkit-clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
clip-path: polygon(50% 0, 100% 50%,50% 100%, 0 50%);
transition: 1s;
}
#picture-clip-path:hover {
clip-path: polygon(0 0, 100% 0,100% 100%, 0 100%);
-webkit-clip-path: polygon(0 0, 100% 0,100% 100%, 0 100%);
}
切角
就是元素有一个或多个角是不全的,这个以前多是由图片或hack(添加一个绝对定位元素)实现的。显然应该有更好的方法。
gradient
这个只使用有方向的linear gradient就可以解决。
#corner-cut1{
width:100px;
height:100px;
background: #58a;
background:
linear-gradient(135deg, transparent 15px, #58a 0) top left,
linear-gradient(-135deg, transparent 15px, #655 0) top right,
linear-gradient(-45deg, transparent 15px, #58a 0) bottom right,
linear-gradient(45deg, transparent 15px, #655 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
}
4个角,对应4个背景,每个背景占1/4,每个背景都是一个相应方向的linear gradient。要注意,linear gradient这个东西是默认接管整个元素背景的,如果不禁止重复的话,会造成最后一个覆盖所有。
这个如果使用SCSS的mixin会方便一点:
@mixin beveled-corners($bg, $tl:0, $tr:$tl, $br:$tl, $bl:$tr) {
background: $bg;
background:
linear-gradient(135deg, transparent $tl, $bg 0) top left,
linear-gradient(225deg, transparent $tr, $bg 0) top right,
linear-gradient(-45deg, transparent $br, $bg 0) bottom right,
linear-gradient(45deg, transparent $bl, $bg 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
}
#corner-cut1{
width:100px;
height:100px;
@include beveled-corners(#58a, 15px, 5px);
}
这里使用了默认值,传1-5个参数都可以。
弯曲的切角
这里的实现和上面的思想是一样的,换成radial-gradient即可:
#corner-cut2{
width:100px;
height:100px;
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;
}
SVG加border-image
使用上面的办法有几个问题,首先就是代码太复杂,要改颜色和切角的大小要改的太多了;还有就是这种方式并不能支持动画。
我们还可以采用外的两个方法来克服这个缺点,这个方法需要写内联的SVG代码。
#corner-cut3{
border: 20px solid #58a;
border-image: 1 url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="%2358a">\
<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"/>\
</svg>');
background: #58a;
background-clip: padding-box;
}
这里要控制切角的大小,只需改变border的宽度,这个宽度是可以应用CSS动画的哦。而且背景与边框的样式不再关联了,背景想是啥是啥。这里给border设置了一个颜色作为fallback。
clip-path
以上两种方法的局限是只能使用很有限样式的边框,如果我们想要图片是背景而且要切角呢?
就用之前的办法咯~
#corner-cut4{
background-image: url("../img/adamcatlace.jpg");
width:100px;
height:100px;
-webkit-clip-path: polygon(20px 0, calc(100% - 20px) 0, 100% 20px, 100% calc(100% - 20px), calc(100% - 20px) 100%, 20px 100%, 0 calc(100% - 20px), 0 20px );
clip-path: polygon(20px 0, calc(100% - 20px) 0, 100% 20px, 100% calc(100% - 20px), calc(100% - 20px) 100%, 20px 100%, 0 calc(100% - 20px), 0 20px );
}
将来
在Level 4的CSS背景与边框中,新引入了corner-shape属性,将来就方便咯。
梯形
梯形的形状广泛的被用于标签页的形状。
这里利用transform 3D,使用近大远小的效果创建两边倾斜的元素。
.trapezoid {
position: relative;
display: inline-block;
padding: .3em 1em 0;
margin-right:-15px;
//background: rgba(255,255,255,0.5);
}
.trapezoid::before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
background: #ccc;
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,0));
border: 1px solid rgba(0,0,0,.4);
border-bottom: none;
border-radius: .5em .5em 0 0;
box-shadow: 0 .15em white inset;
transform: perspective(.5em) rotateX(5deg);
transform-origin: bottom;
}
相较于以前前后加两个伪元素使用border来模拟,这个方法更加灵活,想给整个梯形加个边框加个圆角什么的非常容易,原来的方法你试试。
通过改变transform-origin,可以改变梯形两边倾斜的角度,或者只让一边倾斜。
简单的饼图
使用transform
我们想只用一个元素,最多再加一个伪元素来实现这个。
我们首先需要一个圆:
.pie {
width: 100px;
height: 100px;
border-radius: 50%;
background: yellowgreen;
}
我们把它分为两半,左边的一半颜色是背景,右边半的颜色用来表示百分比:
background-image: linear-gradient(to right, transparent 50%, #655 0);
此时这个元素的样子就像是50%的饼图。
接下来就轮到伪元素上场了,在0-50%时,我们使用一个与背景色相同的半圆伪元素,利用transform围绕圆的中心旋转遮住元素右边的一部分,使用未遮住的部分来表示百分比。在50%-100%时,使用一个与百分比背景颜色相同的半圆伪元素,遮住部分左边背景色部分,并与原元素右边一起组成大于50%的百分比。
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background: #655;
transform-origin: left;
transform: rotate(.1turn);
}
好了,这样的话我们有了一个可以使用transform:rotate和伪元素背景来控制的饼图。这显然是不灵活的。
不过想要直接通过这样的方式来控制CSS显然是不现实的:
<div class="pie">20%</div>
<div class="pie">60%</div>
为了实现这样的灵活性,我们首先做一个铺垫,使用CSS3动画循环整个0-100%的过程:
@keyframes spin { to { transform: rotate(.5turn); } }
@keyframes bg { 50% { background: #655; } }
.pie {
position: relative;
width: 100px;
line-height: 100px;
border-radius: 50%;
background: yellowgreen;
background-image: linear-gradient(to right, transparent 50%, #655 0);
color: transparent;
text-align: center;
}
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
animation: spin 3s linear infinite,
bg 6s step-end infinite;
}
这里的动画在6秒钟的过程中,前3秒伪元素背景就是背景的颜色,转180度到50%;
在第3秒时,伪元素背景变为百分比的颜色并回到初始位置,与刚才结束时一样表示50%,但是在这个瞬间是有闪烁的,不过没关系,我们最后并不真的使用这个动画效果本身。
后三秒伪元素转180度,结束在100%的位置。
好了,那么这个动画到底有什么作用呢?
我们使用一个我们不太好想到的特性,将动画的animation-delay设为一个负值,这个属性本来是控制动画延迟开始时间的,当它是负值时,规范规定它和将这个值设为0一样,动画会马上开始,但是动画会自动的从这个负值的绝对值处开始,也就是这个值前面的那些动画被跳过。想想这个设定挺符合逻辑的。
再使用animation-play-state: paused使动画一开始就停住。
animation: spin 50s linear infinite,
bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
这样我们就可以直接使用内联样式来控制饼图了(记得把伪元素的animation-delay设置为继承):
<div class="pie" style="animation-delay: -20s"></div> <div class="pie" style="animation-delay: -60s"></div>
如果你一定要用:
<div class="pie">20%</div>
<div class="pie">60%</div>
再使用JS将这个值读出来赋给style就好。
这个思想适用于很多地方,比如你想要个渐变的颜色,你又懒得自己调颜色,那你可以使用这种办法,一个从一种颜色到另一种的动画。
.pie {
position: relative;
width: 100px;
line-height: 100px;
border-radius: 50%;
background: yellowgreen;
background-image: linear-gradient(to right, transparent 50%, #655 0);
color: transparent;
text-align: center;
}
@keyframes spin {
to {
transform: rotate(.5turn);
}
}
@keyframes bg {
50% {
background: #655;
}
}
.pie::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
animation: spin 50s linear infinite,
bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
}
SVG
利用一个圆,加一个dash形状的粗边框来实现,dash的粗边框可以控制dash的长度和空的长度,设置为只有一个dash,并通过控制这个dash的宽度来表示百分比。
<svg viewBox="0 0 32 32">
<circle r="16" cx="16" cy="16" />
</svg>
.piesvg svg {
width: 100px;
height: 100px;
transform: rotate(-90deg);
background: yellowgreen;
border-radius: 50%;
}
.piesvg circle {
fill: yellowgreen;
stroke: #655;
stroke-width: 32;
stroke-dasharray: 38 100; /* for 38% */
}
我们可以直接使用js来创建svg
.piesvg svg {
width: 100px;
height: 100px;
transform: rotate(-90deg);
background: yellowgreen;
border-radius: 50%;
}
.piesvg circle {
fill: yellowgreen;
stroke: #655;
stroke-width: 32;
}
$$('.piesvg').forEach(function(pie) {
var p = parseFloat(pie.textContent);
var NS = "http://www.w3.org/2000/svg";
var svg = document.createElementNS(NS, "svg");
var circle = document.createElementNS(NS, "circle");
var title = document.createElementNS(NS, "title");
circle.setAttribute("r", 16);
circle.setAttribute("cx", 16);
circle.setAttribute("cy", 16);
circle.setAttribute("stroke-dasharray", p + " 100");
svg.setAttribute("viewBox", "0 0 32 32");
title.textContent = pie.textContent; pie.textContent = '';
svg.appendChild(title);
svg.appendChild(circle);
pie.appendChild(svg);
});
<div class="piesvg">25%</div>
<div class="piesvg">35%</div>
如果你想使用动画的话,直接对这个属性动画就好了:stroke-dasharray。