【前端读书笔记】 CSS揭秘

316 阅读25分钟

1. CSS 编码的技巧

1.1. 尽量减少代码的重复

1.1.1. 使用代码表现相互关系

例如:

  • 字体尺寸可以用父级字体尺寸的em或者百分比表示
  • 行高可以用字号的倍数表示
  • 长度值可也以用父级字号的em表示

1.1.2. currentColor

currentColor是css的第一个变量

使用举例:让所有的分割线(hr)的颜色自动与文本颜色保存一致:

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

1.1.3. 继承(inherit)

inherit可以用在任何CSs属性中,而且它总是绑定到父元素的计算值(对于伪元素,则会取生成该伪元素的宿主元素) 例如:

  • 设置超链接的颜色与其他文本相同
  • 设置表单元素的字体属性与页面的其他部分相同

2. 背景与边框

2.1. 半透明边框

给容器设置白色背景和半透明边框:

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

但是这样不会看到半透明边框,因为默认情况下,背景会延伸到边框所在的区域下层:

2022-05-15-09-41-10.png

解决方案: 使用background-clip属性来将侵入边框的背景裁剪掉

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

2022-05-15-09-41-51.png

2.2. 多重边框

2.2.1. box-shadow方案

实现原理:

box-shadow接受第四个参数(扩张半径),可以让投影面积加大或者缩小。一个正值的扩张半径加上两个为0的偏移量和为0的模糊值,得到的投影就像是一道实体边框,这是单层边框的原理。 box-shadow支持逗号分隔语法,这意味着可以创建任意数量的投影,这里的应用就是可以创建任意数量的边框。这就是box-shadow实现多重边框的原理

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

2022-05-15-09-55-27.png

注意事项:

  • 投影的行为和边框不完全一致,投影不会影响布局,也不会受到box-sizing的影响
  • 利用box-shadow绘制的边框出现在元素的外圈,不会影响鼠标点击事件。可以给box-shadow属性加上inset关键字,来使投影绘制在元素内圈。

2.2.2. outline方案

outline方案适用于两层边框的情况

使用outline实现上述效果:

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

2022-05-15-10-49-29.png

注意事项:

  • 只适用于两层边框
  • 边框不一定会贴合border-redius属性产生的圆角

2.3. 灵活的背景定位

问题:针对容器的某个角对背景图片做偏移定位,例如右下角

2.3.1. background-position扩展语法方案

background-position允许指定背景图片对任意的边(top,left,right,bottom)进行偏移,只需要在偏移量前面加指定关键字

例如:让背景图片距离底边保持10px距离,距离右边保持20px距离:

    background: url(./car.png) no-repeat skyblue bottom right;
    background-position: right 20px bottom 10px;

2022-05-15-16-02-56.png

2.3.2. background-origin方案

在给背景图片设置距离某个角的偏移量时,有一种情况比较常见,偏移量与容器的内边距一致

使用 3.1. 的方案,代码为:

padding:10px;
background:url(./car.png) no-repeat skyblue;
background-position:right:10px bottom 10px;

这样有效,但是代码不够简洁,每次padding有变,都需要改动三个地方

将background-origin设置为content-box可以解决这个问题

默认情况下,background-position是以padding-box为基准的; background-color是以border-box为基准的;

2022-05-15-16-25-24.png

将background-origin设置为content-box,容器中文字和背景图片都会以content-box为基准,这时设置padding就是文字和图片共同的padding了

padding:10px;
background:url(./car.png) no-repeat skyblue;
background-origin:content-box;

2022-05-15-16-30-53.png

2.3.3. calc()方案

背景图片以左上角偏移的思路来考虑,其实就是希望有一个100%-20px的水平偏移量,以及100%-10px的垂直偏移量,使用calc()函数就可以解决这个问题

background:url(./car.png) no-repeat;
background-position:calc(100%-20px) calc(100%-10px);

效果完全一样

2.4. 边框内圆角

问题:一个容器,外部边框是直角,内部边框是圆角

2022-05-15-16-41-58.png

