CSS揭秘-读书笔记

CSS如今面临的挑战是:在保证DRY、可维护、灵活性、轻量级并且尽可能符合标准的前提下,把我们手中的这些css特性转化为网页中的各种创意。(作者为W3C特邀专家,强调 CSS 代码的 DRY 原则是一个贯穿本书的主题,提供了很多css技巧)

DRY是Don't Repeat Yourself 的首字母缩写,意思是不应该重复已经做过的事。是一种变成理念,旨在提升代码某方面的可维护性。改变某个参数时,只改尽量少的地方,最好是一处

CSS编码技巧

尽量少的代码重复

1
2
3
4
5
6
7
8
9
10
11
button{
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;
}

例如: 上面是一个按钮的样式,字体大小和行高为固定的值

问题1: 想要改变字体大小时,为了垂直居中,line-height也要重新赋值

解决: 可以将行高按照字体大小的比例写(不给固定值)

1
2
font-size: 20px;
line-height: 1.5;

问题2:当改变父级字体大小时,不得不修改每一处使用绝对值的样式;

解决:使用em ,rem , 百分比;

假设html的font-size:16px;

那么可以改写为:

1
2
3
4
5
6
7
8
9
10
11
button{
padding: .375rem 1rem;
border: .0625rem solid #446d88;
background: #58a linear-gradient(#77a0bb, #58a);
border-radius: .25rem;
box-shadow: 0 .0625rem .3125rem gray;
color: white;
text-shadow: 0 -0.0625rem .0625rem #335166;
font-size: 1.25rem;
line-height: 1.5;
}

问题3:改变按钮颜色时,根据上面的样式需要改变background、box-shadow、text-show;

解决:把半透明的黑色或白色叠加在主色调上;

1
2
3
4
5
6
7
8
9
10
11
button{
padding: .375rem 1rem;
border: .0625rem solid rgba(0, 0, 0, .1);
background: #58a linear-gradient(hsla(0,0%,100%,.2), transparent);
border-radius: .25rem;
box-shadow: 0 .0625rem .3125rem rgba(0, 0, 0, .5);
color: white;
text-shadow: 0 -0.0625rem .0625rem rgba(0, 0, 0, .5);
font-size: 1.25rem;
line-height: 1.5;
}

这样只需要覆盖background-color就可以了

1
2
3
4
5
6
button.cancel{
background-color:#c00 ;
}
button.ok{
background-color: #6b0;
}
1. currentColor : 表示“当前的标签所继承的文字颜色”

例如:想让所有hr自动与文本颜色保持一致

1
2
3
4
hr {
height: .5em;
background: currentColor;
}
2.inherit : 继承父级样式(伪元素则为宿主元素)

人类视觉偏差: 需要做些调整

  • 一个完全垂直居中的物体,视觉上可能并不居中,可以将中心点向上挪;
  • 圆形字,例如0与矩形字相比,显得小一些,需要稍微放大;
  • 这些视觉上的错觉在任何形式的视觉设计中都普遍存在,需要做些调整;

关于响应式网页设计的一些建议

在利用媒体查询的同时最好做到以下几点,减小媒体查询成本

  • 使用百分比长度,或使用视口相关的单位(vw,vh,vmin,vmax);
  • 当需要在较大分辨率下得到固定宽度时,使用max-width而不是width;
  • 不要忘记为替换元素(img,video,iframe等),设置一个max-width为100%;
  • 加入背景图片需要完整铺满一个容器,background-size:cover;
  • 当图片或其他元素以行列式进行布局时,推荐使用flexbox或display: inline-block;
  • 使用多列文本时,指定列宽而不是指定列数,这样它就可以在较小的屏幕上自动显示为单列布局;

总的来说,思路是尽最大努力实现弹性可伸缩的布局,并在媒体查询各个断点区间内指定相应的尺寸。

合理使用简写

例如:

1
2
3
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;

可以看到有很多重复的部分,可以改写为:

