从画一个圆开始——CSS圆角探秘(一)

这篇文章能够成型因为两个原因。一是团队内部的分享会,二是CSS魔法在2015年CSS Conf上的一次分享。也因为魔法哥的这次分享,深深的勾起了我对CSS深入了解的欲望。也促成了这篇文章的成型。

这篇文章大多可以在《CSS 揭秘》中找到相关案例,或是相关思想。有兴趣的小伙伴可以买回来看一看。好了,废话不多说,开始正文吧!

这篇文章分为五个小节:

  • 从画一个圆开始 —— 简单阐述现代浏览器上画圆和在IE7+浏览器上画圆
  • 一个图标 —— 用CSS画一个小图标,从中窥探那些一个改变就能产生神奇效果的属性
  • 一次发现 —— 一次正常的网页浏览,一个美妙的东西,然我去一探究竟
  • 一种需求 —— 这是一个实实在在的需求,是我们生产中确实存在的。
  • 一类体验 —— 某些效果,加不加都OK,但加上绝对加分。

一:从画一个圆开始

在现代浏览器上画一个非常简单,一个border-radius属性完完全全的可以解决掉这个问题。

代码:

-webkit-border-radius:50%; 
-moz-border-radius:50%; 
border-radius:50%;

实例:

  是的,画一个圆对于现代浏览器来说是非常简单的事,但是我们知道,在border-radius属性是CSS3新增属性,那么就会导致在IE8以下的浏览器无法正常显示。当然,这个其实不算什么大问题,我们可以使用一张背景图片轻松的实现兼容。

但是如我们想用CSS写出一个兼容IE8的圆,我们该怎样去实现呢?其实border属性的dotted值可以整出来,但只是模拟出来的一个圆,实际上它就是一个点线,你没看错,是个点线 2333333

我们来试一下
代码:

.demo-1-2-box {
    width: 150px;
    height: 150px;
    position: relative; /* 这里是隐藏其他点 */
    overflow: hidden;
}

.demo-1-2 {
    position: absolute;
    width: 100%;
    height: 100%;
    border: 149px dotted; /* IE7与IE8下会有1像素的偏差 */
    margin: 0 0 1px 1px;
    color: #5cb85c;
}

.demo-2-1 {
    width: 200px;
    height: 200px;
    border-left: 60px solid #fff;
    border-top: 60px solid #fff;
}

实例:

  如果你看到的是一个正方形,说明你此时使用的是非IE浏览器。如果你看到的是一个圆形。那你一定使用的是IE浏览器! 正如所看到的一样,这样写在chrome上显示的是一个正方形,在IE上显示的是圆形。如果想全平台生效,我们用Hack处理一下大致是那么回事,但是有一点就是IE8的Hack是个坑,IE7及IE9+都会生效。那么在这里我不去做深入的探讨。

在现在的众多网页设计稿中,很多地方都会使用到圆角等属性,小到一个按钮,大到整个页面,总会有需要它出现的地方,当然这不仅仅是一个设计上的趋势,也是视觉上的一种友好体现。好了,废话不多说,让我们一起来探索CSS属性的一些秘密。

二、一个图标

相信大家在做网页的时候针对图标不是用Web Fonts就是Png雪碧图的方式,简单快捷易用是一大特点,而且经受住的诸多考验。但是大家有没有使用过CSS画图标呢?

在GitHub上有很多这类的项目,在这里分享一个** Icono** ,有兴趣的小伙伴可以进去一探究竟。在这个小节也与CSS绘制图标有关。在这里,我们要绘制一个分享按钮………….的一部分。

需求:

p350_demo_1_1

从这个图标我们可以看到,该图标大致可以分为三个区块:

1.一个缺了右上角的圆角边框(绘制里外都为圆角的线框注重点后面提);

2.一个不是完全规则的三角形(这个不规则的三角形也是可以用CSS绘制出来的);

3.一个类似与老鹰嘴巴的“鹰嘴型”:

p350_demo_1_2

当我第一次看到这么一个小需求,我感觉很有意思。但是如何绘制这样一个鹰嘴一样的形状呢?这是我当时的第一个想法。当然,在这里我们需要重新深入的回顾一下border-radius属性,看到这个属性小伙伴们是不是一愣,这不是在上面画圆的属性吗?是的,我们来深入的探讨一下它!

border-radius:

border-radius:[ <length> | <percentage> ]{1,4} [ / [ <length> | <percentage> ]{1,4} ]?

默认值:看每个独立属性

适用于:所有元素

继承性:无

动画性:看每个独立属性

计算值:看每个独立属性

从上面的语法我们可以看出,border-radius提供2个参数,可以是长度,也可以是百分比。2个参数以“/”分隔,每个参数允许设置1~4个参数值,在这里第1个参数表示水平半径,第2个参数表示垂直半径,如第2个参数省略,则默认等于第1个参数 。当然在这里需要说明:

  • 水平半径:如果提供全部四个参数值,将按上左(top-left)、上右(top-right)、下右(bottom-right)、下左(bottom-left)的顺序作用于四个角。
  • 如果只提供一个,将用于全部的于四个角。
  • 如果提供两个,第一个用于上左(top-left)、下右(bottom-right),第二个用于上右(top-right)、下左(bottom-left)。
  • 如果提供三个,第一个用于上左(top-left),第二个用于上右(top-right)、下左(bottom-left),第三个用于下右(bottom-right)。
  • 垂直半径也遵循以上4点。

