HTML+CSS01 CSS技巧
各种CSS效果
透明边框
默认情况下,背景的颜色会延伸至边框下层,所以如果边框设置为透明色,会被背景色覆盖掉。
可以设置CSS3的属性background-clip
设置元素的背景(背景图片或颜色)是否延伸到边框下面。
background-clip
取值有四个:
border-box
: 背景延伸至边框外沿(但是在边框下层)padding-box
: 背景延伸至内边距(padding
)外沿,不会绘制到边框外content-box
: 背景延伸至内容区(content box
)外沿text
:背景剪裁成为文字的前景色。(只有Chrome支持,需加-webkit-
前缀)
所以将background-clip
设置为padding-box
就可以实现透明边框。
参考:
多重边框
box-shadow
box-shadow
用来产生阴影效果,如果只给出两个数值,那么浏览器解析为x
方向偏移量和y
方向偏移量;如果给出第三个值,将被解释为模糊半径的大小;如果给出第四个值,将被监事未扩展半径的大小。
另外两个属性是inset
属性(声明式)和颜色值。
一直对模糊半径和扩展半径有一些糊涂,从下面这个例子了解box-shadow
的生成过程
首先定义出box-shadow
属性:
1 | .box { |
(1)首先在box
元素生成一个同box
大小、形状完全相同的阴影,颜色为设置的颜色#000
此时,阴影在元素的上层
(2)根据offset-x
和offset-y
,将阴影从上层向右移动30px
,向上移动50px
(3)然后根据设置的20px
的模糊半径,然后在四个方向上,每个方向的阴影边缘为中心,向两侧各扩展10px
的区域,作为高斯模糊的半径
以右侧为例:
(4)最后一步,将阴影与元素重叠的区域剪裁掉,如下图:
(5)得到最终效果:
从上面的例子看出,模糊半径是是以阴影边缘为中心,向两侧扩展一半,作为半径,进行高斯模糊。只能取正值。
扩展半径,是将阴影的面积增大,在它取值为0
时,阴影面积是等于元素的面积的,它不等于0
时,取值是四个方向增大或者减小的尺寸
1 | .inner { |
上图的虚线尺寸就是增加的扩展半径30px
,当设置了扩展半径,模糊半径也会从增大后的阴影边缘向两侧模糊。
可以通过将x-offset
、y-offset
、模糊半径都设为0
,设置不同尺寸的扩展半径,来实现多重边框的效果:
1 | .inner { |
优点是很容易实现2条以上的边框,且可以实现圆角边框,缺点是无法实现非实线的边框。
outline
+ outline-offset
outline
可以设置一个或者或者多个单独轮廓属性,轮廓不占据空间(box-shadow
和border
都占据空间)
outline-offset
用来设置一个outline
与一个元素边缘或者边框的间隙
将两者结合,就可以实现多种边框,并且可以实现box-shadow
无法实现的,非实线的多重边框
1 | .inner2 { |
优点是可以实现非实线的边框,缺点是实现2条以上的边框不方便,且无法实现圆角边框。
参考
边框内圆角
要实现的效果:
边框外围没有圆角,内部有圆角,所以单独使用border-radius
是不行的。上一部分内容中,我们可以发现,box-shadow
是跟随边框有圆角的,而outline
则是没有圆角的,所以我们可以使用三者的组合实现边框内圆角。
利用border-radius
设置圆角,假设为r
,但是不设置border
,设置outline
为w
,这样外边框是没有圆角的,
1 | .inner { |
这时候效果是:
背景会由于border-radius
的设置出现圆角,然后我们用box-shadow
将这部分补上,只设置其扩展半径,颜色与outline
的颜色相同
1 | .inner { |
扩展半径的取值范围见下图:
复习一下扩展半径的值:
所以这里取值最大值不能超过outline
的宽度w
,而最小宽度根据勾股定理不能小于$\sqrt{2}r - r$
,即$\sqrt{2-1}r$
,在我们上面的设置中,扩展半径的取值范围是[2.07, 5)
参考:
背景定位
background-position
我比较熟悉的背景定位是使用background-position
,但是都是只指定了两个属性值:
1 | .backgroundPosition { |
有三个点要注意:
background-position
指定的位置是相对于由background-origin
定义的位置图层的,默认定位于元素的左上角background-position
在一个方向上,可以指定一个值(例如上面),也可以指定两个值,可以在right
后面跟一个数值,表示相对于边缘的位置- 如果指定的是百分比,
0%
代表图片的左(上)边界和容器的左(上)边界重合,100%
代表图片的右(下)边界与容器的右(下)边界重合,50%
代表图片的中心与容器的中心重合
1 | .inner { |
另外,这个属性是可以融合到background
属性中的:
1 | .backgroundPosition { |
background-origin
刚才也提到了,background-position
指定的位置是相对于由background-origin
定义的位置图层的。background-origin
规定了背景图片的属性的原点位置与容器的关系(与background-clip
类似)
可以取值有:
border-box
: 图片边界与border
重合padding-box
: 图片边界与padding
区域重合content-box
: 图片边界与content
区域重合
所以,可以取值content-box
,借用padding
定位实现。
1 | .inner { |
参考:
条纹进度条
可以使用background
的repeating-linear-gradient
属性,来生成一个静态的进度条,再结合动画属性,实现动态的进度条样式。
linear-gradient
可以实现线形重复渐变效果。
repeating-linear-gradient
类似linear-gradient
,并且采用相同的参数,但是它会在所有方向上重复渐变以覆盖其整个容器。
它分为两组参数,第一组参数用来描述渐变线的起点位置,to top
这样的值会转换为0度,to left
会被转换为270度。第二组参数可以包含多个值,用逗号分隔,每个值都是一个色值,后面跟随一个可选的终点位置,终点位置可以是百分比也可以是绝对值
1 | /* 一个倾斜45度的重复线性渐变, |
1 | /* 一个从右下角到左上角的重复线性渐变, |
1 | /* 一个由下至上的重复线性渐变, |
要想实现突然变色,而非渐变色,需要为两个颜色制定同一个终点位置,那么这两个颜色会产生一个无线小的过渡区域,从效果上看,颜色会在那个位置突然变化,而不是一个平滑的过程。
1 | background: linear-gradient(90deg, blue 50%, red 50%); |
上面的写法的可维护性不太好,因为每次修改尺寸时都需要修改两处,但是CSS规范规定,如果某个色标的位置值比整个列表在它之前的位置都要小,则改色标的位置会被设置为它前面的额所有色标位置值的最大值
所以上面的代码也可以改为:
1 | background: linear-gradient(90deg, blue 50%, red 0); |
色块的大小是可以通过background-size
来控制的:
1 | background: linear-gradient(90deg, blue 50%, red 0); |
在就将角度倾斜,通过animation
控制background-position
,就可以实现动起来的效果了:
1 | .inner:after { |
这样可以实现水平方向条纹的横向移动
但是如果要是倾斜45度就出现问题了
1 | .inner:after { |
这个时候应该改为使用repeating-linear-gradient
属性,在所有方向上重复渐变以覆盖其整个容器,使用这个属性时,色标值需要写完整:
1 | background: repeating-linear-gradient(90deg, blue 0 ,blue 50%, red 50%, red 100%); |
所以这样可以实现斜着45度的进度条:
1 | .inner:after { |
(2019-10.21更新)之前理解有错误,其实repeating-linear-gradient
就等于linear-gradient
+ background-repeat
+ background-size
,因为之前用的是百分比来确定色款其实体现不出来,上面的代码不用repeating-linear-gradient
而是直接使用linear-gradient
也是可以直接实现的。
如果改用px
,就可以舍弃background-size
,直接使用repeating-linear-gradient
实现:
1 | .inner:after { |
参考:
不规则卡片
想要实现这样的卡片:
上面的不规则椭圆切口使用background
的radial-gradient
实现。
它的第一个参数定义圆形渐变的中心点,默认为背景的中心,第二个参数定义渐变的形状,可以取值circle
(圆形)和ellipse
(椭圆),这两个参数可以通过at
关键字合并为一个参数,比如circle at 50% -5px
后面的参数和线性填充一样,表示某个确定位置的固定色值,形式为color1 position1, color2 position2
,这个位置值是相对虚拟渐变射线的位置值,如果是圆形可以理解为半径
所以这样的一个椭圆缺口可以通过下面实现:
1 | .top { |
第一个参数定义了在50%, -5px
的横纵坐标位置的一个圆形填充,如果不指定位置如下:
后面的色值参数实际上省略了一部分,完整的应该是:
1 | .top { |
定义了在20px
范围内是透明色,在21px
到填充满都是蓝色,之所以大了1px
是为了让边缘平滑。这样切口实现。
下面实现上下两个色块的交界处的波浪线,可以利用伪元素加上样式为dotted
的border
实现:
1 | .top:after { |
dotted
的边框,显示为一系列圆点。标准中没有定义两点之间的间隔大小,视不同实现而定。圆点半径是border-width
计算值的一半。
参考:
圆和椭圆
一般我们会使用border-radius
实现圆角效果,但是实际上使用border-radius
可以实现圆、椭圆、半圆等各种圆形的效果。
我们常用的可能就是border-radius: 5px
,但是实际上它是一个缩写,它的完整写法是:
1 | border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px |
这八个取值以/
进行分割,每一组四个值,分别代表左上、右上、右下、左下四个角的圆角半径,第一组值是水平方向半径,第二组是垂直方向的半径
1 | border-radius: 左上角水平圆角半径大小 右上角水平圆角半径大小 右下角水平圆角半径大小 左下角水平圆角半径大小 |
理解了完整的取值,就可以通过设置不同的值来实现不同的圆形。以半圆为例:
首先矩形的宽度应该是高度的2倍,上图的半圆应该设置的是左上和右上的圆角,而且水平半径应该都是矩形宽度的一半,垂直半径应该等于矩形高度,所以:
1 | .semicircle { |
border-radius
的百分比是相对于offsetWidth
和offsetHeight
进行设置的,及包括了content
、padding
以及border
的宽度。
更多的实现起来也就不难了,无非是各种组合。
参考
四边形
实现一个四边形我首先想到的方案是使用矩形+三角形拼接而成,三角形使用border
来实现:
1 | .parallel1 { |
能够实现,但是代码量是在是不少,而且还占据了两个伪元素。其实有两种更简单的方法,一种是使用transform: skew
,skew
的意思就是偏离、扭转,它定义了在2D平面上一个对象的歪斜变换,参数可以使一个也可以是两个,当是两个的时候,分别表示沿着横坐标、从坐标扭曲元素的角度。
它的效果可以看下面的三幅图:
transform: skewX(30deg)
transform: skewY(30deg)
transform: skew(30deg)
所以用它来实现四边形就很简单了:
1 | .parallel2 { |
还有一种方法是使用clip-path
,它可以用来创建一个只有元素的部分区域显示的剪切区域,区域内的部分显示,区域外的隐藏(这个属性替代了已经弃用的clip
属性)
它的可能取值有:
clip-source
,用一个SVG的URL来表示剪切元素的路径,比如clip-path: url(resources.svg#c1);
geometry-box
,为基本形状提供相应的参考矿框盒,可以取值有margin-box
、border-box
、padding-box
、content-box
、fill-box
等basic-shape
,可以用一些预置的形状来进行剪切,比如circle
、epplipse
、polygon
用这个属性与使用SVG是很类似的,可以实现多种多样的形状,使用clie-path: polygon(A, B, C, D)
就可以实现各种四边形。其中A/B/C/D分别是四个点的坐标值,其中横坐标在前,纵坐标在后:
1 | .parallel3 { |
可以实现类似菱形的四边形:
1 | .parallel4 { |
也可以实现一个三角形:
1 | .parallel5 { |
简直太强大了。
参考
切角效果
想实现下面这两种切角效果
有三种方法,实际上前面都介绍过,先看实现直角切角效果
(1)首先可以使用linear-gradient
,首先定义一个方向的直线渐变:
1 | .corner1 { |
要注意的是,这个切角是定义的左下角的位置,首先这个「左下角」是由background-position
定义的,只不过简写在background
属性中
还要注意的是角度,只需要记住to top
是0deg
,to right
是90deg
,计算角度时需要从镜像的起始点出发计算
然后定义了background-size: 51% 51%;
相当于只定义了左下角四分之一的背景填充:
之所以不用50%
而是51%
,是为了防止有些浏览器在渲染时出现缝隙的问题,和border-radius
设置为51%
是一样的道理。
所以按照同理,将另外三个角补充完整即可:
1 | .corner1 { |
(2)也可以使用之前一节学习过的clip-path
来实现,将这个切过角的形状作为一个多边形,将各个坐标点描绘出来即可(当然也可以使用内联SVG)
在描述各点坐标时,可以使用calc
这个属性来计算,小心点一点别把横纵坐标搞错就行:
1 | .corner2 { |
(3)圆角切角可以使用radial-gradient
实现,原理与使用linear-gradient
类似,只是需要额外指定径向渐变的圆心位置:
1 | .corner3 { |
参考
使用一个div
实现进度条
1 | .bar { |
效果:
为了使完成部分也出现圆角,可以添加一个radial-gradient
,利用它可以实现一个圆球:
1 | .circle { |
综合起来:
1 | .bar { |
注意,background-size
两个取值之间有一个逗号,意味着是对多个背景的设置,一个背景的设置中如果提供了两个数值时,第一个将作为宽度,第二个作为高度,如果只提供了一个数值,那么它将作为宽度值大小,高度值会被设为auto
,所以完整的写法是:
1 | background-size: 100% auto, var(--p) auto; |
实现的效果:
参考
空心圆环
想到了四种方法来实现空心圆环:
(1)使用标签嵌套(或者伪元素)
1 | .circle { |
使用标签嵌套和微元素原理一样,缺点是需要设置背景色与整体的背景色一致,并非完全的空心圆环
(2)使用border-radius
1 | .circle { |
元素本身是透明背景,边框有颜色
(3)使用box-shadow
1 | .circle { |
与上一种方案类似
(4)使用radial-gradient
1 | .outer4 { |
(5)outline
使用outline
是无法实现的,因为border-radius
不能影响outline