关于本书

浏览器支持与回退机制

当指定一个渐变色作为背景的时候,应该在前面添加一行实色背景声名。

添加实色的一个好方法是取渐变色的平均值,比如:

  1. width: 100px;
  2. height: 200px;
  3. background: rgb(255, 128, 0);
  4. background: -moz-linear-gradient(0deg, yellow, red);
  5. background: -o-linear-gradient(0deg, yellow, red);
  6. background: -webkit-linear-gradient(0deg, yellow, red);
  7. background: linear-gradient(0deg, yellow, red);

可以使用 Modernizr 来检测用户浏览器是否支持 HTML5 与 CSS3 特性。这样就可以针对支持或不支持某些特性的浏览器来分别编写样式了。

还可以使用 @supports 规则来实现回退。但是需要慎用,因为只有在同时支持 CSS 样式和 @supports 规则的浏览器中样式才会生效。

也可以自己写一小段 JavaScript 代码来实现相同的功能

function testProperty(property) {
  var root = document.documentElement;

  if (property in root.style) {
    root.classList.add(property.toLowerCase());
    return true;
  }

  root.classList.add('no-' + property.toLowerCase());
  return false;
}

如果我们想要检测某个具体的属性值是否支持,以下可以实现:

function testValue(id, value, property) {
  var dummy = document.createElement('p');
  dummy.style[property] = value;

  if (dummy.style[property]) {
    root.classList.add(id);
    return true;
  }

  root.classList.add('no-' + id);
  return false;
}

注意:浏览器可以解析某个 CSS 特性并不代表它已经实现(或正确实现)了这个特性。

CSS 编码技巧

尽量减少重复代码

代码可维护性的最大要素是尽量减少改动时要编辑的地方。

例如以下这个例子:

padding: 6px 16px;
border: 1px solid #446d88;
background: #58a linear-gradient(#77a0bb, #58a);
border-radius: 4px;
box-shadow: 0 1px 5px gray;
color: white;
text-shadow: 0 -1px 1px #335166;
font-size: 20px;
line-height: 30px;

image.png
如果我们决定把父级字号加大,就不得不修改每一次使用绝对值作为字体尺寸的样式。如果改用百分比或 em 单位(根据需求也可以使用 rem)就好多了

当某些值相互依赖时,应该把它们的相互关系用代码表达出来。

例如 line-heightpaddingborder-radiusbox-shadowtext-shadow 与字号间的关系。

修改后:

padding: .3em .8em;
border: 1px solid #446d88;
background: #58a linear-gradient(#77a0bb, #58a);
border-radius: .2em;
box-shadow: 0 .05em .25em gray;
color: white;
text-shadow: 0 -.05em .05em #335166;
font-size: 125%;
line-height: 1.5;

此时如果我们要创建一个红色的按钮需要覆盖四条声名(border-color、background、box-shadow 和 text-shadow),并且要根据按钮的亮面和暗面来编写 linear-gradient 属性

只要把半透明的黑色或白色叠加在主色调上,即可产生主色调的亮色和暗色变体,再覆盖 background-color 属性就可以解决:

padding: .3em .8em;
border: 1px solid #446d88;
background: #58a linear-gradient(hsl(0, 0%, 100%, .2), transparent);
border-radius: .2em;
box-shadow: 0 .05em .25em gray;
color: white;
text-shadow: 0 -.05em .05em #335166;
font-size: 125%;
line-height: 1.5;

image.png

1.代码易维护 vs 代码量少

有时候,代码易维护和代码量少不可兼得。例如:

border-width: 10px 10px 10px 0;

如果以后要改动边框的宽度,你需要同时修改三个地方。如果拆成两条声明的话,改起来就容易多了:

border-width: 10px;
border-left-width: 0;

2.currentColor

currentColor 相当于一个变量,代表的是当前文本的字体颜色。由于 color 属性可以被继承,所以后代都可以使用 currentcolor 来调用祖元素的颜色。 currentColor 本身也是很多颜色的初始值,比如 border-coloroutline-colortext-shadowbox-shadow