当然在实际的开发生产中,我们很少遇到需要完完全全去设置这8个值。那么这八个值的实际作用在那里呢?下面我们将会一一通过例子来叙述。

好了,回到最初的问题,这个鹰嘴怎么画?还是不太清晰,那如果是这个鹰嘴形状最像什么呢?我自己可能会给出下面这个答案:

CSS:

.demo-2-1 {
    width: 150px;
    height: 150px;
    border-left: 60px solid #5cb85c;
    border-top: 60px solid #5cb85c;
}

实例

  这个形状很好画,我们只需要简简单单的去设置它的上左两个边即可,但这样一个图形还是看不出来该怎么做成一个鹰嘴的形状。但如果我们改变一下呢?给他加上一个border-radius属性,就是我们上面所复习的知识:

CSS:

 border-radius: 120px 0 0 0/120px 0 0 0;

实例

  咦,这样的话是不是就有那么几分意思了?在这里我们用到了上面提到的border-radius相关值,我们省略了矩形除左上以外三个角的属性。在这种情况下,只有左上是圆角,在上一步中,我已经未设置右下两条边,故这两条边不显示。当然在这里我们还可以这样写border-radius: 120px 0 0 0;,是一样的效果。可以看出“/”之前的参数用来设置水平,之后的参数用来设置垂直。

那我们改变“/”前后的值,然后他们不相等,看看是个什么效果。

CSS:

border-radius: 120px 0 0 0 / 20px 0 0 0;

实例:

 

可能有小伙伴发现了一个问题,为什么我“/”前后值相等的时候内框为圆角,当不等的时候内框为直角。这是一个什么问题呢?

我们来画一组示例图,也让我们更好的了解这个属性值该如何去设置:

161031_1

在这组图中我们可以清晰的看出,当圆角半径小于边框宽度时,内凹角为直角。当圆角半径大于边框宽度时,内凹角为圆角。那么对比上例,更深入一点,我们发现,只有当圆角的圆心不在边框内内凹角为圆角。那么就得设置“/”前后值都超过边框的宽。

好了,都走到这一步了,那么这个鹰嘴到底是怎么实现的呢?我们需要重申两个事实:

  1. 这是一个块级元素画的,那么它的宽高始终是可以改变的。
  2. 这个形状是由border为基础的,border是可以改变粗细的(如上示例)。

好了,我们先使用第一个事实将高度改小一点,再使用第二个事实。让左边框变细,直接去除掉左边框border-left: 60px solid #fff:

实例

 

扩展:

其实在实际生产中,我们有事会遇到多重边框的情况,如何设置多重边框,很多人第一反应是outline,这是一种非常好的解决方案。我们只需要设置一层常规边框,再加上outline就可以轻松实现,并可以模拟实线与虚线,但如果多重边框为圆角,我们所设置的outline也为圆角吗?我们来试试:

  我们很遗憾的看到:
  1. outline只适用于双层边框的场景,因为它并不能接受用逗号分隔多个值。
  2. outline并不会贴合border-radius属性产生圆角。

那么我们该如何去产生一个多重圆角边框呢?box-shodow可能是个很好的解决方法:

box-shodow:

box-shadow:none | <shadow> [ , <shadow> ]*
<shadow> = inset? && <length>{2,4} && <color>?

默认值:none

适用于:所有元素

继承性:无

动画性:是,除了内、外阴影切换时

计算值:指定值

关于box-shodow的取值:

  • none: 无阴影
  • ①: 第1个长度值用来设置对象的阴影水平偏移值。可以为负值
  • ②: 第2个长度值用来设置对象的阴影垂直偏移值。可以为负值
  • ③: 如果提供了第3个长度值则用来设置对象的阴影模糊值。不允许负值
  • ④: 如果提供了第4个长度值则用来设置对象的阴影外延值。可以为负值
  • : 设置对象的阴影的颜色。
  • inset: 设置对象的阴影类型为内阴影。该值为空时,则对象的阴影类型为外阴影

我们可以看到“ 如果提供了第4个长度值则用来设置对象的阴影外延值。可以为负值 ”这么一句话,但其实在实际生产中我们很少用到第四个参数。假设一下,如果我们取消x/y轴上的偏移,不让其模糊,单单只设置阴影外延值会出现什么效果呢?

CSS:

box-shadow: 0 0 0 5px #000

实例:

  我们可以看到,延边很完美的贴合了常规边框。那如果去实现多重边框呢?

我们注意W3C在对box-shodow描述中有这么一句话:

box-shodow可以设定多组效果,每组参数值以逗号分隔。那么这样我们就可以轻松实现多重边框的效果,当然,每个边框不同的颜色我们也可以轻松实现。