1
2
3
4
5
background: url(tr.png) top right,
url(br.png) bottom right,
url(bl.png) bottom left;
background-size: 2em 2em;
background-repeat: no-repeat;

现在只需要改一个地方就可以控制size和repeat了

预处理器

小型项目不推荐使用,未来说不定预处理器受欢迎的特性会加入到原生css中

例如:强大的原生css特性

  • calc(): 可以实现计算,例如想要一个100% - 50px的宽度,可以写为:

    1
    width: calc(100% - 50px);

背景与边框

半透明边框

1
2
border: 10px solid hsla(0,0%,100%,.5);
background: white;

给了一个半透明边框,但实际效果看起来却像是与背景色颜色一样的边框

默认情况下,背景会延伸到边框所在的区域下层。并且在半透明边框处透出了白色的背景。

解决: 利用裁剪属性 background-clip

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

这样浏览器会将内边距外沿背景裁切掉。得到半透明边框效果。

多重边框

1.box-shadow方案:

前3个参数为0,第四个参数为狂战半径,可能得到一个像实线的边框,利用text-shadow的逗号分隔语法,可以实现多个投影,即多边框效果;

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

需要注意的是,box-shadow不影响布局,不受box-sizing影响,可以利用内边距或外边距模拟边框所需要占据的空间,inset关键字可以绘制内圈;

2. outline方案: 描边(适用于两层边框)

如果只需要两层边框,可以先写一个常规边框再加上outline属性产生外层边框

1
2
3
background: yellowgreen;
border: 10px solid #655;
outline: 5px solid deeppink;

outline-offset属性可以控制它跟元素边缘之间的间距

局限:

  • 只适用于两层边框
  • 不贴合border-radius圆角(未来有可能改为贴合)
灵活的背景定位
  • background-position属性设置背景定位: 默认以padding box为准;
  • background-origin可以修改偏移以什么为准,backgroun-origin: content-box;以内容区的边缘作为基准
  • calc():不确定宽高的情况下可以使用calc(100% - 20px)写background-position;

边框内圆角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="something-meaningful">
<div>
I have a nice subtle inner rounding,
don't I look pretty?
</div>
</div>
<style>
.something-meaningful {
background: #655;
padding: .8em;
}
.something-meaningful > div {
background: tan;
border-radius: .8em;
padding: 1em;
}
</style>

如上:内部有圆角外层无圆角,但用了两个元素,怎么只用一个元素实现同样的效果呢

  • 可以利用outline不受border-radius影响来做,利用box-shadow填充outline与圆角之间的缝隙;
1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="something-meaningful">
I have a nice subtle inner rounding,
don't I look pretty?
</div>
<style>
.something-meaningful{
background: tan;
border-radius: .8em;
padding: 1em;
box-shadow: 0 0 0 .6em #655;
outline: .6em solid #655;
}
</style>

条纹背景

横向条纹

如上利用背景属性实现实色条纹,默认repeat所以铺满了

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

不等宽

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

多色条纹

