css 揭秘

[希]Lea verou 著

css 魔法 译

该书涵盖7大主题,47个css技巧,是css进阶必备书籍,开阔思路,探寻更优雅的解决方案。这本书完全用css渲染出的html写成的(布局、图片、颜色、页码、章节号等)。

涵盖7大主题

  • 背景与边框
  • 形状
  • 视觉效果
  • 字体排印
  • 用户体验
  • 结构与布局
  • 过渡与动画

资料

浏览器支持与回退机制

  1. 提供及时有效的浏览器兼容信息的网站:

  2. 浏览器前缀书写:应该把标准语法排在最后,通过层叠机制确保哪条声明最终生效。

    1. background: rgb(255, 128, 0); /* 回退机制 */
    2. background: -moz-linear-gradient(90deg, yellow, red); /* 火狐 */
    3. background: -o-linear-gradient(90deg, yellow, red); /* Opera */
    4. background: -webkit-linear-gradient(90deg, yellow, red); /* Safari、Chrome*/
    5. background: linear-gradient(0deg, yellow, red);

    tip: 浏览器前缀生成工具:

    • Autoprefixer:根据 Can i use 数据库判断添加前缀,本地编译。
    • 作者开发的-prefix-free:在浏览器中进行特性检测,不需要更新,在真实环境中跑出来的结果。
  3. 使用Modernizr工具给根元素()添加辅助类,比如 textshadowno-textshadow针对支持或不支持某些特性的浏览器来分别编写样式

    1. h1 { color: gray; }
    2. .textshadow h1 {
    3. color: transparent;
    4. text-shadow: 0 0 .3em gray;
    5. }
  4. 尝试的 css 特性非常新,可以试试 @supports 规则实现回退,将其视作浏览器“原生”的 Modernizr。

    1. h1 { color: gray; }
    2. @supports (text-shadow: 0 0 .3em gray) {
    3. h1 {
    4. color: transparent;
    5. text-shadow: 0 0 .3em gray;
    6. }
    7. }

    tip: 慎用 @supports, 存在兼容性

  5. js 实现:做一些特性检测然后给根元素加一些辅助类。如果要检测某个样式属性是否被支持,核心思路就是在任一元素的 element.style 对象上检查该属性是否存在。

    1. var root = document.documentElement; // <html>
    2. if ('textShadow' in root.style) {
    3. root.classList.add('textshadow');
    4. } else {
    5. root.classList.add('no-textshadow');
    6. }
    7. // 多个
    8. function testProperty (property) {
    9. var root = document.documentElement; // <html>
    10. if (property in root.style) {
    11. root.classList.add(property.toLowerCase());
    12. return true;
    13. }
    14. root.classList.add('no-' + property.toLowerCase());
    15. return false;
    16. }

    检查某个具体的属性值是否支持,需要把它赋给对应的属性,然后再检查浏览器是否还保存着这个值。

    1. var dummy = document.createElement('p');
    2. dummy.style.backgroundImage = 'linear-gradient(red, tan)';
    3. if (dummy.style.backgroundImage) {
    4. root.classList.add('lineargradients');
    5. } else {
    6. root.classList.add('no-lineargradients');
    7. }
    8. // 多个
    9. function testValue(id, value, property) {
    10. var dummy = document.createElement('p');
    11. dummy.style[property] = value;
    12. if (dummy.style[property]) {
    13. root.classList.add(id);
    14. return true;
    15. }
    16. root.classList.add('no-' + id);
    17. return false;
    18. }

关于 web 标准

标准的每项规范从最初启动到最终成熟,必经阶段:

  1. 编辑草案(ED)
  2. 首个公开工作草案(FPWD)
  3. 工作草案(WD)
  4. 候选推荐规范(CR)
  5. 提名推荐规范(PR)
  6. 正式推荐规范(REC)

    可以认为到第5步就已经是趋于成熟了,到最后阶段只是时间问题。

关于css3、css4及其他传说

tip:为什么不会有CSS4了?

css 编码技巧

  • DRY:Don't Repeat Yourself。尽量减少改动时要编辑的地方
  • 可维护性、可扩展。

举例:

  • 当某些值相互依赖时,应当把它们的相互关系用代码表达出来。
  1. font-size: 20px;
  2. line-height: 1.5; // 等同于 line-height: 30px;
  • 单位:px 改 em、rem,同步放大、缩小
  • 颜色:只要把半透明的黑色或白色叠加在主色调上,即可产生主色调的亮色和暗色变体
  1. button {
  2. padding: .3em .8em;
  3. border: 1px solid rgba(0, 0, 0, .1);
  4. background: #58a linear-gradient(hsla(0, 0%, 100%, .2), transparent);
  5. border-radius: .2em;
  6. box-shadow: 0 .05em .25em rgba(0, 0, 0, .5);
  7. color: white;
  8. text-shadow: 0 -.05em .05em rgba(0, 0, 0, .5);
  9. font-size: 125%;
  10. line-height: 1.5;
  11. }
  12. button.cancel {
  13. background-color: #c00;
  14. }
  15. button.ok {
  16. background-color: #6b0;
  17. }
  • 代码易维护
  1. border-width: 10px;
  2. border-left-width: 0;
  • currentColor,具体可看文章currentColor-CSS3超高校级好用CSS变量
  • 继承:inherit 可以用在任何css属性中,而且它总是绑定到父元素的计算值(对伪元素lais来说,则会取生成该伪元素的宿主元素)。
  1. // 举例,在创建提示框的时候,小箭头能够自动继承背景和边框的样式
  2. .callout {
  3. position: relative;
  4. }
  5. .callout::before {
  6. content: '';
  7. position: absolute;
  8. top: -.4em; left: 1em;
  9. padding: .35em;
  10. background: inherit;
  11. border: inherit;
  12. border-right: 0;
  13. border-bottom: 0;
  14. transform: rotate(45deg);
  15. }

  • 相信你的眼睛,而不是数字:视觉错误,有针对性的调整

    • 眼睛在看到一个完美垂直居中的物体时,会感觉它并不居中。需要把这个物体从几何学的中心点再稍微往上挪一点
    • 圆形的字形(比如0)需要比矩形字形稍微放大一些。圆形占据的宽高和矩形一致,但圆形看着要小一些,因为我们倾向于把圆形感知得比其实际尺寸更小一些。
    • 文本容器设置内边距,文字:yolo,四边指定相同,但实际看起来上下空得多。需要减少顶部、底部的内边距。原因在于:字母的形状在两端都比较整齐,而顶部和底部则往往参差不齐。
  • 响应式网页设计(灵活有弹性):媒体查询是最后的手段。尽最大努力实现弹性可伸缩的布局,并在媒体查询的各个断点区间内指定相应的尺寸。

    • 使用百分比单位,或其他相对单位,比如 vw、vh、vmin、vmax,而非绝对单位px
    • 当需要在较大分辨率下得到固定宽度时,使用max-width而不是width。因为能适应较小的分辨率
    • 不要忘记伪替换元素(比如img、object、video、iframe等)设置一个max-width,值为100%
    • 假如背景图片需要完整地铺满一个容器,不管容器的尺寸如何变化,请设置 background-size:cover.
    • 在使用多列文本时,指定 column-width(列宽)而不是指定 column-count(列数),这样它就可以在较小的屏幕上自动显示为单列布局。
  • 合理使用简写

    • 比如:background: url(tr.png) no-repeat rop right / 2em em;
    • 怪异的简写语法:即使是初始值也要写出来,使用/作为分隔。这通常是为了消除歧义。在上面的例子中,top right 显然是 background-position,而 2em 2em 是 background-size。但是,设想一下 50% 50%,解析器就无法解析了。
  • 合理使用预处理器

    • 使用原生特性,比预处理器提供的版本强大的多

      • css 自定义变量
      1. ul {--accent-color: purple;}
      2. ol {--accent-color: rebeccapurple;}
      3. li {background: var(--accent-color);}
      • css 值与单位:calc() 函数
      • css 颜色:color() 函数
      • css 嵌套:正在讨论
    • 合理使用预处理器,让代码灵活

