前言
1.自适应的椭圆
如果我们想要实现一个圆形效果或者椭圆效果,我们都知道使用border-radius
可以解决,比如:
div{
width: 100px;
height: 100px;
border-radius: 50px;
background: red;
}
当然,这段代码不够DRY,因为当款宽高改变的时候,我们又要去改变border-radius
,所以我们自然而然想到使用百分比来解决这个问题:
div{
width: 100px;
height: 100px;
border-radius: 50%;
background: red;
}
现在我们能否实现一个半圆效果呢?代码如下:
div{
width: 100px;
height: 100px;
border-radius: 50% / 100% 100% 0 0;
background: red;
}
怎么实现的?首先border-radius
支持水平方向以及垂直方向的圆半径的赋值,具体是用/
分割,前面的则可以是四个值,代表水平方向的圆半径,方便是四个角的位置,与border-width
的解析原理,后面也是类似代表四个角方位的垂直方向的半径。在这里,我们设置水平方向的值为50%
,其实只需要设置左上右上的即可,但这里设置了四个角,主要是因为另外的两个角不会影响我们实现的目的,在垂直方向,我们设置左上右上100%
,因为我们看图可以推断在垂直方向我们顶部的两个圆角占据了整个元素的高度,而底部完全没有任何圆角,所以我们在垂直方向的合理值应该是100% 100% 0 0
,下面我们来回答为何底部的水平方向圆角不影响我们的实现,因为我们的底部的垂直方向的圆角半径为0
,你试着能找到一个垂直半径为0,而水平方向半径不为0
的几何图形吗?
如果我们想实现一个1/4
的圆呢,代码如下:
div{
width: 100px;
height: 100px;
border-radius: 100% 0 0 0;
background: red;
}
原理也很简单,我们只需要设置其中第一角的半径值都是100%
即可,其他设置为0
。
2.平行四边形
假如我们需要实现下面这种效果图:
可能我们的代码是这样的:
div{
transform: rotate(7deg)
}
div p{
transform: rotate(-7deg)
}
我们对容器进行了旋转,却发现字体也跟着旋转,于是我们不得不把字体再旋转回来,那么我们有没有简单方法,当然有了,这里使用的则是伪元素方案:
.button{
position: relative;
}
.button::before{
content: '';
position: absolute;
top: 0; right: 0; bottom:0; left: 0;
z-index: -1;
transform: rotate(7deg)
}
这段代码使用绝对定位元素上下左右值为0
时候,在水平和垂直方向具有拉伸性的特点作为内容区域,这样不管内容多少,始终会覆盖在内容区域之上,但是我们需要让它在在内容区域之下显示,所以我们设置z-index: -1
使其被推到宿主元素之下,这样对伪元素的进行旋转并会不影响宿主元素,可谓不可多得的技巧。
3.菱形图片
倘若设计师给你这么一个头像的设计稿:
你会怎么实现,当然了,你肯定不能让美工帮你把图片给你调整成菱形,不然会被打死,常规想法我们可能是这样的:
.picture{
transform: rotate(45deg);
overflow: hidden;
}
.picture img{
transform: rotate(45deg);
}
结果却是一个六边形,然而我们要的并不是六边形,原理很简单,因容器太大,图片太小,导致剪切的时候只剪切了图片区域,所以我们要增加图片大小,增加图片宽度之后,效果是这样:
纳尼?似乎不是我们想要的效果,CSS3中有一个放大功能,为何不用它来试一试,下面是代码:
.picture{
transform: rotate(45deg);
overflow: hidden;
}
.picture img{
transform: rotate(45deg) scale(1.42);
}
效果还不错。但是这个方法需要一层额外的父级标签,而且如果我们遇到是一张非正方形的图片那这个就基本没戏了。那有没有更好的方法,当然有。
使用clip-path
属性,他可以将我们想要的元素裁剪成指定的形状,这种PS软件的裁剪效果是一样的,代码是这样的:
clip-path: polygon(505 0, 100% 50%, 50% 100% , 0 50%);
就是这么简单,而且效果还很好,唯一的不足就是兼容性不怎么好。
4.切角效果
切角效果现在很多地方都在运用,比如下面这种缺角效果,如果让你实现,你会怎么实现它?
可能你会想到使用背景图片来实现,又或者通过绝对定位等方法实现,但是都不怎么友好,这里建议的第一种解决方案则是使用无所不能的CSS渐变,CSS渐变可以接受一个角度值作为方向,具体看代码:
background: #ad141400;
background: linear-gradient(-45deg, #ad141400 15px,#FF9800 0);
效果和原图效果一模一样,第一行声明只是作为回退机制处理。
如果试试两个角,那怎么处理,我想你已经想到了,就是运用两次渐变:
background: linear-gradient(-45deg, #ad141400 15px,#ff9800 0) right,linear-gradient(45deg, #ffffff 15px,#ff9800 0) left;
background-size: 50% 100%;/*防止渐变重复渲染,使其各渲染一半*/
background-repeat: no-repeat;/*防止渐变重复渲染,覆盖斜角*/
如果四个角,那就再运用两次渐变,原理相同:
background: linear-gradient(135deg, #ad141400 15px,#ff9800 0) top left,
linear-gradient(-135deg, #ffffff 15px,#ff9800 0) top right,
linear-gradient(-45deg, #ad141400 15px,#ff9800 0) bottom right,
linear-gradient(45deg, #ffffff 15px,#ff9800 0) bottom left;
background-size: 50% 50%;/*防止渐变重复渲染,使其各渲染一半*/
background-repeat: no-repeat;/*防止渐变重复渲染,覆盖斜角*/
凹向四级边角,经常使用径向渐变来实现:
background: radial-gradient(circle at top left, #ad141400 15px,#ff9800 0) top left,
radial-gradient(circle at top right, #ffffff 15px,#ff9800 0) top right,
radial-gradient(circle at bottom left, #ad141400 15px,#ff9800 0) bottom left,
radial-gradient(circle at bottom right, #ffffff 15px,#ff9800 0) bottom right;
background-size: 50% 51%;/*防止渐变重复渲染,使其各渲染一半*/
background-repeat: no-repeat;/*防止渐变重复渲染,覆盖斜角*/
![](https://luoyelusheng.com/post-images/1634465922186.png)
这里垂直background-size
需要增加一像素,因为在谷歌下面有一像素的白线在中间。
当然上述方案似乎他麻烦了,我们还可以借助SVG实现这一效果:
border: 21px solid transparent;
border-image: 1 url('data:image/svg+xml,\ <svg xmlns="http://www.w3.org/…oints="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2" />\ </svg>');
background: #58a;
background-clip: padding-box;
padding: .2em .3em;
max-width: 12em;
color: white;
![](https://luoyelusheng.com/post-images/1634465929915.png)
在这里我们只需要修改边框即可。
5.梯形标签页
tab标签切换的时候,则需要我们实现一种梯形效果,比如:
![](https://luoyelusheng.com/post-images/1634465936982.png)
我们可以通过伪元素实现:
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
border-bottom: none;
border-radius: .5em .5em 0 0;
background: #ccc linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,0));
box-shadow: 0 0.15em white inset;
transform: scale(1.1, 1.3) perspective(.5em) rotateX(5deg);
transform-origin: bottom;
关键的原理是利用3d旋转矩形,由于透视关系,我们看到的二维图形往往是一个梯形,核心代码:
transform: scale(1.1, 1.3) perspective(.5em) rotateX(5deg);
其中perspective
代表透视距离,默认为0
,我们还可设置transform-origin
的值为bottom left
或者bottom right
就可以左侧倾斜或者右侧倾斜。当然有一个缺点就是斜边的角度依赖与元素的宽度,不过确实是很好用的一种实践。
6.饼图
倘若我们想要实现下面这种效果:
可能我们会去借助图形库来解决,但如果我们自己实现,那怎么实现,我们现在看一段代码:
.pie {
width: 100px;
height: 100px;
border-radius: 50%;
background: yellowgreen;
background-image: linear-gradient(to right, transparent 50%, currentColor 0);
color: #655;
}
这段代码定义了一个圆形,然后又定义了线性渐变,效果如下:
下面我们通过伪元素并结合rotate
来实现百分比,代码如下:
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
}
并结合动画实现最终的效果:
.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;
}
@keyframes spin {
to { transform: rotate(.5turn); }
}
@keyframes bg {
50% { background: currentColor; }
}
但其实我们经常用的饼图效果代码结构是这样的:
<div class="pie">80%</div>
代码实现:
.pie {
width: 100px; height: 100px;
border-radius: 50%;
background: yellowgreen;
background-image: linear-gradient(to right, transparent 50%, currentColor 0);
color: #655;
animation-delay: -20s;
}
.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 50s linear infinite, bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
}
@keyframes spin {
to { transform: rotate(.5turn); }
}
@keyframes bg {
50% { background: currentColor; }
}
var doc = document.querySelector('.pie');
var text = parseInt(doc.innerText);
doc.style.animationDelay = '-' + text + 's';
![](https://luoyelusheng.com/post-images/1634465956497.png)
另外一种是svg实现方案,具体可看这个例子:demo