CSS3 画形状

在制作页面时,常用CSS画各种形状带代替img,这样可以免去一次HTTP请求。而且有些基本形状用CSS实现比切图更方便和灵活。本篇就介绍一下常用形状的画法。

  • 圆形
  • 椭圆(半椭圆,4分之一椭圆)
  • 三角形
  • 平行四边形
  • 菱形
  • 梯形

圆形

是最常见最基本的图型,给宽高相等的div设border-radius: 50%,轻松实现:


.circle {
    width: 5em;
    height: 5em;
    background: #fb3;
    border-radius: 50%;
}

<div class="circle"></div>

椭圆

参照border-radius一文,给宽高不等的div设border-radius: 50%来实现:

.ellipse {
    width: 5em;
    height: 2.5em;
    background: #fb3;
    border-radius: 50%;
}

<div class="ellipse"></div>

半椭圆的关键是给四个角指定不同的border-radius半径:


.half-ellipse1 {
    width: 5em;
    height: 1.25em;
    background: #fb3;
    border-radius: 50% / 100% 100% 0 0;
}
.half-ellipse2 {
    width: 5em;
    height: 1.25em;
    background: #fb3;
    border-radius: 50% / 0 0 100% 100%;
}
.half-ellipse3 {
    width: 2.5em;
    height: 2.5em;
    background: #fb3;
    border-radius: 100% 0 0 100% / 50%;
}
.half-ellipse4 {
    width: 2.5em;
    height: 2.5em;
    background: #fb3;
    border-radius: 0 100% 100% 0 / 50%;
}

<div class="half-ellipse1"></div>
<div class="half-ellipse2"></div>
<div class="half-ellipse3"></div>
<div class="half-ellipse4"></div>

以左图上半椭圆为例,左上角和右上角的半径值应该是相同的,左下角和右下角的半径值同样也应该是相同的。

先看水平方向。因为左上角和右上角没有直边,这意味着它俩的半径之和要等于整个div的宽度,所以左上角和右上角的水平半径应该均为50%。

再看垂直方向。因为左上角和右上角的圆角占据了整个元素的高度,底部完全没有任何圆角。所以垂直半径应该设成100% 100% 0 0

最终应该border-radius: 50% 50% 0 0 / 100% 100% 0 0;。但由于左下角和右下角的垂直半径为0,所以它俩的水平半径设成什么都没有影响。因此可以简化成border-radius: 50% / 100% 100% 0 0;

下半椭圆和左右半椭圆的思路都是一样的,自己看看代码应该能推理出来。

4分之一椭圆的关键是其中一个角的水平和垂直半径都要为100%,其他三个角无圆角:


.quarter-ellipse {
    width: 5em;
    height: 2.5em;
    background: #fb3;
}
.quarter-ellipse1 {
    border-radius: 100% 0 0 0;
}
.quarter-ellipse2 {
    border-radius: 0 100% 0 0;
}
.quarter-ellipse3 {
    border-radius: 0 0 100% 0;
}
.quarter-ellipse4 {
    border-radius: 0 0 0 100%;
}

<div class="quarter-ellipse quarter-ellipse1"></div>
<div class="quarter-ellipse quarter-ellipse2"></div>
<div class="quarter-ellipse quarter-ellipse3"></div>
<div class="quarter-ellipse quarter-ellipse4"></div>

画这些半椭圆啊,4分之一椭圆啊,有什么用?例如点这里

三角形

用一边border有颜色,另三边border透明来实现:


.triangle1 {
    width: 0;
    border: 2em solid transparent;
    border-top: 2em solid #fb3;
}
.triangle2 {
    width: 0;
    border: 2em solid transparent;
    border-right: 2em solid #fb3;
}
.triangle3 {
    width: 0;
    border: 2em solid transparent;
    border-bottom: 2em solid #fb3;
}
.triangle4 {
    width: 0;
    border: 2em solid transparent;
    border-left: 2em solid #fb3;
}

<div class="triangle1"></div>
<div class="triangle2"></div>
<div class="triangle3"></div>
<div class="triangle4"></div>

最左图只是示意,当div宽高为0时(无内容时高度自动为0不用设),border就是4个三角形。之后你需要什么方向的三角形,只要将该方向的border显示出来就行了。不用div用伪元素也是可以实现的,原理是一样的。三角形的应用场景也很多,例如聊天窗口处的小三角箭头:


平行四边形

transform的skew倾斜来实现:

.parallelogram {
    display: inline-block;
    padding: .5em 1em;
    background-color: #0fa5d9;
    color: white;
    transform: skewX(-45deg);
}

<div class="parallelogram">HMTL</div>

但如图所示,skew倾斜后,内部文字也倾斜了。如果想内部文字不倾斜,需要在div里额外加一层标签,再将该标签负相同角度skew回来:


.parallelogram2 {
    display: inline-block;
    padding: .5em 1em; 
    background-color: #0fa5d9;
    color: white;
    transform: skewX(-45deg);
}
/* 负相同角度将文字倾斜回来 */
.parallelogram2 > div { transform: skewX(45deg); }

<div class="parallelogram2">HMTL</div>

如果不想多一层标签,也可以用伪元素,效果是一样的:

.parallelogram3 {
    position: relative;
    display: inline-block;
    padding: .5em 1em; 
    color: white;
}
.parallelogram3::before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -1;
    background-color: #0fa5d9;
    transform: skew(-45deg);
}

<div class="parallelogram3">HMTL</div>

其实对其他任何变形式样,如果只想变形元素,但不想变形它的内容时就可以用该技巧。例如对正方形rotate一下就能得到菱形。

菱形

如果是背景的话直接给正方形用rotate就能得到菱形。但如果是图片的话,用rotate可能效果不对…


.diamond {
    width: 150px;
    height: 150px;
    transform: rotate(45deg);
    overflow: hidden;
}
.diamond img {
    transform: rotate(-45deg);
}

<div class="diamond"><img src="head.png" /></div>

上例中用了和平行四边形一样的思路,内部img用相反的角度rotate回去。但如图所示,成了奇怪的八角形。解决方案是将图片放大,放大多少呢?根据勾股定理,正方形的对角线等于边长乘根号2,约等于1.414,因此取稍微大一点放大1.42倍:

.diamond img {
    transform: rotate(-45deg) scale(1.42);
}

如果不想多一层div标签,想直接将img图片弄成菱形,也可以用clip-path来裁剪。它的好处是简单优雅,可以指定多个剪裁角度,处理非正方形的图片也毫无压力,缺点是会有游览器兼容性问题,试下来IE全军覆没,Firefox也不行,只有Chrome和Oprea支持。希望解决了兼容性问题后,将来它能大放异彩。


.diamond-clip {
    -webkit-clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
    clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}

<img class="diamond-clip" src="head.png" />

梯形

一种常见的方法是给长方形的div,加上::before和::after两个伪元素,伪元素参照上面画出三角形,这样来拼接成一个梯形。缺点是,伪元素数量有限,就这么两个,用完后再有需要用到伪元素的需求就没法满足了。其实可以用3D的rotate来实现。


.trapezoid {
    display: inline-block;
    padding: .5em 1em;
    color: white;
    background: #58a;
    transform: perspective(.5em) rotateX(5deg);
}

<div class="trapezoid">HTML</div>

这个方法简单方便,不需要用到伪元素。但有和平行四边形一样的问题,里面的内容文字也3D旋转了。想让内容文字不旋转需要加一层标签,或用伪元素。


.trapezoid2 {
    position: relative;
    display: inline-block;
    padding: .5em 1em;
    color: white;
}
.trapezoid2::before {
    content: '';
    position: absolute;
    z-index: -1;
    top: 0;right: 0;bottom: 0;left: 0;
    background: #58a;
    transform: perspective(.5em) rotateX(5deg);
}

<div class="trapezoid2">HTML</div>

从图中加上红色边框也能看出,3D旋转的伪元素背景,和div自身的底部不贴合。由于transform具有层级关系,会导致div下面的空间被遮蔽。因此需要指定transform-origin: bottom;让它在旋转时,底边固定。


.trapezoid2::before {
    ……
    transform-origin: bottom;
}

这样底边虽然贴合了,但内容文字明显不居中。要让内容文字居中也很简单,可以缩减点padding-bottom,再用scaleY将背景垂直方向拉大点,具体比例需要自己微调一下


.trapezoid4 {
    ……
    padding: .5em 1em .35em;
    ……
}
.trapezoid4::before {
    ……
    transform: perspective(.5em) rotateX(5deg) scaleY(1.3);
    transform-origin: bottom;
}

这样将transform-origin改成bottom left或bottom right,就可以得到左倾斜,右倾斜的标签页。你可以点击这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 各种纯css图标 CSS3可以实现很多漂亮的图形,我收集了32种图形,在下面列出。直接用CSS3画出这些图形,要比...
    剑残阅读 9,472评论 0 8
  • 1、属性选择器:id选择器 # 通过id 来选择类名选择器 . 通过类名来选择属性选择器 ...
    Yuann阅读 1,617评论 0 7
  • CSS3简介 CSS3的现状 浏览器支持程度差,需要添加 私有前缀 ; 移动端支持优于PC端; 不断改进中; 应用...
    magic_pill阅读 778评论 0 1
  • 转载请声明 原文链接 关注公众号获取更多资讯 这篇文章主要总结H5的一些新增的功能以及一些基础归纳,这里只是一个提...
    程序员poetry阅读 9,057评论 22 225
  • 徐志摩,是我很喜欢的一位诗人。 他有着富裕的家庭背景,在有着优越的家庭条件下不像于当时的富家子弟般浪荡无为,他...
    万古生长夜阅读 481评论 0 0