1
2
3
background: linear-gradient(#fb3 33.3%,
#58a 0, #58a 66.6%, yellowgreen 0);
background-size: 100% 45px;
纵向条纹

与横向一样 只不过增加一个参数指定渐变方向,linear-gradient默认to right,background-size值也置换一下。

1
2
3
background: linear-gradient(to right, /* 或 90deg */
#fb3 50%, #58a 0);
background-size: 30px 100%;
斜向条纹
1
2
3
4
background: linear-gradient(45deg,
#fb3 25%, #58a 0, #58a 50%,
#fb3 0, #fb3 75%, #58a 0);
background-size: 42.426406871px 42.426406871px;

为什么是42.426406871px(勾股定理)

如果宽度为15px那么:2 1× ≈ 5 2 42.426 406 871 像素

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

还是推荐使用透明度而不是固定的同色系颜色

随机排列的条纹

上面都是某个固定的宽repeat出来的,所以是很规律的,如何实现不规律的条纹。

1
2
3
4
5
6
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%;

还有很多复杂的背景图,有兴趣可以看看(表示我现在看不动)

连续的图像边框

先跳过

形状

自适应的椭圆

1
border-radius: 50%;

正方形会变成圆形,其他矩形则为椭圆

半椭圆

1
2
3
4
5
6
7
8
9
/*纵向上部分的半椭圆*/
border-radius: 50% / 100% 100% 0 0;
/*以上是缩写 等同于下面 两个值分别代表横轴纵轴的圆角length*/
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
border-bottom-right-radius: 50% 0;
border-bottom-left-radius: 50% 0
/*横向左侧部分的半椭圆*/
border-radius: 100% 0 0 100% / 50%;

↑二分之一椭圆

↓四分之一椭圆

1
border-radius: 100% 0 0 0;

平行四边形

transform: skew()

会影响内部元素也出现变形

解决1:嵌套skew内部与外部变形相反

1
2
3
4
5
<a href="#yolo" class="button">
<div>Click me</div>
</a>
.button { transform: skewX(-45deg); }
.button > div { transform: skewX(45deg); }

解决2: 利用伪元素,只让伪元素变形

1
2
3
4
5
6
7
8
9
10
11
12
13
.button {
position: relative;
/* 其他的文字颜色、内边距等样式…… */
}
.button::before {
content: '';
position: absolute;
/*撑满宿主元素*/
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
background: #58a;
transform: skew(45deg);
}

transform的其他属性也适用,例如rotate()

菱形图片

一个容器中放入菱形图片

1
2
3
4
5
6
7
8
9
.picture {
width: 400px;
transform: rotate(45deg);
overflow: hidden;
}
.picture > img {
max-width: 100%;
transform: rotate(-45deg) scale(1.42);
}

结构与布局

自适应

未知宽高的父级元素,子元素左右居中

给父元素加上

1
2
width: min-content;
margin: auto;
满幅背景,定宽内容
  • 常见方法,威哥区块准备两层元素:外层实现满幅背景,内层定宽内容,后者margin: auto实现水平居中
1
2
3
4
5
6
7
8
9
10
11
12
<footer>
<div class="wrapper">
<!-- 页脚的内容写在这里 -->
</div>
</footer>
footer {
background: #333;
}
.wrapper {
max-width: 900px;
margin: 1em auto;
}

利用calc()一个标签

1
2
3
4
5
6
7
8
<footer>
<!-- 页脚的内容写在这里 -->
</footer>
footer {
padding: 1em;
padding: 1em calc(50% - 450px);
background: #333;
}
垂直居中
  • 行内元素text-align:center;
  • 块级元素对他自身margin: auto;

然而实际应用中是个很头痛的事情

1.定位的方式

有固定的宽高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
main {
position: absolute;
top: 50%;
left: 50%;
margin-top: -3em; /* 6/2 = 3 */
margin-left: -9em; /* 18/2 = 9 */
width: 18em;
height: 6em;
}
/*可以改写为*/
main {
position: absolute;
top: calc(50% - 3em);
left: calc(50% -9em);
width: 18em;
height: 6em;
}

未知宽高

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

只适用于视口居中的场景

1
2
3
4
5
6
main {
width: 18em;
padding: 1em 1.5em;
margin: 50vh auto 0;
transform: translateY(-50%);
}
3.最佳解决方案 flexbox
1
2
3
4
5
6
7
body {
display: flex;
min-height: 10 margin: 0;
}
main {
margin: auto;
}
紧贴底部的页脚
1
2
3
4
5
6
7
8
9
10
11
body {
display: flex;
flex-flow: column;
min-height: 100vh;
}
main {
flex: 1;
}
footer: {
height: 10vh;
}

↑ flex方法

↓ 其他方法

1
2
3
4
5
6
7
8
main {
min-height: calc(100vh - 7em);
/* 避免内边距或边框搞乱高度的计算: */
box-sizing: border-box;
}
footer{
height: 7em;
}

过渡与动画

没看完暂时先到这里

------ 本文结束------
0%