hr {
  height: .5em;
  background: currentColor;
}

3.继承
**
inherit 关键字可以用在任何 CSS 属性中,它总是绑定到父元素的计算值(对伪元素来说,则会取生成该伪元素的宿主元素)。

例如把表单元素的字体设定为与页面的其他部分相同:

input, select, button {
  font: inherit;
}

把超链接的颜色设定为与页面中其他文本相同:

a {
  color: inherit; 
}

inherit 关键字对于背景色同样非常有效:

.callout {
  position: relative; 
}

.callout::before {
  content: "";
  position: absolute;
  top: -.4em; left: 1em;
  padding: .35em;
  background: inherit;
  border: inherit;
  border-right: 0;
  border-bottom: 0;
  transform: rotate(45dg);
}

image.png

相信你的眼睛,而不是数字

我们的眼睛在看到一个完美垂直剧中的物体时,会感觉它并不居中。实际上,我们应该把这个物体从几何学的中心点再稍微向上挪一点,才能取得理想的视觉效果:
image.png
圆形的字形(比如 0)与矩形字形相比,需要稍微大一些,因为我们倾向于把圆形感知得比实际尺寸更小一些。
image.png
假如我们给容器的四边指定相同的内边距,则实际效果看起来并不相等:
image.png
原因在于,字母的形状在两端都比较整齐,而顶部和底部则往往参差不齐,就需要减少顶部和底部的内边距。
image.png

关于响应式网页设计

每个媒体查询都会增加成本,未来每次对 CSS 代码的修改要求我们逐一核对这些媒体查询是否需要配合修改。

大部分代码应该以弹性的方式来编写,而把它作为最后的手段。例如希望在较大或较小的视口下完全改变网站的设计(譬如把侧边栏改成水平布局)。

媒体查询的断点不应该由具体的设备来决定,而应该根据设计自身来决定。不仅因为需要面向的设备太多了,还因为桌面端可能会以任意尺寸的窗口来显示。

下面的建议避免不必要的媒体查询:

  • 使用百分比长度来取代固定长度,也可以尝试与视口相关的单位(vw、vh、vmin、和 vmax)。
  • 当需要在较大分辨率下得到固定宽度时,使用 max-width 而不是 width,因为它可以适应较小的分辨率,而无需媒体查询。
  • 不要忘记为替换元素(比如 img、object、video、iframe)设置一个 max-width ,值为 100%。
  • 使用 background-size: cover 可以使背景图片铺满容器,但是通过 CSS 把一张大图缩小显示往往是不太明智的。
  • 当图片(或其他元素)以行列形式进行布局时,让视口的宽度来决定列的数量。
  • 在使用多列文本时,指定 column-width 而不是指定 column-count,这样它就可以在较小的屏幕上自动显示为单列布局。

合理使用简写

使用展开式写法可能会干扰你想要达到的效果,例如 background-color 后面还可能同时会有 background-image。当然,如果我们明确地去覆盖某个具体的展开式属性,那就需要使用展开式属性,就像 “尽量减少代码重复”一节中那样。

展开式属性与简写属性的配合使用:

background: url(tr.png) no-repeat top right / 2em 2em,
                        url(br.png) no-repeat bottom right / 2em 2em,
                        url(bl.png) no-repeat bottom left / 2em 2em;

可以写成:

background: url(tr.png) top right,
                        url(br.png) bottom right,
                        url(bl.png) bottom left;

background-size: 2em 2em;
background-repeat: no-repeat;

我应该使用预处理器吗

