问题

斜切角在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-width15px,得到结果为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斜切角的更多相关文章

  1. Matplotlib数据可视化(3):文本与轴

      在一幅图表中,文本.坐标轴和图像的是信息传递的核心,对着三者的设置是作图这最为关心的内容,在上一篇博客中虽然列举了一些设置方法,但没有进行深入介绍,本文以围绕如何对文本和坐标轴进行设置展开(对图像 ...

  2. 如何用css写一个带斜切角、有边框又有内外阴影的按钮呢?

    如果有一天,UI设计师丢过来一张UI稿,上面有这样一个带有斜切角.有边框还有内外阴影的按钮,你会怎么实现呢?第一反应切图?可是按钮内容.大小都是可变的,那得切多少图啊~Canvas?SVG?No,no ...

  3. css秘密花园

    picture元素 http://www.w3cplus.com/responsive/responsive-images-101-part-6-picture-element.htmlCHAPTER ...

  4. css3 斜切角/斜边的实现方式来自BAT大神的出品

    设计图含有斜切角的效果时,我们一般想到的方法是切出四个角为背景,然后用border连起来,这样就能显示出该效果了,那么直接使用css呢?下面就整理css做斜边的效果. 1.方案一:利用linear-g ...

  5. CSS的未来

    仅供参考 前言 完成<CSS核心技术与实战>这本书,已有一个多月了,而这篇文章原本是打算写在那本书里面的,但本章讲解的内容,毕竟属于CSS未来的范畴,而这一切都还不能够确定下来,所以这一章 ...

  6. 前端极易被误导的css选择器权重计算及css内联样式的妙用技巧

    记得大学时候,专业课的网页设计书籍里面讲过css选择器权重的计算:id是100,class是10,html标签是5等等,然后全部加起来的和进行比较... 我只想说:真是误人子弟,害人不浅! 最近,在前 ...

  7. 前端css兼容性与易混淆的点

    一.常用的骨灰级清除浮动 .clearfix:after { content: "."; display: block; height:; clear: both; visibil ...

  8. 理解CSS外边距margin

    前面的话   margin是盒模型几个属性中一个非常特殊的属性.简单举几个例子:只有margin不显示当前元素背景,只有margin可以设置为负值,margin和宽高支持auto,以及margin具有 ...

  9. 理解CSS视觉格式化

    前面的话   CSS视觉格式化这个词可能比较陌生,但说起盒模型可能就恍然大悟了.实际上,盒模型只是CSS视觉格式化的一部分.视觉格式化分为块级和行内两种处理方式.理解视觉格式化,可以确定得到的效果是应 ...

随机推荐

  1. virltualbox 升级之后 苹果虚拟机报The installed support driver doesn't match the version of the user解决方案

    1.反安装virtualbox后,不要重启 2.删除virtualbox的安装目录 3.进入%userprofile% 目录 (比如: C:\users\me) 删除 .VirtualBox Virt ...

  2. ZABBIX 4.0 LTS 部署

    1. 环境说明 关于zabbix的详细使用可以参考之前的3.0 版本,该文档仅记录zabbix 4.0 编译安装过程!ZABBIX 3.0 从入门到精通(zabbix使用详解) : https://w ...

  3. 每天一个linux命令:df

    1.命令简介 df (disk free) 其功能显示每个文件所在的文件系统的信息,默认是显示所有文件系统. 2.用法 df [选项]... [文件]... 3.选项   4.示例 示例1:显示磁盘使 ...

  4. 通过apicloud实现的混合开发App的Demo

    技术:html+css+js+apicloud封装的api   概述 本Demo主要基本的HTML+CSS+JS实现的混合App,通过第三方平台apicloud主要页面有首页资讯+商城,目前数据都是静 ...

  5. 开源中文分词工具探析(七):LTP

    LTP是哈工大开源的一套中文语言处理系统,涵盖了基本功能:分词.词性标注.命名实体识别.依存句法分析.语义角色标注.语义依存分析等. [开源中文分词工具探析]系列: 开源中文分词工具探析(一):ICT ...

  6. idea maven 集成多模块 module

    首先第一步创建 顶级项目  也就是父项目 在创面那部中 不管你勾不勾 create from 那个选项 都无所谓,最终创建的项目要全删的 ,只保留pom.xml 父项目结构 接下来 创建子项目  也是 ...

  7. xorm中的几个坑

    项目中使用的是xorm,虽然用了很顺手了,可是还是会遇到一些坑,这里纪录一些. 结构体自动忽略空字段 在xorm中,结构体会自动忽略空字段(或则说默认值,比如int 的0 ,string的" ...

  8. C语言 · 单词数统计

    单词数统计 输入一个字符串,求它包含多少个单词. 单词间以一个或者多个空格分开. 第一个单词前,最后一个单词后也可能有0到多个空格. 比如:" abc    xyz" 包含两个单词 ...

  9. Hadoop:hdfs文件permission denied问题解析

    Cron jobs can be scheduled, but fail to write parquet file and seems due to user permission of “yarn ...

  10. Java编程的逻辑 (91) - Lambda表达式

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...