书中box-shadow+outline的方法好像已经失效,因为不仅box-shadow会在设置border-radius产生圆角,outline也会产生,所以方法失效

2.5. 条纹背景

条纹背景实现原理:

  1. 如果多个色标具有相同的位置,他们会产生一个无限小的过渡区域,从效果上看,颜色会从这个位置突然变化,而不是一个平滑的过程。
  2. linear-gradient() 函数用于创建一个表示两种或者多种颜色线性渐变的图片。其结果属于<gradient>数据类型,是一种特别的<image>数据类型,因此我们可以通过background-size来控制渐变的大小。
  3. 如果某个色标的位置值比整个列表中在它之前的色标的位置小,则该色标的位置值会被设置为它前面所有色标位置值的最大值。

2.5.1. 横向条纹

2.5.1.1. 等宽条纹
 background-image: linear-gradient( red 50%, green 50%);
 background-size: 100% 20px;

效果:

2022-05-16-09-47-22.png

根据实现原理第三点,如果把第二个色标的位置值设置为0,那么它的位置就会总是被浏览器调整为前后一个色标的位置值,这样在以后修改时,就可以少修改一个数字

 background-image: linear-gradient( red 50%, green 0);
 background-size: 100% 20px;

效果与上面完全一样

2022-05-16-09-47-22.png

2.5.1.2. 不等宽条纹

调整第一个色标的位置值即可实现不等宽条纹:

 background-image: linear-gradient( red 20%, green 0);
 background-size: 100% 20px;

效果如图:

2022-05-16-09-53-29.png

2.5.1.3. 多色条纹

实现多色条纹只需在双色条纹的基础上再继续增加色标和对应的位置值即可:

background-image: linear-gradient( red 33.3%, green 0%, green 66.6%,yellow 0%);
background-size: 100% 60px;

效果如图:

2022-05-16-09-59-45.png

2.5.2. 竖向条纹

竖向条纹和水平条纹类似,只需改变渐进的方向:

background-image: linear-gradient(to right/*或者90deg*/, red 50%, green 0%);
background-size: 50px 100%;

效果如图:

2022-05-16-10-19-26.png

2.5.3. 斜向条纹

linear-gradient()radial-gradient()各有一个循环式的加强版:repeating-linear-gradient()repeating-radial-gradient()。它们的工作方式和前两者类似,只有一点不同:色标是无线循环重复的,直到填满整个背景

利用repeating-linear-gradient就可以作出斜向条纹:

background: repeating-linear-gradient(45deg, red 0,red 25px, green 0,green 50px);

效果如图:

2022-05-16-10-30-42.png

2.5.4. 同色系条纹

大多数情况下,我们想要的条纹往往是同色系条纹 同色系条纹制作思路: 把最深的颜色指定为背景色,同时把半透明的白色条纹叠加在背景色之上得到浅色条纹

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

效果如图:

2022-05-16-10-38-49.png

2.6. 复杂的背景图案

2.6.1. 网格

思路:将水平和竖直的条纹叠加起来

2.6.1.1. 桌布网格(方格纹)
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: 50px 50px;

效果如图:

2022-05-16-15-10-06.png

2.6.1.2. 蓝图网格

不管每个格子有多大,线条宽度始终为1px

background: skyblue;
background-image: linear-gradient(90deg, white 1px, transparent 0), linear-gradient(white 1px , transparent 0);
background-size: 50px 50px;

效果如图:

2022-05-16-15-21-57.png

2.6.2. 波点

利用径向渐变(radial-gradient)可以创建波点背景

2.6.2.1. 圆点阵列
background: #655;
background-image: radial-gradient(tan 30% , transparent 0);
background-size: 50px 50px;

效果如图:

2022-05-16-15-30-25.png

2.6.2.2. 波点

生成两层圆点阵列图案,并把它们的背景定位错开,就可以得到真正的波点图案了

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

效果如图:

2022-05-16-15-37-38.png

2.6.3. 棋盘

 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%,rgba(0,0,0,.25)0);