预处理器不是完美无缺的:

  • CSS 的文件体积和复杂度可能会失控。即使是简洁明了的源代码在经过编译后也可能会变得复杂。
  • 预处理器的编译延时让你不得不等待一段时间才能预览到代码的效果。
  • 每次抽象都必然会带来更高的学习成本。
  • 预处理器也有它自己的 bug,我们很少会怀疑预处理器的某个 bug 才是我们出错的原因。
  • 网站开发者可能会不自觉地“依赖”和“滥用”。
  • 未来很多预处理吕的特性都会融入到原生 CSS 中,而原生特性通常比预处理器提供的要强大得多(以下为例子)。

预处理吕完全不知道如何完成 100% -50px 这样的计算,因为在页面真正被渲染之前,百分比值是无法解析的。

下面的变量玩法在预处理器中也是不可能做到的:

在有序列表中列表项的背景色是 rebeccapurple ,在无序列表中将是 purple(在预处理器中不也可以使用 CSS 语法吗???)

ul {--accent-color: purple;}
ol {--accent-color: rebeccapurple;}
li {background: var(--accent-color);}

建议在每个项目的开始时使用纯 CSS ,只有当代码开始变得无法保持 DRY 时使用。

背景与边框

半透明边框

默认情况下,背景会延伸到边框所在的区域下层。
image.png
可以通过 background-clip 属性来调整上述默认行为实现半透明边框(属性文档)。

border: 10px solid hsla(0, 0%, 100%, .5);
background: white;
background-clip: padding-box;

image.png

多重边框

box-shadow 方案

使用 box-shadow 指定一个为零的偏移量以及为零的模糊值,得到的“投影”其实就是一道实线边框。

background: yellowgreen;
box-shadow: 0 0 0 10px #665;

image.png
相对于 border 属性来说 box-shadow 的好处在于支持逗号分隔语法,可以创建任意数量的投影。需要注意的是 box-shadow 是层层叠加的,需要调整扩张半径。

</html>
background-color: yellowgreen;
box-shadow:
  0 0 0 10px #665,
  0 0 0 15px deeppink,
  0 2px 5px 15px rgba(0, 0, 0, .6);

image.png

  • 投影不会影响布局,而且也不会受到 box-sizing 属性的影响。不过可以通过内边距或外边距来模拟出边框所需要占据的空间。
  • 投影并不会响应鼠标事件,比如悬停或点击。可以给 box-shadow 属性设置 inset 关键字,来使投影绘制在元素的内圈,但需要增加额外的内边距来腾出足够的空隙。

outline 方案
**
当只需要两层边框时,可以加上 outline 属性来产生外层的边框。优点在于 outline 可以产生虚线边框,而 box-shadow 不行。

另外还可以通过 outline-offse 属性来控制它跟元素边缘之间的间距,甚至能接受负值。

outline: 1px dashed white;
outline-offset: -10px;

image.png
这个方案同样也有需要注意的的地方:

  • outline 并不接受用逗号分隔多个值,想获取更多层的边框,box-shadow 方案是唯一选择。
  • 边框不会贴合 border-radius 产生的圆角,未来有可能改善。

灵活的背景定位

在 CSS2.1 中 ,我们只能指定背景图片距离左上角的偏移量,或者干脆完全靠齐到其他三个角。

对于具有固定尺寸的容器来说,若要设置距离右下角的偏移量,可以计算距离左上角的偏移量再设置给 background-postion

当容器尺寸不固定时,就难以做到了(可以设置百分比)。

background-position 的扩展语法方案
**
background-postion 已经得到了扩展,只要我们在偏移量前指定关键字。

background: url(./eg_bg_03.gif) no-repeat #58a;
background-position: right 20px bottom 10px;

image.png
提供一个回退方案也很简单,就是把老套的 bottom right 定位值写进 background 属性中。

background: url(./eg_bg_03.gif) rigth bottom no-repeat #58a;
background-position: right 20px bottom 10px;

background-origin 方案
**
当偏移理与容器的内边距一样时,如果采用扩展语法,代码会是这样:

padding: 10px
background: url(./eg_bg_03.gif) rigth bottom no-repeat #58a;
background-position: right 10px bottom 10px;

每次改动内边距时,都需要更新三个值。