背景与边框

  1. 半透明边框(translucent-borders)
  1. border: 10px solid hsla(0, 0%, 100%, .5);
  2. background: white;
  3. background-clip: padding-box;

  1. 多重边框(multiple-borders)

box-shadow 方案

  1. background: yellowgreen;
  2. box-shadow: 0 0 0 10px #655,
  3. 0 0 0 15px deeppink,
  4. 0 2px 5px 15px rgba(0, 0, 0, .6);

注意事项:不影响布局,不受 box-sizing 属性影响,outset的区域不响应鼠标事件,改为inset。

outline 方案

  1. background: #655;
  2. outline: 1px dashed #fff;
  3. outline-offset: -10px;

不贴合border-radius

  1. 灵活的背景定位

background-position 方案

  1. background: url(http://csssecrets.io/images/code-pirate.svg)
  2. no-repeat bottom right #58a;
  3. background-position: right 20px bottom 10px;

background-origin 方案

  1. background: url(http://csssecrets.io/images/code-pirate.svg)
  2. no-repeat bottom right #58a;
  3. background-origin: content-box;

background-position是以padding box为准的

calc() 方案

  1. background: url(http://csssecrets.io/images/code-pirate.svg)
  2. no-repeat bottom right #58a;
  3. background-position: calc(100% - 20px) calc(100% - 10px);
  1. 边框内圆角
  1. background: tan;
  2. border-radius: .8em;
  3. padding: 1em;
  4. box-shadow: 0 0 0 .6em #655;
  5. outline: .6em solid #655;

勾股定理:a*a + b*b = c*c

扩张半径需要比描边的宽度值小,但同时要比 (Math.sqrt(2) - 1) * r (根号2 - 1)r 大,r表示border-radius

  1. 条纹背景

横向

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

垂直条纹

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

斜向条纹

  1. background: linear-gradient(45deg,
  2. #fb3 25%, #58a 0, #58a 50%,
  3. #fb3 0, #fb3 75%, #58a 0);
  4. background-size: 42.4px 42.4px;

灵活的同色系条纹

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

  1. 复杂背景

网格

  1. background: #58a;
  2. background-image: linear-gradient(white 2px, transparent 0),
  3. linear-gradient(90deg, white 2px, transparent 0),
  4. linear-gradient(hsla(0,0%,100%,.3) 1px, transparent 0),
  5. linear-gradient(90deg, hsla(0,0%,100%,.3) 1px, transparent 0);
  6. background-size: 50px 50px, 50px 50px,
  7. 10px 10px, 10px 10px;

波点: 两层,第二层背景偏移定位置必须是贴片宽高的一半

  1. background: #655;
  2. background-image: radial-gradient(tan 20%, transparent 0),
  3. radial-gradient(tan 20%, transparent 0);
  4. background-size: 30px 30px;
  5. background-position: 0 0, 15px 15px;

scss mixin

  1. // scss mixin
  2. @mixin polka($size, $dot, $base, $accent) {
  3. background: $base;
  4. background-image: radial-gradient($accent $dot, transparent 0),
  5. radial-gradient($accent $dot, transparent 0);
  6. background-size: $size $size;
  7. background-position: 0 0, $size/2 $size/2;
  8. }
  9. // 调用
  10. @include polka(30px, 30%, #655, tan);

棋盘: 用两个直角三角形来拼合出我们想要的方块,把第二层渐变在水平和垂直方向均移动贴片长度的一半

  1. .checkerboard {
  2. background: #eee;
  3. background-image:
  4. linear-gradient(45deg, rgba(0,0,0,.25) 25%, transparent 0, transparent 75%, rgba(0,0,0,.25) 0),
  5. linear-gradient(45deg, rgba(0,0,0,.25) 25%, transparent 0, transparent 75%, rgba(0,0,0,.25) 0);
  6. background-position: 0 0, 15px 15px;
  7. background-size: 30px 30px;
  8. }
  9. // scss mixin
  10. @mixin checkerboard($size, $base, $accent: rgba(0, 0, 0, .25)) {
  11. background: $base;
  12. background-image: linear-gradient(45deg, $accent 25%, transparent 0, transparent 75%, $accent 0),
  13. linear-gradient(45deg, $accent 25%, transparent 0, transparent 75%, $accent 0);
  14. background-size: 2*$size 2*$size;
  15. background-position: 0 0, $size $size;
  16. }
  17. // 调用
  18. @include checkerboard(15px, #58a, tan);

棋盘-svg

  1. background: #eee url('data:image/svg+xml,
  2. <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill-opacity=".25" >\
  3. <rect x="50" width="50" height="50" />\
  4. <rect y="50" width="50" height="50" />\
  5. </svg>');
  6. background-size: 30px 30px;

棋盘-圆锥渐变实现:存在兼容性

  1. background: repeating-conic-gradient(#bbb 0, #bbb 25%, #eee 0, #eee 50%);
  2. background-size: 30px 30px;

调色盘: 圆锥渐变

  1. border-radius: 50%;
  2. background: conic-gradient(red, yellow, lime, aqua, blue, fuchsia, red);

  1. 连续的图像边框

技巧:背景边框:在石雕背景图片之上,再叠加一层纯白的实色背景

  1. padding: 1em;
  2. border: 1em solid transparent;
  3. background: linear-gradient(white, white) padding-box,
  4. url(http://csssecrets.io/images/stone-art.jpg) border-box 0 / cover;
  5. width: 21em;
  6. overflow: hidden;
  7. resize: both;

信封

  1. padding: 1em;
  2. border: 16px solid transparent;
  3. border-image: 16 repeating-linear-gradient(-45deg, red 0, red 1em, transparent 0, transparent 2em,
  4. #58a 0, #58a 3em, transparent 0, transparent 4em);

行军的蚂蚁

  1. .ants {
  2. padding: 1em;
  3. border: 1px solid transparent;
  4. background: linear-gradient(white, white) padding-box,
  5. repeating-linear-gradient(-45deg, black 0, black 25%, transparent 0, transparent 50%) 0 / .6em .6em;
  6. animation: ants 12s linear infinite;
  7. max-width: 20em;
  8. font: 100%/1.6 Baskerville, Palatino, serif;
  9. }
  10. @keyframes ants { to { background-position: 100% 100% } }

border-image原理:九宫格伸缩发:把图片切割成九块,然后把它们应用到元素边框相应的边和角。

原理体验:border-image

脚注

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

由于后面特别多,就不一一列举了展示图片了,感兴趣的去看源码及效果吧。

形状

  1. 自适应的椭圆:ellipse
  1. border-radius: 50%;

若是宽高一致,就显示为一个圆,宽高不等,就显示一个椭圆。

若border-radius值为宽高小的一边,就表现为小的边为半圆,长的边为直线。

可单独制定水平和垂直半径:用 / 分隔值即可。border-radius: 100px / 75px

  1. 半椭圆:half-ellipse
  1. border-radius: 50% / 100% 100% 0 0;
  • 垂直堆成,左上角和右上角半径相同,且半径之和等于整个形状的宽度。
  • 顶部的两个圆角占据了整个元素的高度,底部没有任何圆角。
  1. 四分之一椭圆:quarter-ellipse
  1. border-radius: 100% 0 0 0;
  1. 平行四边形:主要利用 transform:skew()变形:parallelograms

嵌套方案:外层skew变形,但内容变形了,对内容再应用一次反向的 skew() 变形,从而抵消容器的变形。

  1. <a class="button"><div>click me</div></a>
  2. .button { transform: skewX(-45deg); }
  3. .button > div { transform: skewX(45deg); }

伪元素方案:parallelograms-pseudo

  1. 菱形图片

嵌套变形方案:diamond-images

  1. <div class="pic">
  2. <img src=""adam-catlace.jpg alt="..."/>
  3. </div>
  4. .pic {
  5. width: 400px;
  6. transform: rotate(45deg);
  7. overflow: hidden;
  8. }
  9. .pic > img {
  10. max-width: 100%;
  11. transform: rotate(-45deg) scale(1.42);
  12. }

裁切路径方案:diamond-clip

  1. .img {
  2. clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
  3. transition: 1s clip-path;
  4. }
  5. .img:hover {
  6. clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  7. }
  1. 切角效果

一个角

  1. background: #58a;
  2. background: linear-gradient(-45deg, transparent 15px, #58a 0);

二个角

  1. background: #58a;
  2. background: linear-gradient(-45deg, transparent 15px, #655 0) right,
  3. linear-gradient(45deg, transparent 15px, #58a 0) left;
  4. background-size: 50% 100%;
  5. background-repeat: no-repeat;

四个角: bevel-corners-gradients

  1. background: #58a;
  2. background: linear-gradient(135deg, transparent 15px, #58a 0) top left,
  3. linear-gradient(-135deg, transparent 15px, #58a 0) top right,
  4. linear-gradient(-45deg, transparent 15px, #58a 0) bottom right,
  5. linear-gradient(45deg, transparent 15px, #58a 0) bottom left;
  6. background-size: 50% 50%;
  7. background-repeat: no-repeat;
  8. // scss mixin
  9. @mixin beveled-corners ($bg, $tl:0, $tr:$tl, $br:$tl, $bl:$tr) {
  10. background: $bg;
  11. background: linear-gradient(135deg, transparent $tl, $bg 0) top left,
  12. linear-gradient(225deg, transparent $tr, $bg 0) top right,
  13. linear-gradient(-45deg, transparent $br, $bg 0) bottom right,
  14. linear-gradient(45deg, transparent $bl, $bg 0) bottom left;
  15. background-size: 50% 50%;
  16. background-repeat: no-repeat;
  17. }
  18. // 调用
  19. @include beveled-corners(#58a, 15px, 5px);

弧形切角(内凹圆角):用径向渐变替代上述线性渐变。scoop-corners

  1. background: #58a;
  2. background: radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
  3. radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
  4. radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right,
  5. radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left;
  6. background-size: 50% 50%;
  7. background-repeat: no-repeat;
  8. // scss mixin
  9. @mixin scoop-corners($bg, $tl:0, $tr:$tl, $br:&tl, $bl:$tr) {
  10. background: $bg;
  11. background: radial-gradient(circle at top left, transparent $tl, #58a 0) top left,
  12. radial-gradient(circle at top right, transparent $tr, #58a 0) top right,
  13. radial-gradient(circle at bottom right, transparent $br, #58a 0) bottom right,
  14. radial-gradient(circle at bottom left, transparent $bl, #58a 0) bottom left;
  15. background-size: 50% 50%;
  16. background-repeat: no-repeat;
  17. }
  18. // 调用
  19. @include scoop-corners();

内联 svg 与 border-image 方案:bevel-corners

  1. border: 20px solid #58a;
  2. border-image: 1 url('data:image/svg+xml,\
  3. <svg xmlns="http://www.w3.org/2000/svg"\
  4. width="3" height="3" fill="%2358a">\
  5. <polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"/>\
  6. </svg>');
  7. background: #58a;
  8. background-clip: padding-box;

裁切路径方案:好处:可使用任意类型的背景,比如图片。bevel-corners-clipped

  1. background: #58a;
  2. clip-path: polygon(
  3. 20px 0, calc(100% - 20px) 0, 100% 20px,
  4. 100% calc(100% - 20px), calc(100% - 20px) 100%,
  5. 20px 100%, 0 calc(100% - 20px), 0 20px);
  1. 梯形标签页

利用 3D 旋转模拟实现:trapezoid-tabs

  1. nav > a {
  2. position: relative;
  3. display: inline-block;
  4. padding: .3em 1em 0;
  5. }
  6. nav > a::before {
  7. content: ''; /* 用伪元素来生成一个矩形 */
  8. position: absolute;
  9. top: 0; right: 0; bottom: 0; left: 0;
  10. z-index: -1;
  11. background #ccc;
  12. transform: perspective(.5em) rotateX(5deg);
  13. transform-origin: bottom;
  14. background-image: linear-gradient(hsla(0, 0%, 100%, .6), hsla(0, 0%, 100%, 0));
  15. border: 1px solid rgba(0, 0, 0, .4);
  16. border-bottom: none;
  17. box-shadow: 0 .15em white inset;
  18. }

对元素使用了 3D 变形之后,其内部的变形效应是“不可逆转”的。但 2D 变形,内部是可抵消外部的变形效应。

该方案优点:能添加背景、边框、圆角、投影灯,并且,只需要把 transform-origin 改成 bottom left 或 bottom right,就可以立即得到左侧倾斜或右侧倾斜的标签页。

  1. 简单的饼图

基于 transform 的解决方案:pie-animated

该方案结构最简:只需一个元素作为容器,其他部分由伪元素、变形属性和css渐变实现。

  1. @keyframes spin {
  2. to { transform: rotate(.5turn); }
  3. }
  4. @keyframes bg {
  5. 50% { background: #655; }
  6. }
  7. .pie {
  8. width: 100px;
  9. height: 100px;
  10. border-radius: 50%;
  11. background: yellowgreen;
  12. }
  13. .pie::before {
  14. content: '';
  15. display: block;
  16. margin-left: 50%;
  17. height: 100%;
  18. border-radius: 0 100% 100% 0 / 50%;
  19. background-color: inherit;
  20. transfrom-origin: left;
  21. animation: spin 3s linear infinite,
  22. bg 6s step-end infinite;
  23. }

制作多个不同比率的静态饼图:pie-static

  1. <div class="pie">20%</div>
  2. <div class="pie">60%</div>
  3. @keyframes spin {
  4. to { transform: rotate(.5turn); }
  5. }
  6. @keyframes bg {
  7. 50% { background: #655; }
  8. }
  9. .pie {
  10. position: relative;
  11. width: 100px;
  12. line-height: 100px; // line-height 本身就可以起到设置高度的作用
  13. border-radius: 50%;
  14. background: yellowgreen;
  15. background-image: linear-gradient(to right, transparent 50%, #655 0);
  16. color: transparent;
  17. text-align: cener;
  18. }
  19. .pie::before {
  20. content: '';
  21. position: absolute;
  22. top: 0; left: 0;
  23. width: 100%;
  24. height: 100%;
  25. border-radius: 0 100% 100% 0 / 50%;
  26. background-color: inherit;
  27. transfrom-origin: left;
  28. animation: spin 3s linear infinite,
  29. bg 6s step-end infinite;
  30. animation-play-state: paused;
  31. animation-delay: inherit;
  32. }
  33. document.querySelectorAll('.pie').forEach(function (pie) {
  34. var p = parseFloat(pie.textContent);
  35. pie.style.animationDelay = '-' + p + 's';
  36. })

动画暂停,用负的动画延时(animation-delay: -20s)来直接跳至动画中的任意时间点。

.pie 元素内联样式,伪元素继承 inherit

svg 解决方案:pie-svg

  1. <svg viewBox="0 0 32 32">
  2. <circle r="16" cx="16" cy="16" />
  3. </svg>
  4. // css
  5. svg {
  6. width: 100px;
  7. height: 100px;
  8. transform: rotate(-90deg);
  9. background: yellowgreen;
  10. border-radius: 50%;
  11. }
  12. svg > circle {
  13. fill: yellowgreen;
  14. stroke: #655;
  15. stroke-width: 32;
  16. stroke-dasharray: 38 100; /* 可得到比率为38%的扇区 */
  17. }

视觉效果

  1. 单侧投影:shadow-one-side
  1. box-shadow: 0 5px 4px -4px black;

box-shadow 第四个长度参数,扩张半径,排在模糊半径参数之后,这个参数会根据你指定的值去扩大或缩小(负值)投影的尺寸。应用一个负的扩张半径,而它的值刚好等于模糊半径,那么投影的尺寸就会与投影所属元素的尺寸完全一致。

  1. 邻边投影:shadow-2-sides
  1. box-shadow: 3px 3px 6px -3px black;
  1. 双侧投影:shadow-opposite-sides
  1. box-shadow: 5px 0 5px -5px black,
  2. -5px 0 5px -5px black;
  1. 不规则投影:drop-shadow
  1. filter: drop-shadow(2px 2px 10px rgba(0, 0, 0, .5));

能与点状、虚线、半透明边框、切角、折角等不规则的形状贴合。

可参考文章:CSS3 filter:drop-shadow滤镜与box-shadow区别应用

  1. 染色效果

滤镜方案:color-tint-filter

  1. img {
  2. transition: .5s filter;
  3. filter: sepia(1) saturate(4) hue-rotate(295deg);
  4. }
  5. img:hover,
  6. img:focus {
  7. filter: none;
  8. }

sepia():给图片增加一种降饱和度的橙黄色染色效果。几乎所有像素的色相值会被收敛到35-40.

saturate():给每个像素提升饱和度

hue-rotate():把每个像素的色相以指定的度数进行偏移。

混合模式方案:color-tint

  1. <a>
  2. <img src="tiger.jpg"/>
  3. </a>
  4. a { background: hsl(335, 100%, 50%); }
  5. a > img { mix-blend-mode: luminosity; }

当两个元素叠加时,“混合模式”控制了上层元素的颜色与下层颜色进行混合的方式。

luminosity:会保留上层元素的 hsl 亮度信息,并从它的下层吸取色相和饱和度信息。

染色:下层放主色调,上层设置 luminosity 混合模式。

mix-blend-mode:为整个元素设置混合模式

background-blend-mode:为每层背景单独制定混合模式。

  1. 毛玻璃效果:frosted-glass
  1. body, main::before {
  2. background: url('tigger.jpg') 0 / cover fixed;
  3. }
  4. main {
  5. position: relative;
  6. backgrond: hsla(0, 0%, 100%, .3);
  7. overflow: hidden;
  8. }
  9. main::before {
  10. content: '';
  11. position: absolute;
  12. top: 0; right: 0; bottom: 0; left: 0;
  13. filter: blur(20px);
  14. margin: -30px;
  15. }

由于不能直接对元素本身设置模糊效果,就对一个伪元素进行处理,然后将其定位宿主到元素的下层,它的背景将会无缝匹配 的背景。

模糊效果会削减实色像素所能覆盖的范围,削减的幅度正是模糊半径的长度。因此让伪元素相对宿主元素的尺寸向外夸大至少20px

  1. 折角效果

45° 折角的解决方案:folded-corner

  1. background: #58a; /* 回退样式 */
  2. background: linear-gradient(to left bottom, transparent 50%, rgba(0, 0, 0, .4) 0) no-repeat 100% 0 / 2em 2em, linear-gradient(-135deg, transparent 1.5em, #58a 0);

其他角度解决方案:

folded-corner-realistic

folded-corner-mixin

  1. .note {
  2. positon: relative;
  3. background: #58a;
  4. background: linear(-150deg, transparent 1.5em, #58a 0);
  5. border-radius: .5em;
  6. }
  7. .note::before {
  8. content: '';
  9. position: absolute;
  10. top: 0;
  11. right: 0;
  12. background: linear-gradient(to left bottom, transparent 50%, rgba(0, 0, 0, .2) 0, rgba(0, 0, 0, .4)) 100% no-repeat;
  13. width: 1.73em;
  14. height: 3em;
  15. transform: translateY(-1.3em) rotate(-30deg);
  16. transform-origin: bottom right;
  17. border-bottom-left-radius: inheirt;
  18. box-shadow: -.2em .2em .3em -.1em rgba(0, 0, 0, .15);
  19. }
  20. // scss mixin
  21. @mixin folded-corner($bg, $size, $angle:30deg) {
  22. positon: relative;
  23. background: $bg;
  24. background: linear($angle - 180deg, transparent $size, $bg 0);
  25. border-radius: .5em;
  26. $x: $size / sin($angle);
  27. $y: $size / cos($angle);
  28. &::before {
  29. content: '';
  30. position: absolute;
  31. top: 0;
  32. right: 0;
  33. background: linear-gradient(to left bottom, transparent 50%, rgba(0, 0, 0, .2) 0, rgba(0, 0, 0, .4)) 100% no-repeat;
  34. width: $y;
  35. height: $x;
  36. transform: translateY($y - $x) rotate(2*$angle - 90deg);
  37. transform-origin: bottom right;
  38. border-bottom-left-radius: inheirt;
  39. box-shadow: -.2em .2em .3em -.1em rgba(0, 0, 0, .15);
  40. }
  41. }
  42. // 调用
  43. .note {
  44. @include folded-corner(#58a, 2em, 40deg);
  45. }

字体排印

  1. 连字符断行:hyphenation
  1. text-align: justify;
  2. hyphens: auto;

两端对齐,英文,有些单词之间的间隔太大,损伤了可读性。实际中,两端对齐总是与连字符断行相辅相成。

文本折行算法:主要是 贪婪算法 和 Knuth-Plass 算法。

贪婪算法:每次分析一行,把尽可能多的单词填充改行,当遇到第一个装不下的单词或音节时,就移至下一行继续处理。

Knuth-Plass 算法:高级很多,把整段文本纳入考虑范围,从而产生出美学上更令人愉悦的效果。但计算性能稍差。

绝大多数桌面文字处理程序采用 Knuth-Plass 算法,处于性能考虑,浏览器采用 贪婪算法。

  1. 插入换行:line-breaks
  1. <dl>
  2. <dt>Name:</dt>
  3. <dd>Lea Verou</dd>
  4. <dt>Email:</dt>
  5. <dd>Lea@verou.me</dd>
  6. <dd>Leaverou@mit.edu</dd>
  7. <dt>Location:</dt>
  8. <dd>Earth</dd>
  9. </dl>

dt,dd 块级元素。

在每个 dd 后面添加一个 br 换行,糟糕的结构。使用生成性内容来添加换行,并以此取代br。

有一个 Unicode 字符专门代表换行:0x000A,在 css 中这个字符可以写作 "\000A",或简化为"\A"

在 html 直接输入换行符,会与响铃的其他空白符合并。保留空白和换行,white-space: pre

  1. dt, dd { display: inline; }
  2. dd {
  3. margin: 0;
  4. font-weight: bold;
  5. }
  6. dd + dt::before {
  7. content: '\A';
  8. white-space: pre;
  9. }
  10. dd + dd::before {
  11. content: ',';
  12. margin-left: -.2em;
  13. font-weight: normal;
  14. }
  1. 文本行的斑马条纹:zebra-lines

表格

  1. tr: nth-child(even) {
  2. background: rgba(0, 0, 0, .2);
  3. }

文本:渐变背景条纹

  1. padding: .5em;
  2. line-height: 1.5;
  3. background: beige;
  4. background: auto 3em;
  5. background-origin: content-box;
  6. background-image: linear-gradient(rgba(0, 0, 0, .2) 50%, transparent 0);

background-size 设置为 line-height 的两倍,每个背景贴片需要覆盖两行代码。

  1. 调整 tab 的宽度:tab-size

使用 pre 和 code 显示代码,tab 缩进代码,浏览器会把其宽度显示为 8 个字符。

  1. pre { tab-size: 2; }
  1. 连字:ligatures

大多数衬线字体中的 f 和 i ,i 的圆点往往会与 f 的升部发生冲突,导致两者显示不清。为了缓解这种情况,出现连字。设计成 双字形或三字形的单一组合体。

  1. font-variant-ligaturescommon-ligatures
  2. discretionary-ligatures
  3. historical-ligatures;

开启通用连字,关闭酌情连字

  1. font-variant-ligatures: common-ligatures
  2. no-discretionary-ligatures
  3. no-historical-ligatures;
  1. 华丽的 & 符号:ampersands

  2. 自定义下划线:

underlines

wavy-underlines

  1. background: linear-gradient(gray, gray) no-repeat;
  2. background-size: 100% 1px;
  3. background-origin: 0 1.15em;
  4. text-shadow: .05em 0 white, -.05em 0 white;
  1. 现实中的文字效果

凸版印刷效果:letterpress

  1. background: hsl(210, 13%, 40%);
  2. color: hsl(210, 13%, 75%);
  3. text-shadow: 0 -1px 1px black;

原理:出现在底部的浅色投影或出现在顶部的暗色投影,会让人产生物体时凹进平面内的错觉;同理,出现在底部的暗色投影或出现在顶部的浅色投影,会让人产生物体从平面上凸起的错觉。

形成错觉的原因:现实世界中光源总是悬在头顶。

空心字效果:stroked-text

  1. background: deeppink;
  2. color: white;
  3. text-shadow: 1px 1px black, -1px -1px black,
  4. 1px -1px black, -1px 1px black;

文字外发光效果:glow

  1. a {
  2. background: #203;
  3. color: white;
  4. transition: 1s;
  5. }
  6. a:hover {
  7. color: transparent;
  8. text-shadow: 0 0 .1em white, 0 0 .3em white;
  9. }
  10. // 或
  11. a:hover {
  12. filter: blur(.1em);
  13. }

文字凸起效果:extruded

  1. background: #58a;
  2. color: white;
  3. text-shadow: 0 1px hsl(0, 0%, 85%),
  4. 0 2px hsl(0, 0%, 80%),
  5. 0 3px hsl(0, 0%, 75%),
  6. 0 4px hsl(0, 0%, 70%),
  7. 0 5px hsl(0, 0%, 65%),
  8. 0 5px 10px black;
  9. // scss mixin
  10. @mixin text-3d($color:white, $depth: 5) {
  11. $shadows: ();
  12. $shadow-color: $color;
  13. @for $i from 1 through $depth {
  14. $shadow-color: darken($shadow-color, 10%);
  15. $shadow: append($shadows, 0 ($i * 1px) $shadow-color, comma);
  16. }
  17. color: $color;
  18. text-shadow: append($shadows, 0 ($depth * 1px) 10px black, comma);
  19. }
  20. h1 { @include text-3d(#eee, 4)};

环形文字-svg:circular-text

用户体验

  1. 选用合适的鼠标光标
  1. cursor: not-allowed; // 禁用
  1. 扩大可点击区域:hit-area-border
  1. border: 10px solid transparent;
  2. box-shadow: 0 0 0 1px rgba(0, 0, 0. .3) inset;
  3. background-clip: padding-box;

伪元素实现:伪元素可以代表其宿主元素来响应鼠标交互。hit-area

  1. button {
  2. position: relative;
  3. }
  4. button::before {
  5. content: '';
  6. position: absolute;
  7. top: -10px; right: -10px;
  8. bottom: -10px; left: -10px;
  9. }
  1. 自定义复选框:checkboxes

:checked,改伪类只在复选框被勾选时才匹配,不论这个勾选状态是由用户交互触发,还是脚本触发。

借助组合选择符来给其他元素设置样式。当 label 元素与复选框关联之后,也可以起到触发开关的作用。

  1. <input type="checkbox" id="awesome"/>
  2. <label for="awesome">Awesome</label>
  3. input[type="checkbox"] + label::before {
  4. content: '\a0'; /* 不换行空格 */
  5. display: inline-block;
  6. vertical-align: .2em;
  7. width .8em;
  8. height: .8em;
  9. margin-right: .2em;
  10. border-radius: .2em;
  11. background: silver;
  12. text-indent: .15em;
  13. line-height: .65;
  14. }
  15. input[type="checkbox"]:checked + label::before {
  16. content: '\2713';
  17. background: yellowgreen;
  18. }
  19. // 不损失可访问性的方式隐藏,不能使用display:none,会把它从键盘tab键切换焦点的队列中完全删除
  20. input[type="checkbox"] {
  21. position: absolute;
  22. clip: rect(0, 0, 0, 0);
  23. }
  24. input[type="checkbox"]:focus + label::before {
  25. box-shadow: 0 0 .1em .1em #58a;
  26. }
  27. input[type="checkbox"]:disabled + label::before {
  28. background: gray;
  29. box-shadow: none;
  30. color: #555;
  31. }

结构与布局

  1. 自适应内部元素:intrinsic-sizing
  1. <p>Some text [...]</p>
  2. <figure>
  3. <img src="adamcatlace.jpg" />
  4. <figcaption>
  5. The great Sir Adam Catlace was named after Countess Ada Lovelace, the first programmer.
  6. </figcaption>
  7. </figure>
  8. <p>More text [...]</p>

希望这个 figure 元素能跟 它所包含的图片一样框,而且水平居中。

  1. figure {
  2. max-width: 300px; /* 回退 */
  3. max-width: min-content;
  4. margin: auto;
  5. }
  6. figure > img {
  7. max-width: inherit;
  8. }

min-content: 解析为这个容器内部最大的不可断行元素的宽度(即最宽的单词、图片或具有固定宽度的盒元素)

  1. 精确控制表格列宽
  1. table {
  2. table-layout: fixed;
  3. width: 100%;
  4. }
  1. 根据兄弟元素的数量来设置样式:styling-sibling-count

通过兄弟元素的总数设置样式

  1. li:only-child {
  2. /* 只有一个列表项是的样式 */
  3. }
  1. li:first-child:nth-last-child(1) {
  2. /* 相当于li:only-child,第一项同时是最后一项 */
  3. }
  1. li:first-child:nth-last-child(4) {
  2. /* 这个元素是父元素的第一个子元素,同时是从后往前数的第四个子元素,即命中一个正好有四个列表项的第一个列表项 */
  3. }
  1. li:first-child:nth-last-child(4),
  2. li:first-child:nth-last-child(4) ~ li {
  3. /* 当列表正好是四项时,命中所有列表项 */
  4. }

根据兄弟元素的数量范围来匹配元素

  1. li:nth-child(n+b) {
  2. /* n+b, n从0开始,选中从b个元素开始的所有子元素*/
  3. }
  1. li:nth-child(n+4) {
  2. /* 选中除了第1、第2、第3个子元素之外的所有子元素 */
  3. }
  1. li:first-child:nth-last-child(n+4),
  2. li:first-child:nth-last-child(n+4) ~ li {
  3. /* 当列表至少包含四项时,命中所有列表项 */
  4. }

-n+b:可以选中开头的b个元素,当列表中有4个或更少的列表项时:

  1. li:first-child:nth-last-child(-n+4),
  2. li:first-child:nth-last-child(-n+4) ~ li {
  3. /* 当列表最多包含四项时,命中所有列表项 */
  4. }
  1. li:first-child:nth-last-child(n+2):nth-last-child(-n+6),
  2. li:first-child:nth-last-child(n+2):nth-last-child(-n+6) ~ li {
  3. /* 当列表包含2-6项时,命中所有列表项 */
  4. }

实际应用篇:伪类匹配列表数目实现微信群头像CSS布局的技巧

  1. 满幅的背景,定宽的内容:fluid-fixed

定宽内容居中,正常写法

  1. <footer>
  2. <div class="wrap">内容</div>
  3. </footer>
  4. footer { background: #333; }
  5. .wrap {
  6. max-width: 900px;
  7. margin: 1em auto;
  8. }

一层实现:

  1. footer {
  2. padding: 1em; /* 回退 */
  3. padding: 1em calc(50% - 450px);
  4. background: #333
  5. }
  1. 垂直居中

绝对定位方案:

  1. main {
  2. position: absolute;
  3. top: 50%;
  4. left: 50%;
  5. transform: translate(-50%, -50%);
  6. }

弹性盒子方案:

  1. body {
  2. display: flex;
  3. min-height: 100vh;
  4. margin: 0;
  5. }
  6. main { /* 水平垂直居中 */
  7. margin: auto;
  8. }
  1. main {
  2. display: flex;
  3. align-items: center;
  4. justify-content: center;
  5. width: 18em;
  6. height: 10em;
  7. }
  1. 紧贴底部的页脚

块级页脚,页面内容足够长在页面底部,页面内容很少,需要紧贴在视口底部。

固定高度的方案:sticky-footer-fixed

  1. main {
  2. min-height: calc(100vh - 7em)
  3. }

更灵活的方案:sticky-footer

  1. body {
  2. display: flex;
  3. flex-flow: column;
  4. min-height: 100vh;
  5. }
  6. main { flex: 1; }

过渡与动画

  1. 缓动效果:具有回弹效果,利用贝塞尔曲线:bounce

ease-out 是 ease-in 的反向版本。

cubic-bezier(x1, y1, x2, y2),把控制锚点的水平坐标和垂直坐标互换,就可以得到任何调速函数的反向版本。

cubic-bezier 图形化工具

  1. @keyframes bounce {
  2. 60%, 80%, to {
  3. transform: translateY(400px);
  4. animation-timing-function: ease;
  5. }
  6. 70% { transform: translateY(300px); }
  7. 90% { transform: translateY(360px); }
  8. }
  9. .ball {
  10. animation: bounce 3s cubic-bezier(.1, .25, 1 ,.25);
  11. }
  1. 逐帧动画:steps():frame-by-frame
  1. @keyframes loader {
  2. to { background-position: -800px 0; }
  3. }
  4. .loader {
  5. width: 100px;
  6. height: 100px;
  7. background: url(img/loader.png) 0 0;
  8. animation: loader 1s infinite steps(8);
  9. }

steps() 会根据你指定的步数进量,把整个动画切分为多帧,而且每个动画会在帧与帧之间硬切。

关于steps:CSS3 animation属性中的steps功能符深入介绍

  1. 打字效果:typing

ch 单位:表示“0”字形的宽度。在等宽字体中,“0”字形的宽度和其他所有字形的宽度一致。用 ch 单位表示宽度,那取值实际上就是字符的数量。

  1. @keyframes typing {
  2. from { width: 0; }
  3. }
  4. @keyframes caret {
  5. 50% { border-color: transparent; }
  6. }
  7. h1 {
  8. width: 15ch; /* 文本的宽度 */
  9. overflow: hidden;
  10. white-space: nowrap;
  11. border-right: .5em solid;
  12. animation: typing 6s steps(15),
  13. caret 1s steps(1) infinite;
  14. }
  15. document.querySelectAll('h1').forEach(function (h1) {
  16. var len = h1.textContent.length, s = h1.style;
  17. s.width = len + 'ch';
  18. s.animationTimingFunction = "steps("+len+"), steps(1)";
  19. })
  1. 状态平滑的动画:动画暂停、开启,state-animations
  1. @keyframes panoramic {
  2. to { background-position: 100% 0; }
  3. }
  4. .panoramic {
  5. width: 150px;
  6. height: 150px;
  7. background: url(img/naxos-greece.jpg);
  8. background-size: auto 100%;
  9. animation: panoramic 10s linear infnte alternate;
  10. animation-play-state: paused;
  11. }
  12. .panoramic:hover, .panoramic:focus {
  13. animation-play-state: running;
  14. }

整张图片从左滚蛋到右侧。

  1. 沿环形路径平移的动画:circular

沿着环形进行移动,同时保持自己本来的朝向。

每个transform-origin都是可以被两个translate()模拟出来的。下面两段代码是等效的。

  1. transform: rotate(30deg);
  2. transform-origin: 200px 300px;
  3. transform: translate(200px, 300px) rotate(30deg) translate(-200px, -300px);
  4. transform-origin: 0 0;

牢记变形函数并不是彼此独立的。每个变形函数并不是只对这个元素进行变形,而是会把整个元素的坐标系统进行变形,从而影响后面的变形操作。这也说明了为什么变形函数的顺序是很重要的。

  1. @keyframes spin {
  2. from {
  3. transform: translateY(150deg) translateY(-50%)
  4. rotate(0turn)
  5. translateY(-150deg) translateY(50%)
  6. rotate(1turn);
  7. }
  8. to {
  9. transform: translateY(150deg) translateY(-50%)
  10. rotate(1turn)
  11. translateY(-150deg) translateY(50%)
  12. rotate(0turn);
  13. }
  14. }
  15. .avatar { animation: spin 3s infinite linear; }

最后

书中记录的这些效果,都有很详细的启发作用,每个案例都敲一遍,理解了感觉css真的有魔力呢。

向该书的作者致敬,表示感谢。

css 揭秘-读书笔记的更多相关文章

  1. CSS揭秘读书笔记 (一)

    CSS揭秘读书笔记      (一) 一.半透明边框 要想实现半透明边框可以使用border: border: 10px  solid  hsla(0,0%,100%,.5); background: ...

  2. css揭秘读书笔记

    currentColor属性让hr和段落相同的颜色: div { color: red; } hr { background: currentColor; /* 一定要设置高度*/ height: 0 ...

  3. 《CSS揭秘》笔记(一)

    前言 我们在现代 CSS 中所面临的挑战已经不在于如何绕过这些转瞬即逝的浏览器 bug.如今的挑战是,在保证 DRY ① .可维护.灵活性.轻量级并且尽可能符合标准的前提下,把我们手中的这些CSS特性 ...

  4. Spring揭秘 读书笔记 三 bean的scope与FactoryBean

    本书可作为王富强所著<<Spring揭秘>>一书的读书笔记  第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...

  5. spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...

  6. spring揭秘 读书笔记 一 IoC初探

    本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...

  7. 《精通CSS》读书笔记(一)

    最近新添16本书,目前开始看陈剑瓯翻译的<精通CSS——高级Web标准解决方案>(Andy Budd, CSS Mastery -- Advanced Web Standards Solu ...

  8. spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...

  9. 《Two Days DIV + CSS》读书笔记——CSS选择器

    1.1.2 CSS选择器 CSS 选择器最基本的有四种:标签选择器.ID 选择器.类选择器.通用选择器. [标签选择器] 一个完整的 HTML 页面由很多不同的标签组成,而标签选择器,则是决定哪些标签 ...

随机推荐

  1. 花生日记_花生日记APP下载_花生日记官方网站

    花生日记 国内领先的社交电商导购分享平台. 独创社交电商3+模式,社交+电商+社群,上线1个月注册用户超百万.合作商家涵括各个类目以及平台.为数万宝妈提供月收入3000以上兼职收入. 微信扫描下方二维 ...

  2. ES6对数组的扩展(简要总结)

    文章目录 数组的扩展(ES6) 1. 扩展运算符 2. Array.from 3. Array.of() 4. copyWithin() 5. find() 和 findIndex() 6. fill ...

  3. python多线程编程—同步原语入门(锁Lock、信号量(Bounded)Semaphore)

    摘录python核心编程 一般的,多线程代码中,总有一些特定的函数或者代码块不希望(或不应该)被多个线程同时执行(比如两个线程运行的顺序发生变化,就可能造成代码的执行轨迹或者行为不相同,或者产生不一致 ...

  4. Mysql基于Mysql Cluster+MysqlRouter的集群部署方案

    http://note.youdao.com/noteshare?id=a61c4a6ff2b76e5305430eb66eb116e2&sub=4B4B6E8D0E2849F9B0DFB67 ...

  5. iOS 13 presentViewController

    升级了iOS 13,发现代码中使用presentViewController的都变成了这样的,顶部留了一部分 查看present样式,iOS 13 默认自动适配,需要在present的时候,设置sty ...

  6. windows10 双系统安装后,grub2 引导修复(亲自实验);grub2 命令行 手动加载内核;fedora 29 系统grub2引导修复;

    之前在本机有fedora 29的系统,但是由于错误安装,把windows10 启动安装到 linux 所在的硬盘中,导致原来的 efi中的grub启动被破坏,不能进入到linux中:我首先通过磁盘精灵 ...

  7. 阿里巴巴Java开发手册正确学习姿势是怎样的?刷新代码规范认知

    很多人都知道,阿里巴巴在2017发布了<阿里巴巴Java开发手册>,前后推出了很多个版本,并在后续推出了与之配套的IDEA插件和书籍. 相信很多Java开发都或多或少看过这份手册,这份手册 ...

  8. AST抽象语法树 Javascript版

    在javascript世界中,你可以认为抽象语法树(AST)是最底层. 再往下,就是关于转换和编译的"黑魔法"领域了. 现在,我们拆解一个简单的add函数 function add ...

  9. 05-深入python的set和dict

    一.深入python的set和dict 1.1.dict的abc继承关系 from collections.abc import Mapping,MutableMapping #dict属于mappi ...

  10. eclipse中js中文乱码问题的解决办法

    在Eclipse中编辑JS文件简直是一种折磨,但是却总是很无奈得要去适应. 这里说一下Eclipse中,编辑JS文件时候,出现中文乱码问题的解决办法. 这个问题很容易想到是文件编码的问题,因此通常是修 ...