background-size: 50px 50px;
background-position: 0 0, 25px 25px;

效果如图:

2022-05-16-15-47-18.png

2.7. 伪随机背景

通过质数来增加随机真实性来源于Alex Walker的蝉原则。 具体理论参见《蝉原则对网页设计的重要性》

2.8. 连续的图像边框

问题:将一幅图案或者图片应用为边框,而不是背景。并且希望这个元素的尺寸在放大或者缩小时,这幅图片都可以自动延伸并覆盖完整的边框区域

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

3. 形状

3.1. 自适应椭圆

3.1.1. 椭圆

需求:当一个元素的长宽相等,就显示为一个圆,当长宽不等,就显示为一个椭圆

border-radius可以单独指定水平和垂直半径,只要用一个斜杠(/)分隔这两个值即可

.oval{
    margin-top: 50px;
    width: 300px;height: 200px;border-radius:150px / 100px;
    background-color: green;
}

效果如图:

2022-05-17-09-04-18.png

border-radius不仅可以接受长度值,还可以接受百分比值。这个百分比会基于元素的尺寸进行解析

.oval1{
    margin-top: 50px;
    width: 300px;height: 200px;border-radius: 50%/ 50%;
    background-color: yellow;
}

当然,也可以简写为:

.oval1{
    margin-top: 50px;
    width: 300px;height: 200px;border-radius: 50%;
    background-color: yellow;
}

效果如图:

2022-05-17-09-07-34.png

3.1.2. 半椭圆

border-radius有四个展开式属性:

  • border-top-left-radius
  • border-top-right-radius
  • border-bottom-right-radius
  • border-bottom-left-radius

2022-05-17-09-22-00.png 想要作出这样一个半椭圆,有以下分析:

  • 顶部两个角的水平圆角各是50%
  • 顶部两个角的竖直圆角都为100%
  • 底部两个角的竖直圆角都为0
  • 底部两个角的水平圆角是多少不再重要(因为底部的竖直圆角为0,此时水平圆角总是被计算为0)
.oval2 {
    margin-top: 50px;
    width: 300px;
    height: 200px;
    border-radius: 50% / 100% 100% 0 0;
    background-color: skyblue;
}

3.1.3. 四分之一椭圆

分析: 其中一个角的水平和竖直圆角都是100%,其他三个角都不设圆角

.oval3 {
    margin-top: 50px;
    width: 300px;
    height: 200px;
    border-radius: 100% 0 0 0;
    background-color: pink;
}

效果如图:

2022-05-17-09-28-44.png

3.2. 平行四边形

创建一个平行四边形可以先创建一个矩形,再通过skew()这个变形属性对矩形进行斜向拉伸

但这样直接使用会导致样式变形的同时内容也发生斜向变形

3.2.1. 伪元素方案

为了让样式产生变形的效果的同时使内容保持不变形,可以把所有的样式应用到伪元素上然后再对伪元素进行变形

.parallelogram{
    margin: 100px;
    width: 300px;
    height: 200px;
    position: relative;
}
.parallelogram::before{
    content:'';
    position:absolute;
    top:0;right: 0;bottom: 0;left: 0;
    z-index: -1;
    background: #58a;
    transform: skew(45deg);
}

效果如图:

2022-05-17-09-40-20.png

3.3. 菱形

polygon()允许我们用一系列(以逗号分隔的)坐标点来指定一个任意的多边形,甚至可以用百分比值,他们会解析为元素自身的尺寸

.diamond{
    margin: 100px;
    width: 300px;
    height: 200px;
    clip-path: polygon(50% 0, 100% 50%, 50% 100%,050%);
    background-color: red;
}

效果如图:

2022-05-17-10-16-20.png

3.4. 切角效果

3.4.1. 渐变方案