默认情况下,background-postion 是以 padding-box 为准的。
image.png
通过设置 background-origincontent-box 就能使偏移量和内边距保持一致了。

background: url(./eg_bg_03.gif) rigth bottom no-repeat #58a;
background-origin: content-box;

background-positionbackground-origin 也能组合起来使用。

calc() 方案
**
将背景图片定位到距离底边 10px 且距离右边 20px 的位置,其实就是希望它有一个 100%-20px 的水平偏移量,以及 100%-10px 的垂直偏移量。可以通过 calc() 函数来实现:

background: url(./eg_bg_03.gif) no-repeat #58a;
background-position: calc(100% - 20px) calc(100% - 10px);

边框内圆角

有时我们需要一个容器,只有内侧有圆角,而边框或描边是直角。可以用两个元素实现这个效果:

.box {
  background: #655;
  padding: .8em;
}
.box > div {
  background: tan;
  border-radius: .8em;
  padding: 1em;
}

image.png
使用两个元素时会更加灵活,因为它允许我们充分运用背景的能力。

同样,使用一个元素也可以实现:

background: tan;
border-radius: .8em;
padding: 1em;
box-shadow: 0 0 0 .6em #655;
outline: .6em solid #655

利用描边不会贴合元素的圆角,但 box-shadow 会的特性,将两者叠加到一起,box-shadow 刚好填补描边和容器之间的空隙。
image.png
到底多大的阴影扩张值可以填补这些空隙呢:

根据勾股定理可得斜边 = √(a² + b²) = √(2a²) = a√2

由图可知阴影的扩张值 = r√2 - r = (√2 - 1)r
image.png

条纹背景

可能有人试过用 SVG 来取代位图,但这样不是会有一个独立的文件。

通过 linear-gradient 属性可以设置垂直线性渐变:

background: linear-gradient(#fb3, #58a);

image.png
当把两个实色拉进时可以得到一个水平条纹:

background: linear-gradient(#fb3 50%, #58a 50%);

image.png
通过 bakcground-size 设置条纹的高度,再通过默认属性 repeat 铺满:

background: linear-gradient(#fb3 50%, #58a 50%);
background-size: 100% 30px;

image.png
如果我们把第二个色标的位置值设置为 0,那它的位置总是被浏览器调整为前一个色标的位置值 。

background: linear-gradient(#fb3 50%, #58a 0);
background-size: 100% 30px;

要创建超过两种颜色的条纹也很容易:

background: linear-gradient(#fb3 33.3%, #58a 0, #58a 66.6%, yellowgreen 0);
background-size: 100% 30px;

image.png
垂直条纹
**
我们只需要在水平条纹的代码开头加上一个额外的参数来指定渐变的方向,再将 background-size 的值颠倒。

background: linear-gradient(to right, #fb3 50%, #58a 50%);
background-size: 30px 100%;

image.png
斜向条纹
**
旋转的原理只是把每个贴片进行了旋转,只有单个贴片包含了四条条纹旋转,才能实现斜向条纹。

background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #fb3 0, #fb3 75%, #58a 0);
background-size: 30px 30px;

image.png
这些条纹看起来比前面制作的水平和垂直条纹细一些,背景的尺寸决定了直角三角形斜边长度。
image.png
如果想让条纹的宽度变化为匀们原本想要的 15px,就需要把 background-size 指定为 2 * 15√2

更好的斜向条纹
**
假设我们想让条纹不是 45° 而是 60° 时,如果只把渐变的角度改一下,那么结果会相当糟糕。
image.png
可以使用循环式 repeating-linear-gradient()repeating-redial-gradient(),它们的工作方式跟前两者相似,只有一点不同:色标是无限循环重复的,直到填满整个背景。

background: repeating-linear-gradient(45deg, #fb3, #58a 30px);

image.png
还原以上例子:

background: repeating-linear-gradient(45deg, #fb3, #fb3 15px, #58a 0, #58a 30px);

image.png
使用 repeating-linear-gradient 的好处:

  • 改动颜色时只需要修改两处,而不是原来的三处。
  • 渐变中指定的长度直接代表了条纹自身的宽度,不用再进行计算了。
  • 可以随心所欲改变旋转的角度

image.png
我们在创建双色条纹时都需要用到四个色标,这意味着,我们最好用前面的方法来实现水平或垂直的条纹,而用这种方法来实现斜向条纹。

我们甚至可以将两种方法结合起来:

background: repeating-linear-gradient(45deg, #fb3 0, #fb3 25%, #58a 0, #58a 50%);
background-size: 42px 42px;

灵活的同色系条纹
**
有时我们只是需要在明度方面有着轻微的差异:

background: repeating-linear-gradient(30deg, #79b, #79b 15px, #58a 0, #58a 30px);

image.png
我们可以把最深的颜色指定为背景色,同时把半透明白色的条纹叠加在背景色之上来得到深色条纹:

background: #58a;
background-image: repeating-linear-gradient(30deg,
                                        hsla(0,0%,100%,.1),
                                        hsla(0,0%,100%,.1) 15px,
                                        transparent 0, transparent 30px);

得到的效果是一样的,并且只需要修改一个地方就可以改变所有颜色。对于那些不支持 CSS 渐变的浏览器来说,这里的背景色还起到了回退的作用。

复杂的背景图案

用 CSS 渐变来创建任何各类的几何几何图案几乎都是可能的,只不过有时这种方法太过复杂。

网格

我们可以把透明的水平和垂直条纹叠加起来,从而得到各种样式的风格:

background: white;
background-image: linear-gradient(90deg,
                                        rgba(200,0,0,.5) 50%, transparent 0),
                                    linear-gradient(
                                        rgba(200,0,0,.5) 50%, transparent 0);
background-size: 30px 30px;

image.png
某些情况下我们希望风格中每个格子的大小可以调整,而网格线条的粗细同时保持固定。可以使用固定长度来代替百分比。

background: #58a;
background-image: 
    linear-gradient(90deg, white 1px, transparent 0),
  linear-gradient(white 1px, transparent 0);
background-size: 30px 30px;

image.png
SVG 代码不见得比它更短。

我们甚至可以把两幅不同线宽、不同颜色的风格图案叠加起来:

background: #58a;
background-image: 
    linear-gradient(90deg, white 2px, transparent 0),
  linear-gradient(white 2px, transparent 0),
    linear-gradient(hsla(0,0%,100%,.3) 1px, transparent 0),
    linear-gradient(90deg, hsla(0,0%,100%,.3) 1px, transparent 0);
background-size: 75px 75px, 75px 75px,
                                 15xp 15px, 15px 15px;

image.png
波点

径向渐变也同样非常实用,因为它允许我们创建圆形、椭圆、或是它们的一部分。
创建加点阵列:

background: #655;
background-image: radial-gradient(tan 30%, transparent 0);  
background-size: 30px 30px;

image.png
我们可以生成两层圆点阵列图案,并把它们的背景定位错开,就能得到以下:
image.png

background: #655;
background-image: radial-gradient(tan 30%, transparent 0),
                                  radial-gradient(tan 30%, transparent 0);  
background-size: 30px 30px;
background-position: 0 0, 15px 15px;

注意第二层的偏移定位值必须是贴片宽高的一半。意味着如果要改动贴片的尺寸,需要修改四处。
可以使用预处理器的 mixin 解决:

@mixin polke($size, $dot, $base, $accent) {
  background: $base;
  background-image:
      radial-gradient($accent $dot, transparent 0),
      radial-gradient($accent $dot, transparent 0);
  background-size: $size $size;
  background-position: 0 0, $size/2 $size/2;
}

@include polka(30px 30%, #655, tan);

棋盘

用一层 CSS 渐变无法创建四周有空隙的方块。
image.png
但用两个直角三角形可以拼合出我们想要的方块:

background: #eee;
background-image: linear-gradient(45deg, #bbb 25%, transparent 0);
background-size: 30px 30px;

image.png
把角标反转就能创建相反的三角形:
image.png
再把二层的渐变在水平和垂直方向均移动贴片长度的一半,然后组合:

background: #eee;
background-image:
  linear-gradient(45deg, #bbb 25%, transparent 0),
  linear-gradient(45deg, transparent 75%, #bbb 0);
background-position: 0 0, 15px 15px;
background-size: 30px 30px;

image.png
这只是棋盘的一半,我们需要把这一组渐变重复一份就能得到上图的棋盘:

background: #eee;
background-image:
  linear-gradient(45deg, #bbb 25%, transparent 0),
  linear-gradient(45deg, transparent 75%, #bbb 0),
  linear-gradient(45deg, #bbb 25%, transparent 0),
  linear-gradient(45deg, transparent 75%, #bbb 0);
background-position: 0 0, 15px 15px,
                                       15px 15px, 30px 30px;
background-size: 30px 30px;

我们还可以把第一组和第二组合并为一层渐变,把第三组和第四组合并为一层渐变,再把深灰色改成半透明的黑色。这样我们只需要修改底色就可以改变整个棋盘的色调:

background: #eee;
background-image:
  linear-gradient(45deg,
    rgba(0, 0, 0, .25) 25%, transparent 0,
    transparent 75%, rgba(0, 0, 0, .25) 0),
  linear-gradient(45deg,
    rgba(0, 0, 0, .25) 25%, transparent 0,
    transparent 75%, rbga(0, 0, 0, .25) 0);
background-position: 0 0, 15px 15px;
background-size: 30px 30px;

伪随机背景

多样性和随机性可以使背景显得更自然,然而 CSS 本身并没有提供任何随机功能。
当我们创建四种颜色的条纹图案时,重复规律是非常明显的:

background: linear-gradient(90deg,
              #fb3 15%, #655 0, #655 40%,
              #ab4 0, #ab4 65%, hsl(20, 40%, 90%));
background-size: 80px 100%;

捕获.PNG
我们把这组条纹从一个平面拆散为多个图层:一种颜色作为底色,另三种颜色作为条纹,然后再让条纹以不同的间隔进行重复平铺。

background: hsl(20, 40%, 90%); 
background-image: 
  linear-gradient(90deg, #fb3 10px, transparent 0),
  linear-gradient(90deg, #ab4, 20px, transparent 0),
  linear-gradient(90deg, #655 20px, transparent 0);
background-size: 80px 100%, 60px 100%, 40px 100%;

图片.png
因为最顶层的贴片重复规律最容易被所以把平铺间距最大的贴片放在最顶层,但依然每隔 240px 就会重复。

各层背景图像以不同间距重复数次后再次统一对齐就是一个贴片的终点,所以贴片的尺寸实际上就是所有 background-size 的最小公倍数。

为了让最小公倍数最大化,这些数字最好是互质的(质数跟其它任意数字都是互质的)。

于是代码变成:

background: hsl(20, 40%, 90%); 
background-image: 
  linear-gradient(90deg, #fb3 11px, transparent 0),
  linear-gradient(90deg, #ab4, 23px, transparent 0),
  linear-gradient(90deg, #655 41px, transparent 0);
background-size: 41px 100%, 61px 100%, 83px 100%;

平铺的尺寸现在是 41x61x83=207583 像素。

这个技巧被 Alex Walker 定名为“蝉原则”,这个方法不仅可以用于背景,还可以用于其它涉及规律重复的情况。

  • 在照片库中,为每幅图片应用细微的伪随机旋转效果时,可以使用多个:nth-child(a)选择符,且让 a 是质数。
  • 生成一个动画,让它看起来不是按照明显的规律在循环时,可以应用多个时长为质数的动画。

连续的图像边框

有时我们想把一幅图案或图片应用为边框,而不是背景。
timg.jpg

如果使用 border-image 会让图片的某个特定部分固定在拐角处,我们希望出现在拐角处的图片区域是随着元素宽高和边框厚度的变化而变化。

最简单的办法是使用两个 HTML 元素:一个元素用来设置背景,另一个元素用来存放内容。但需要一个额外的 HTML 元素。

我们可以使用 background-clip 给两层背景指定不同的值,让下层的图片背景透过边框区域显示出来。注意只能为多层背景的最底层设置背景色,因此需要 CSS 渐变来模拟出背景的效果:

padding: 1em;
border: 1em solid transparent;
background:
  linear-gradient(white, white),
  url(bg.jpg);
background-size: cover;
background-clip: padding-box, border-box;

image.png
但边框的图片有一种怪异的拼接效果,原因是 background-origin 的默认值是 padding-box

padding: 1em;
border: 1em solid transparent;
background:
  linear-gradient(white, white),
  url(bg.jpg);
background-size: cover;
background-clip: padding-box, border-box;
background-origin: border-box;

image.png
这些属性可以整合到 background 这个简写属性中:

padding: 1em;
border: 1em solid transparent;
background:
  linear-gradinet(white, white) padding-box,
  url(bg.jpg) border-box 0 0 / cover

这个技巧也可以用在渐变图案上:

padding: 1em;
      border: 1em solid transparent;
      background:
        linear-gradient(white, white) padding-box,
        repeating-linear-gradient(-45deg,
          red 0, red 12.5%,
          transparent 0, transparent 25%,
          #58a 0, #58a 37.5%,
          transparent 0, transparent 50%) 0 / 5em 5em;

image.png
不过 border-image 方法存在一些问题:

  • 每当我们改变 border-image-slice 时,都需要同时修改 border-width 来让它们相互匹配。
  • 由于我们不能在 border-image-slice 属性中使用 em 单位,只能把边框厚度指定为像素单位
  • 条纹的宽度需要在色标的位置信息中写好,因此我们在改变条纹宽度时,需要修改四处。

还可以实现蚂蚁行军的效果,详细看 p49。、

当然,border-image 也有它强大的地方,尤其是在搭配渐变图案时。

实现一个顶部边框被裁切的效果:

border-top: .2em solid transparent;
border-image: 100% 0 0 linear-gradient(90deg,
    currentColor 4em,
    transparent 0);
padding-top: 1em;

image.png

形状

自适应椭圆

我们希望容器的宽高相等,就显示为一个圆,如果宽高不等,就显示为一个椭圆,并且它能根据其内容自动调整并适应。

border-radius 可以单独指定水平和垂直半径,只要用一个斜杠(/)分隔即可。并且还可以接受百分比值,百分比值会基于元素的宽高进行解析。

如果要创建一个自适应椭圆,可以把两个半径值都设置为 50%:

border-radius: 50% / 50%;

这行代码可以进一步简化:

border-radius: 50%;

半椭圆
**
border-radius 甚至可以为所有四个角提供完全不同的水平和垂直半径,方法是在斜杠前指定 1~4 个值,在斜杠后指定另外 1~4 个值。举例:10px / 5px 20px 效果相当于 10px 10px 10px 10px / 5px 20px 5px 20px
横轴半椭圆:

border-radius: 50% / 100% 100% 0 0;

捕获2.PNG
纵轴半椭圆:

border-radius: 100% 0 0 100% / 50%;

捕获3.PNG

平行四边行

创建一个平行四边形,然后通过 skew() 的变形属性来对这个矩形进行斜向拉伸:

transform: skewX(-45deg);

捕获4.PNG
但是这导致它的内容也发生了斜向变形。

嵌套元素方案

可以使用一层额外的 HTML 元素包裹内容再对内容应用一次反向的 skew() 变形,从而抵消容器的变形效果。

<a class="button">
 <div>Click me
</a>

.button { transform: skewX(-45deg); }
.button > div { transform:skewX(45deg); }

捕获5.PNG
伪元素方案

可以把所有样式(背景、边框等)应用到伪元素上,然后再对伪元素进行变形,因为内容并不包含在伪元素里,所以内容并不会受到变形的影响。

用伪元素生成的方块是重叠在内容之上的,所以要为伪元素设置 z-index: -1; 样式。
捕获6.PNG
最终效果与前文完全一致:

.button {
  position: relative;
  /* 其它的文字颜色、内边距等样式…… */
}
.button:before {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: -1;
  transform: skew(-45deg);
}

这个技巧还适用于其他任何变形样式,当想变形一个元素而不想变形它的内容时就可以用到它。

  • 如果要在 IE8 下实现多重背景,这个方法是个不错的变通解决方案。
  • 这个方法可以用来实现“边框内圆角”中的效果。
  • 可以用来为某一层“背景”单独设置类似 opacity这样的属性。
  • 当不能使用“多重边框”中的技巧时,这个方法可以用更加灵活的方式来模拟多层边框。

菱形图片

把图片裁切为菱形是一种常见的设计手法,但我们通常不希望在图像处理软件中预先把图片裁好。

基于变形的方案

与前一篇“平行四边形“中讨论的第一个解决方案一致:需要把图片用一个 <div> 包裹起来,然后对其应用相反的 rotate() 变形样式:

<div class="picture">
  <img src="adam-catlace.jpg" />
</div>

.picture {
  width: 400px;
  transform: rotate(45deg);
  overflow: hidden;  
}
.picture img {
  max-width: 100%;
  transform: rotate(-45deg);
}

image.png
由于 max-width: 100% 会被解析为容器(.picture)的连长,但是我们需要让图片的宽度与容器的对角线相等。通过勾股定理应该把 max-width 的值设置为 √2 * 100% ≈ 141.421% ,可以向上取整为 142%。

如果使用 scale() 变形样式来把图片放大会更加合理,原因如下:

  • 我们希望图片的尺寸保留 100% 这个值,这样当浏览器不支持变形样式时仍然可以得到一个合理的布局
  • 通过 scale() 变形样式来缩放图片时,是以它的中心点进行缩放的(除非我们额外指定了 transform-origin 样式)。通过 width 属性来放大图片时,只会以它的左上角为原点进行缩放,从而迫使我们动用额外的负外边距把图片的位置调整回来。

结合得到以下代码:

.picture {
  width: 400px;
  transform: rotate(45deg);  
  overflow: hidden;
}
.picture > img {
  max-width: 100%;
  transform: rotate(-45deg) scale(1.42);  
  }

image.png
裁切路径方案

上面的方法需要一层额外的 HTML 标签,并且处理不了一张非正方形的图片。

使用 clip-path 属性的 polygon() 多边形函数来指定一个菱形可以更好地实现同样的效果:

clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);

image.png

切角效果

视觉效果

字体排印

用户体验

结构与布局

过渡于动画

总结

  • 当指定一个渐变色作为背景的时候,应该在前面添加一行实色背景声名。
  • 代码可维护性的最大要素是尽量减少改动时要编辑的地方。
  • 只要把半透明的黑色或白色叠加在主色调上,即可产生主色调的亮色和暗色变体。
  • 合理使用简写属性使代码更易维护(哪怕代码量增多)。
  • 当设置颜色的地方与文本颜色相同时可以考虑使用 currentColor
  • 有相同样式时可以使用 inherit 关键字。
  • 媒体查询应该作为最后的响应式手段。
  • 涉及规律重复的情况下可以使用“蝉原则”。
  • border 设置渐变背景时,可以使用 border-image 。使用图片背景时,可以使用 background-clip
  • border-radius 可以生成各种圆。
  • 当想变形一个元素而不想变形它的内容时可以使用伪元素。
  • clip-path 可以生成各种几何图形。

未理解的部分(懒)

  • “连续的图像边框”border-image 方法存在的一些问题