CSS斜切角
问题
斜切角在Web设计和印刷中是相当受欢迎的样式。它通常是在一个或多个元素的角落切一个45°
的角(也就是所谓的斜切角)。特别是最近,扁平化设计的势头压过了拟真设计,也使这种效果更加流行。当斜切角只存在元素的一侧,并且每个都占据元素的50%
高度的时候,一个箭头的形状产生了,这在按钮和面包屑导航中非常受欢迎。
图注:带斜切角的按钮,创建了箭头形状强调其意义
但是,要用CSS来创建这个效果并不是那么容易,这不是一行代码就可以搞定的效果。这导致很多作者倾向于直接使用背景图像完成,而不是结合三角形来完成斜切角(当背景是纯色),也不会去使用一个或多个角落已经被切的图像来作为整个背景。
图注:应用了斜切角的网站示例(半透明的“Find & Book”盒子的左下角)
这种方法显然是不灵活的,而且难以维护,还增加了延迟,因为增加了HTTP请求和网站的总文件大小。有没有什么更好的方法呢?
解决方案
第一个解决方案是万能的CSS渐变。我们假设我们暂时只完成一个斜切角——右下角那个。其诀窍在于渐变可以接受一个角度值作为参数(如45deg
),色标位置是绝对长度,这两个都不会因为元素和背景尺寸的改变受到影响。
综上所述,我们只需要一个线性渐变就ok了。它需要一个透明的色标作为斜切角,还有另一个相同位置的带有我们想要作为背景颜色的色标。CSS代码如下(如一个15px
大小的切角):
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0);
很简单,对不对?你可以看到结果。
图注:右下角斜切的元素,通过一个简单的CSS渐变完成
从技术上说,我们甚至不需要第一条声明。我们只是把它作为一个降级引入:当CSS渐变不被支持时,也就是第二条声明失效的时候。所以我们还是需要一个纯色背景。
为方便调试,我们使用不同的颜色(
#58a
和#655
)。在应用中,两个渐变应该是相同的颜色。
现在,假设我们需要两个斜切角,左右下角分别一个。只用一个渐变是没办法搞定的,所以两个渐变上场。我们首先想到的可能是:
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0),
linear-gradient(45deg, transparent 15px, #655 0);
但是,如下图所示,这是不ok的。
图注:给底部两个角都应用斜切角效果的失败尝试
默认情况下,两个渐变被应用于同一个元素,它们会相爱相杀(彼此掩盖)。我们需要把它们变小,通过使用background-size
来让每个渐变都只应用于元素的一半:
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0) right,
linear-gradient(45deg, transparent 15px, #655 0) left;
background-size: 50% 100%;
你可以在下图中看到结果。
图注:只一条background-size
是不够哒~
即使应用了background-size
,这俩渐变还是会把对方盖住。因为我们忘了把background-repeat
关掉了,所以我们的背景就都重复了两次。因此,我们的背景还是在相爱相杀——这次是因为背景重复。新修改的代码如下:
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0) right,
linear-gradient(45deg, transparent 15px, #655 0) left;
background-size: 50% 100%;
background-repeat: no-repeat;
你可以在下图中看到结果。
图注:我们的左下和右下斜切角终于ok了
它终!于!通过验证了!现在,你应该知道要如何把这个效果应用到其它四个角了吧。一共需要四个渐变,代码如下:
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;
你可以在下图中看到结果。
图注:使用四个渐变,给四个角都应用了效果
前面的代码有个问题是,它不是特别可维护的。要改变背景颜色还有四个角的大小,需要五次编辑。加入预处理器mixin有助于减少重复。这是SCSS代码:
@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;
}
然后,在需要的时候,它可以像这样被使用,使用2-5
个参数:
@include beveled-corners(#58a, 15px, 5px);
在这个示例中,我们将会得到在左上角和右下角得到15px
斜切角,在左下角和右上角得到5px
斜切角,和border-radius
的原理相似。这是因为我们为SCSS的mixin的参数提供了默认值,还有,这些默认值也可以引用其它的参数。
曲线切口角
有很多渐变的方法可以用来创建曲线切口角,大家常常把这个效果称之为“内圆角”,因为它看起来就是圆角的反相版本。和斜切角唯一的不同是它使用了径向渐变,而不是线性渐变:
g2geogeske.com上使用曲线切口角的非常棒的例子;设计师已经把它们变成核心设计元素,因为它们存在于导航、内容、甚至页脚中。
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;
你可以在下图中看到结果。
图注:使用径向渐变完成的曲线切口角
和前面的技术一样,切口角的大小可以通过色标的位置进行控制,使用mixin可以让代码更易于维护。
内联SVG、border-image的解决方案
虽然基于渐变的解决方案是可行的,但是它有几个问题:
- 代码非常长,而且重复。在通常情况下,我们希望在四个角都有相同尺寸的切口角,这样我们就需要重复四次编辑。相似的,要修改背景颜色我们也需要四次编辑,五个计算降级。
- 在不同尺寸的切口角之间设置动画是完全不可能的(依赖于浏览器)。
幸好,根据我们的需求,还有几个我们可以采用的方法。一个是在内联SVG中使用border-image
生成圆角。根据border-image
的工作原理,你可以想象一下我们的SVG会如何吗?
因为尺寸并不重要(border-image
可以缩放,而且SVG缩放是完美的,不需要担心尺寸——这就是矢量图的好处!),单位可以是1
,或者更直接的,直接是数字。拐角长度可以是长度1
,直边长度也为1
。结果(缩放)如下图所示。
图注:基于SVG的border-image
,及其切片
代码如下:
border: 15px solid transparent;
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>');
注意我们使用了大小为1
的切片。这不是1
像素的意思,它指的是SVG文件的坐标系(因此缺省单位)。如果我们指定了它的百分比,我们需要的就是1/3
图像的近似值,如33.34%
。近似值是有风险的,因此不是所有的浏览器都使用相同的精确度。但是,通过使用SVG文件的坐标系统的单位,我们就不需要纠结精确值的问题了。
图注:给border-image
属性应用SVG
结果如上图所示。我们的切口角有了,但是没有背景。你可以通过两个方法解决:指定一个背景,或者给我们的border-image
声明添加一个关键字fill
,这样它就不会丢弃中间的切片。这里,我们选择指定一个背景,因为这样也可以作为一个降级。
另外,我们的切口角比前面创建的切口角要小,有点奇怪。我们明明指定了一个15px
的边框宽度!这是渐变造成的,15px
沿着渐变方向的,而方向垂直于梯度。同时边框的宽度不是对角线测量的,而是水平/垂直方向的。所以你找到原因了吗?对,我们要再次使用勾股定理,我们在前面也讲过。
图注:指定border-width
为15px
,得到结果为15 / 根号(2) ≈ 10.606601718
的拐角尺寸,这也是为什么我们的拐角看起来小很多
上图有助于我们理解。总而言之,为了得到相同的尺寸,我们使用的边框应该是我们用渐变方法的尺寸的根号(2)
倍。这里,应该是15 * 根号(2) ≈ 21.213203436
像素,也就是约等于20px
,除非我们真的需要对角线尽可能地接近于15px
:
border: 20px solid transparent;
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;
图注:我们的切口角哪去了?!
但是,上图的效果并不是我们期待的效果。我们辛辛苦苦创建的切口角躲到哪里去了?年轻人,不要担心!切口角还在那里。如果你把背景设置成其它的颜色,如#655
,你就会知道是怎么回事了。
图注:把我们的background
换成其它颜色,就可以发现神秘消失的切口角了
上图所示,我们的切口角消失的原因是我们指定的背景把它们挡住了。我们需要做的是使用background-clip
来阻止背景扩展到覆盖了我们的边框:
border: 20px solid transparent;
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-width
是可添加动画的!我们还可以只通过两次编辑就改变背景。另外,因为我们的背景现在是独立于拐角效果的,我们甚至可以给它指定一个渐变,或其它的纹理,只要它在边缘处的颜色还是#58a
就好。例如,看看下图,使用了一个从hsla(0,0%,100%,.2)
到transparent
的径向渐变。
图注:带有径向渐变背景的切口角
只剩下一个小问题了。如果border-image
不被支持,降级不仅没有拐角。因为背景裁剪,它看起来还像是盒子边缘和内容之间没有任何填充空间。为了解决这个问题,我们可以给我们的边框添加一个和背景相同的颜色:
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-image
应用的时候,颜色会被忽略,这可以提供一个更优雅的降级,看起来如图所示。
因为这个缺陷,使得我们想要改变背景颜色的时候,需要的编辑次数从2
变成了3
。
clip-path
的解决方案
因为border-image
的解决方案非常紧凑而且相对DRY,它仍然有其局限性。例如,我们仍然需要有一个纯色背景,或一个在边缘处带有纯色的背景。如果我们想要一种不同的背景呢,例如纹理、图案,或一个线性渐变?
有一个方法可以使我们不受所有的这些限制,尽管它也有自己的局限性。还记得clip-path
属性吗?一件非常令人惊叹的事情是,CSS的clip-path
可以结合百分比(这里指的是元件尺寸)以及绝对长度使用,给了我们极大的灵活性。
例如,clip-path
裁剪一个带20px
(水平方向)切角的矩形元素的代码如下所示:
background: #58a;
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
);
尽管代码很短,也不意味着它是DRY的,这就是它本身最大的问题之一,如果你不使用预处理器的话。事实上,这是我们提出的最WET的CSS解决方案,要改变拐角尺寸需要8
次编辑!但是,我们只需要在一处位置改变背景。
它的优势是我们可以使用任何我们想要的背景,甚至是裁剪像图片这样的替换元素。如下图带有切角的图像。
图注:通过clip-path
制作的带有切角的图片
前面的几种方法都不能完成。另外,clip-path
是可动画的,即使斜切角的大小不同,形状也不同。我们需要做的只是使用一个不同的裁剪路径。
除了WET,它的浏览器支持也不够,它还有个缺点是:如果没有提供足够的padding
,它还会裁剪文本,因为它只裁剪元素,而不区分都是哪些部分。与此相反,渐变的方法只是让文本在超出拐角(因为它们只是背景),这样border-image
方法只是扮演边框的角色,来包裹文本。
将来的拐角
将来我们不需要再通过CSS渐变、裁剪或SVG来完成这种效果了。一个新属性,corner-shape
即将加入到CSS Backgrounds & Borders Level 4中,可以帮我们节省很多精力。它可以和border-radius
结合使用,用于产生不同切口角效果,在border-radius
中定义尺寸即可。如,在所有角落指定15px
的切口角将会很简单:
border-radius: 15px;
corner-shape: bevel;
转载自:http://www.w3cplus.com/css3/css-secrets/cutout-corners.html
CSS斜切角的更多相关文章
- Matplotlib数据可视化(3):文本与轴
在一幅图表中,文本.坐标轴和图像的是信息传递的核心,对着三者的设置是作图这最为关心的内容,在上一篇博客中虽然列举了一些设置方法,但没有进行深入介绍,本文以围绕如何对文本和坐标轴进行设置展开(对图像 ...
- 如何用css写一个带斜切角、有边框又有内外阴影的按钮呢?
如果有一天,UI设计师丢过来一张UI稿,上面有这样一个带有斜切角.有边框还有内外阴影的按钮,你会怎么实现呢?第一反应切图?可是按钮内容.大小都是可变的,那得切多少图啊~Canvas?SVG?No,no ...
- css秘密花园
picture元素 http://www.w3cplus.com/responsive/responsive-images-101-part-6-picture-element.htmlCHAPTER ...
- css3 斜切角/斜边的实现方式来自BAT大神的出品
设计图含有斜切角的效果时,我们一般想到的方法是切出四个角为背景,然后用border连起来,这样就能显示出该效果了,那么直接使用css呢?下面就整理css做斜边的效果. 1.方案一:利用linear-g ...
- CSS的未来
仅供参考 前言 完成<CSS核心技术与实战>这本书,已有一个多月了,而这篇文章原本是打算写在那本书里面的,但本章讲解的内容,毕竟属于CSS未来的范畴,而这一切都还不能够确定下来,所以这一章 ...
- 前端极易被误导的css选择器权重计算及css内联样式的妙用技巧
记得大学时候,专业课的网页设计书籍里面讲过css选择器权重的计算:id是100,class是10,html标签是5等等,然后全部加起来的和进行比较... 我只想说:真是误人子弟,害人不浅! 最近,在前 ...
- 前端css兼容性与易混淆的点
一.常用的骨灰级清除浮动 .clearfix:after { content: "."; display: block; height:; clear: both; visibil ...
- 理解CSS外边距margin
前面的话 margin是盒模型几个属性中一个非常特殊的属性.简单举几个例子:只有margin不显示当前元素背景,只有margin可以设置为负值,margin和宽高支持auto,以及margin具有 ...
- 理解CSS视觉格式化
前面的话 CSS视觉格式化这个词可能比较陌生,但说起盒模型可能就恍然大悟了.实际上,盒模型只是CSS视觉格式化的一部分.视觉格式化分为块级和行内两种处理方式.理解视觉格式化,可以确定得到的效果是应 ...
随机推荐
- 通过IIS操作修改服务器文件没有权限的解决办法
问题描述:通过部署在IIS上的程序去操做文件(比如删除.旋转图片等)时,在本地执行没有问题,但是部署到服务器上提示“没有权限”.解决方法:找到你需要操作的文件的根文件夹,右键点击属性 选择“安全”选项 ...
- Python的pandas
pandas 是python中很重要的组件,网上关于pandas 的文章也很多,比如Python科学计算之Pandas 和 Python数据分析入门 Pandas基于两种数据类型:series与dat ...
- Docker国内镜像source
现在使用docker的镜像大多基于几种基本Linux系统.虽然我不需要在容器李安装很多东西,但经常需要一些必要的工具,而基础镜像里并不包含,比如vim, ifconfig, curl等.考虑下载速度, ...
- 单片机 MCU 中 stack 使用的探讨
stack 的使用,是单片机开发中影响最大,但是最少被讨论的问题.而提及这个问题的地方,都是对这个问题含糊其辞. 今天花了点时间,使用最笨的办法,直接阅读汇编代码,来对这个问题就行探究,这里做一下记录 ...
- Android 实现登录界面和功能实例
近期一个android小程序须要登录功能,我简单实现了一下.如今记录下来也当做个笔记,同一时候也希望能够相互学习.所以,假设我的代码有问题,还各位请提出来.多谢了! 以下.就简述一下此实例的主要内容: ...
- iOS 可高度自定义的底部弹框
技术: iOS Objective-C 概述 一个可以让开发者通过编写 tableView 的内容随心所欲的定制自己想要的底部弹框 详细 代码下载:http://www.demodashi.com ...
- 离线环境下安装ansible,借助有网环境下pip工具
环境 有网的机器(192.168.19.222):rhe65,python2.7.13,pip9.0.1 离线机器(192.168.19.203):rhe65,python2.6 FTP(192.16 ...
- 码云git 使用配置
码云git 使用配置:www.gitee.com安装:1.Git-2.18.0-64-bit.exe:2.GitExtensions-2.51.04.msi:3.GitExtensionsVSIX.v ...
- [Linux]Linux read/write
Read 默认read是block模式,如果想设置非block默认,则open时候参数添加O_NONBLOCK read block模式下,并非等到Buffer满才返回,而是只要有data avaia ...
- git rebase 的使用
rebase 在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase. 在本节中我们将学习什么是“rebase”,怎样使用“rebase”,并将展示该操作的惊艳之处,以及指 ...