.chamfer{
    margin: 100px;
    width: 300px;
    height: 200px;
    background: #58a;
    background: linear-gradient(-45deg,transparent15px ,#58a 0);
}

效果如图:

2022-05-17-10-26-07.png 使用渐变方案切一个角很简单,但是切多个角就不那么简单了,切几个角就要用几次linear-gradient,比较繁琐

3.4.2. 裁切路径方案

.chamfer1 {
    margin: 100px;
    width: 300px;
    height: 200px;
    background: green;
    clip-path: polygon(20px 0, calc(100% - 20px)0, 100% 20px, 100% calc(100% - 20px),calc(100%- 20px) 100%, 20px 100%, 0 calc(100% - 20px),0 20px);  
}

效果如图:

2022-05-17-10-43-16.png

优点

  • 可以使用任意类型的背景,甚至可以第替换元素(比如图片)进行裁切
  • 支持动画效果

缺点:

  • 代码不够DRY
  • 浏览器支持程度不足
  • 当内边距不足时,会裁切掉文本

3.5. 梯形标签页

方案:3D旋转

3.6. 简单的饼图

3.6.1. transform解决方案

.pie{
    width: 100px;height: 100px;border-radius: 50%;
    background: yellowgreen;
    background-image: linear-gradient(to righttransparent 50%,#655 0);
}
.pie::before{
    content:'';
    display: block;
    margin-left: 50%;
    height: 100%;
    border-radius: 0 100% 100% 0 / 50%;
    background-color: #655;
    transform-origin:left ;
    transform: rotate(.1turn);
}

效果如图:

2022-05-17-15-37-35.png

4. 视觉效果

4.1. 单侧投影

4.1.1. 单侧投影

扩张半径:排在模糊半径参数之后,称作扩展半径。这个参数会根据指定的值去扩大或者缩小投影的尺寸。举例来说,一个-4px的扩张半径会把投影的宽度和高度各减少10px(即每边各减少5px)

2022-05-17-15-59-22.png

从逻辑上来说,如果应用一个负值的扩张半径,而它的值刚好等于模糊半径,那么投影的尺寸就会与投影所属元素的尺寸完全一致,除非用偏移量(前两个长度参数)来移动它,否则我们将完全看不见任何投影。因此,如果给投影一个正的垂直偏移量,我们就会在元素的底部看到一道投影,而元素的另外三侧是没有投影的

 .shadow{
        margin-top: 50px;
        width: 100px;height: 80px;background-color: yellow;
        box-shadow: 0 5px 4px -4px rgba(0,0,0,.7);
    }

效果如图:

2022-05-17-15-53-06.png

4.1.2. 邻边投影

思路:

  • 我们不应该把投影缩得太小,而是只需把阴影藏进一侧,另一侧自然露出。因此扩张半径不应设置为模糊半径的相反值,而应该是相反值的一半
  • 需要指定两个偏移量,因为我们希望在水平和垂直方向上同时移动。他们的值需要大于或者等于模糊半径的一半,因为我们希望把投影藏进另外两条边之内
.shadow1 {
    margin: 50px;
    width: 100px;
    height: 80px;
    background-color: yellow;
    box-shadow:3px 3px 6px -3px rgba(0, 0, 0, .7);
}

效果如图:

2022-05-17-16-05-21.png

4.1.3. 双侧投影

若想把投影设置在元素的两条对边(比如左边和右边),只能使用两块投影来达到目的(相当于用了两次单侧投影)

.shadow2 {
    margin: 50px;
    width: 100px;
    height: 80px;
    background-color: yellow;
    box-shadow: 5px 0px 5px -5px rgba(0, 0, 0, .7, -5px 0px 5px -5px rgba(0, 0, 0, .7);
}

效果如图:

2022-05-17-16-09-38.png

4.2. 不规则投影

border-radius会忽视透明部分,所以当元素添加了一些伪元素或者半透明的装饰时,box-shadow的效果就不那么完美了

解决方案:滤镜效果

滤镜效果filter有很多函数:

  • blur()
  • grayscale()
  • drop-shadow()
  • ...

这些滤镜可以连起来使用,例如:

fliter:blur() grayscale() drop-shadow()

这里需要用到drop-shadow(),这个滤镜可以接受的参数基本和box-shadow()一样,但不包括扩张半径和insert关键字,也不支持逗号分割的多层投影语法

比如:

box-shadow:2px 2px 10px rgba(0,0,0,.5);

可以这样写:

filter: drop-shadow(2px 2px 10px rgba(0,0,0,.5));

4.3. 染色效果

4.3.1. 基于滤镜的方案

4.3.2. 基于混合模式的方案

4.4. 毛玻璃效果

思路: 不能直接对元素本身进行模糊处理,就对一个伪元素进行处理,然后将其定位到元素的下层,它的背景将会无缝匹配<body>的背景

4.5. 折角效果

4.5.1. 45度折角的解决方案

.angled {
    width: 100px;
    height: 80px;
    margin: 100px;
    background: #58a;
    background: linear-gradient(to left bottom,transparent 50%, rgba(0, 0, 0, .4) 0)no-repeat 100% 0 / 2em 2em,
        linear-gradient(-135deg, transparent 1414em, #58a 0);
}

效果如图:

2022-05-17-17-15-01.png

5. 字体排印

5.1. 连字符断行

理想的两端对齐效果必须配合连字符断行才有较好的可读性。否则单词的间距会看起来很奇怪。两端对齐是与连字符断行相辅相成的。

解决方案: 新属性hyphens接受三个值:none,manual,auto。manual是他的初始值。将hyphens:auto就可以实现连字符断行的效果

5.2. 插入换行

    <div>
        <dl>
            <dt>Name:</dt>
            <dd>Lea Verou</dd>

            <dt>Email:</dt>
            <dd>lea@verou.me</dd>

            <dt>Location:</dt>
            <dd>Earth</dd>
        </dl>
    </div>


   <style>
       dt,
    dd {
        display: inline;
    }

    dd {
        margin: 0;
        font-weight: bold;
    }

    dd::after {
        content: "\A";
        white-space: pre;
    }
   </style>

5.3. 文本行的斑马条纹

实现表格行的斑马条纹;

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

在文本行中实现斑马条纹解决方案: 对整个元素设置统一的背景图像,一次性加上所有的斑马条纹(使用渐变生产背景图像,并且用em做单位)

.zbra {
    width: 200px;
    padding: .5em;
    line-height: 1.5;
    background: beige;
    background-image: linear-gradient(rgba(0, 0, 0, 2) 50%, transparent 0);
    background-origin: content-box;
    background-size: auto 3em;
}

效果如图:

2022-05-18-10-18-33.png

5.4. 调整tab的宽度

问题: 包含大量代码的网页通常使用<pre><code>元素来显示代码。但是即使tab非常适合用来缩进代码,待人们在网页中常常有意避开tab,因为tab在浏览器中会显示8个字符的宽度。

解决方案: 新属性tab-size可以控制tab显示宽度。这个属性接受一个数字(表示字符数)或者长度值

pre{
    tab-size:2;
}

5.5. 连字

字体设计师通常会在字体中包含一些额外的自行,称作连字(ligature)。这些字形被设计为双字形或者三字形的单一组合体,专门提供给排版软件使用,代为显示特定的字符组合

解决方案: font-variant-ligatures:控制连字效果的开启和关闭

开启所有可能的连字:

font-variant-ligatures:common-ligatures discretionary-ligatures historical-ligatures;

这个属性可以被继承,如果你认为酌情连字会干扰到正常文字的阅读效果,想关掉它,那么可以只开启通用连字:

font-variant-ligatures:common-ligatures;

或者显式地关掉其他两种:

font-variant-ligatures:common-ligatures no-discretionary-ligatures no-historical-ligatures;

5.6. 华丽的“&”符号

通过@font-face规则实现基本的字体嵌入

5.7. 自定义下划线

解决方案: 使用background-image及其相关属性:

.underline{
    width: 150px;
    background: linear-gradient(gray ,gray)no-repeat;
    background-size: 100% 1px;
    background-position: 0 1.15em;
    text-shadow: 0.05em 0 white,-0.05em 0 white;
}

效果如图:

2022-05-18-10-55-58.png

5.8. 现实中的文字效果

5.8.1. 凸版印刷效果

适用场景:

  • 中等亮度背景配上深色文字
  • 深色底浅色字的背景
中等亮度背景配深色文字

在底部加浅色投影

.underline1{
    width: 150px;
    background: hsl(210,13%,60%);
    color:hsl(210,13%,30%);
    text-shadow: 0 1px 1px hsla(0,0%,100%,.8);
}

效果如图:

2022-05-18-11-03-05.png

深色底配浅色文字

给文字顶部加深色投影

.underline2{
    margin: 50px;
    width: 150px;
    background: hsl(210,13%,40%);
    color:hsl(210,13%,75%);
    text-shadow: 0 -1px 1px black;
}

效果如图:

2022-05-18-11-05-57.png

5.8.2. 空心字效果

使用多个text-shadow,分别为这些投影加上不同方向的少量偏移:

.hollow {
    margin: 50px;
    width: 100px;
    height: 80px;
    text-align: center;
    background: deeppink;
    font-size: 40px;
    font-weight: bold;
    color: white;
    line-height: 80px;
    text-shadow:  1px 1px black,-1px -1px black, 1px-1px black, -1px 1px black;
}

效果如图:

2022-05-18-15-22-17.png

重叠设置多层轻微模糊的投影来模拟描边:

.hollow1 {
    margin: 50px;
    width: 100px;
    height: 80px;
    text-align: center;
    background: deeppink;
    font-size: 40px;
    font-weight: bold;
    color: white;
    line-height: 80px;
    text-shadow: 0px 0px 1px black, 0 0 1px black, 00 1px black, 0 0 1px black, 0 0 1px black, 0 01px black;
}

效果如图:

2022-05-18-15-27-13.png

5.8.3. 文字外发光效果

text-shadow方案

准备几层重叠的text-shadow即可,不需要考虑偏移量,颜色也只需和文字保持一致

.glow {
    margin: 50px;
    width: 150px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    background: #203;
    font-size: 40px;
    font-weight: bold;
    color: #ffc;
    text-shadow:0 0 .1em,0 0 .3em;
}

效果如图:

2022-05-18-15-31-38.png

filter方案
.glow1 {
    margin: 50px;
    width: 150px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    background: #203;
    font-size: 40px;
    font-weight: bold;
    color: #ffc;
}
.glow1 span {
    filter: blur(.05em);
}

效果如图:

2022-05-18-15-42-00.png

5.8.4. 文字凸起效果

效果一

思路: 使用一长串的累加投影,不设模糊并以1px的跨度逐渐错开,是颜色逐渐变暗,然后在底部加一层强烈的暗投影,从而模拟完整的立体效果

.bluge{
    margin: 50px;
    width: 150px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    font-size: 40px;
    font-weight: bold;
    background: #58a;
    color: white;
    text-shadow: 
    0 1px hsl(0,0%,85%),
    0 2px hsl(0,0%,80%),
    0 3px hsl(0,0%,75%),
    0 4px hsl(0,0%,70%),
    0 5px hsl(0,0%,65%),
    0 1px 10px black;
}

结果如下:

2022-05-18-15-49-25.png

效果二
.bluge1 {
    margin: 50px;
    width: 150px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    font-size: 40px;
    font-weight: bold;
    background: hsl(0,50%,45%);
    color: white;
    text-shadow:
        1px 1px black,
        2px 2px black,
        3px 3px black, 
        4px 4px black, 
        5px 5px black, 
        6px 6px black, 
        7px 7px black, 
        8px 8px black;
}

效果如图:

2022-05-18-15-56-32.png

5.9. 环形文字

使用svg

6. 用户体验

6.1. 鼠标光标

内建光标:

2022-05-18-16-01-17.png

使用方式:

cursor:not-allowed //或者其他光标;

6.3. 扩大可点击区域

我们可以在按钮的上层覆盖一层透明的伪元素,并让伪元素在四个方向上都比宿主元素大出10px;

.button1 {
    width: 50px;
    height: 50px;
    background-color: skyblue;
    border-radius: 50%;
    margin: 50px;
    position: relative;
}
.button1::before {
    content: '';
    position: absolute;
    top: -10px;
    right: -10px;
    bottom: -10px;
    left: -10px;
}

6.4. 自定义复选框

单选框和复选框这两种控件在绝大多数浏览器中仍然是几乎或者完全无法设置样式的。

解决方案:

利用伪类checked基于复选框的勾选状态借助组合选择符来给其他元素设置样式

有一个元素总是跟复选框形影不离,它就是<lable>标签,当<lable>标签与复选框关联后,也可以起到触发开关的作用

我们可以为<lable>添加伪元素,并基于复选框的状态来为其设置样式,然后把真正的复选框隐藏起来。

6.5. 通过阴影来弱化背景

问题:很多时候,我们需要通过一层半透明的遮罩层来把后面的一切整体调暗,以便凸显某个特定的UI元素

6.5.1. 伪元素方案

body.dimmed::before{
    position:fixed;
    top:0;
    right:0;
    bottom:0;
    left:0;
    z-index:1;
    background:rgba(0,0,0,.8);
}

缺点: 可移植性不太好,因为<body>元素可能有其他需求已经占用了::before伪元素,而且在使用这个效果时,需要使用JavaScript来给body添加dimmed这个类

6.5.2. box-shadow方案

初步解决方案:

box-shadow:0 0 0 999px rgba(0,0,0,.8);

缺点: 无法在较大屏幕分辨率(>2000px)下正常工作

进阶解决方案: 1vmax相当于1vw和1vh的较大值,100vw是真个视口的宽度,100vh是整个视口的高度。因此,满足我们需求的最小值就是50vmax.

box-shadow:0 0 0 50vmax rgba(0,0,0,.8);

缺点:

  • 遮罩层与视口相关而不是与页面相关,当滚动页面时,遮罩层边缘就会漏出来
  • 当使用一个独立的元素(或者伪元素)来实现遮罩层时,这个遮罩层不仅可以从视觉上把用户的注意力引导到关键元素上,还可以防止用户的鼠标与页面的其他部分发生交互。box-shadow没有这个能力:只能在视觉上起到引导注意力的作用,无法阻止鼠标交互。

6.5.3. backdrop方案

如果你想引导用户关注的元素就是一个模态的<dialog>元素,那么根据浏览器的默认样式,它会自带一个遮罩层,利用::backdrop伪元素,这个原始遮罩层也可以设置样式:

dialog::backdrop{
    background:rgba(0,0,0,.8);
}

6.6. 通过模糊来弱化背景

问题:如果我们想对除了某个特定元素之外的一切应用模糊效果,那么到底应该把滤镜应用到那个元素上呢?如果把它应用到<body>元素上,所有元素都会被模糊处理

解决方案: 增加一个额外的HTML元素来实现这个效果:需要把页面上除了关键元素之外的一切都包裹起来。<main>元素在这里是很合适的。

6.7. 滚动提示

滚动条与顶部阴影

6.8. 交互式的图片对比控件

7. 结构与布局

7.1. 自适应内部元素

问题: 如果不给元素指定一个具体的height,它就会自动适应其内容的高度。假如我们希望width也有类似的行为,该怎么做呢?

解决方案 width和height的关键字min-content,这个关键字将解析为这个容器内部最大的不可断行元素的宽度(即最宽的单词、图片或者具有固定宽度的盒元素)

    figure{
        width:min-content;
        margin: auto;
    }

效果如图:

2022-05-18-20-06-52.png

为了给旧版浏览器提供一个平稳的回退样式,我们需要在使用这个技巧的同时,提供一个固定的max-width值 比如:

    figure{
        max-width:300px;
        max-width:min-content;
        margin: auto;
    }

    figure>img{max-width:inherit;}

对于现代浏览器来说,后一条max-width声明会覆盖前一条。如果figure的尺寸是由内部因素决定时,第二条规则中的max-width:inherit就不会生效了

7.2. 精确控制表格列宽

问题:让表格的行为更加可控

解决方案

table-layout的默认值是 auto,其行为模式被称为自动表格布局算法,也就是我们最为熟悉的表格布局行为。不过,它还接受另外一个值fixed,这个值明显可控一些。我们设置的(宽度)样式会直接起作用,而不仅仅被视为一种提示;同时,溢出行为(包括text-overflow)与其他元素行为也是一样的,因此,表格的内容将只能影响表格行的高度。

table{
    table-layout:fixed;
    width:100%;
}

7.3. 根据兄弟元素的数量来设置样式

问题: 在某些场景下,我们需要根据兄弟元素的总数来为他们设置样式。最常见的场景就是,当一个列表不断延长时,通过隐藏控件或者压缩控件等方式来节省屏幕空间。

2022-05-18-20-21-48.png

7.4. 满幅的背景,定宽的内容

一般做法是为每个区块准备两层元素:外层实现满幅的背景,内层用来实现定宽的内容

去掉一层额外的元素: 添加额外的一层是为了使用margin:auto使内容居中, 可以用calc()代替margin:auto

padding:1em;
padding:1em calc(50%-450px);
background:#333;

7.4. 垂直居中

结构代码:

    <main>
        <h1>Am I centered yet?</h1>
        <p>Center me, please!</p>
    </main>

7.4.1. 基于绝对定位的解决方案

对于需要垂直居中的元素来说,其尺寸往往是由其内容来决定的。如果能找到一个属性的百分比是以元素自身的宽高作为解析基准。传统绝对定位方法中需要宽高固定的局限将不复存在。

对于绝大多数CSS属性(包括margin)来说,百分比都是以其父元素的尺寸为基准来进行解析的。

但是translate()变形函数中使用百分比时,是以这个元素自身的宽高为基准进行换算和移动的。

这样,只要换用基于百分比的CSS变形来对元素进行偏移,就不需要把元素的尺寸写死了。这样我们就能彻底解除对固定尺寸的依赖

main{
    position:absolute;
    top:50%;
    left:50%;
    transform:translate(-50%,-50%);
}

缺点:

  • 需要使用绝对定位,而绝对定位对整个布局的影响很大,有时不被允许使用
  • 如果需要居中的元素已经在高度上超过了视口,顶部会被视口裁切掉
  • 某些浏览器中,这个方法可能会导致一些元素显示模糊

7.4.2. 基于视口单位的解决方案

main{
    width:18em;
    padding:1em 1.5em;
    margin:50vh auto 0;
    transform:translateY(-50%);
}

缺点:

  • 只适合视口居中的场景

7.4.3. 基于Flexbox的解决方案

这是最佳解决方案

只需两行声明即可:先给这个待居中元素的父元素设置display:flex(在这个例子中是<body>),再给这个元素自身设置margin:auto(在这个例子中是<main>)

body{
    display:flex;
    min-height:100vh;
    margin:0;
}

main{
    margin:auto;
}

优点:

  • 当我们使用Flexbox时,margin:auto不仅在水平方向上将元素居中,垂直方向上也是如此
  • Flexbox的另一个好处是可以将匿名容器垂直居中

7.5. 紧贴底部的页脚

7.5.1. 固定高度的解决方案

用计算属性计算页脚高度: 例如;

#wrapper{
    min-height:calc(100vh-7em)
}

7.5.2. 更灵活的解决方案

Flexbox

思路:

  1. 首先将父元素设置display:flex
  2. 将flex-flow设置为column
  3. 将父元素<body>的min-height设置为100vh,这样它就至少会占据整个视口的高度
  4. 我们希望页头<header>和页脚<footer>的高度由其内部因素决定,而内容区块<main>的高度应该可以自动伸展并沾满所有可用的空间。只要我们给<main>这个容器的flex属性指定一个大于0的值(比如1),就可以实现这个效果
body{
    display:flex;
    flex-flow:column;
    min-height:100vh;
}
main{
    flex:1;
}

8. 过渡与动画