FLIP 动画入门了解

最近看到一个词 “FLIP 动画”,我还以为是什么新奇的技术,点击去看了一眼,原来是 CSS3 的相关技术的应用。

具体解释,我就从其他地方 Copy 的一段:

CSS FLIP 动画是一种使用 CSS 过渡和变换属性来创建流畅动画效果的技术。FLIP 是 “First, Last, Invert, Play” 的缩写,它描述了一种优化动画性能的方法。

FLIP 动画的基本原理是在动画开始和结束时,通过获取元素的初始状态和最终状态的位置、大小和其他属性,然后通过 CSS 变换和过渡来实现平滑的动画效果。

具体步骤如下:

  • First(首次):获取元素的初始状态(位置、大小、样式等)。
  • Last(最后):获取元素的最终状态(位置、大小、样式等)。
  • Invert(反转):通过 CSS 变换将元素的最终状态反转到初始状态。
  • Play(播放):应用 CSS 过渡,将元素从初始状态平滑地过渡到最终状态。

通过使用 FLIP 技术,可以减少动画期间的重排和重绘操作,提高动画的性能和流畅度。这种技术特别适用于需要在页面布局改变时进行动画的情况,如元素的位置变化、大小变化或样式变化等。

请注意,FLIP 动画需要一些 JavaScript 代码来计算元素的初始状态和最终状态,并应用相应的 CSS 类和样式

简而言之,言而简之!就是利用 CSS3 的动画特性,通常只要把起始、结束两个状态告诉浏览器,渲染引擎(浏览器)会自动控制动画序列,从而实现动画,无需额外 JS

FLIP 动画 为了得到起始、结束的状态需要 JS 配合,初始状态 容易得到,但是为了得到 结束状态 ,就得让元素放置到 结束状态 的位置,正常情况下,直接放置是不会有任何动画,而且元素直接到了 结束状态

怎么让元素其实已经放置到 结束状态 ,但是看起来还是初始状态呢?这就是其中一个关键点,其实实现起来也很简答,利用 CSS3 位移属性,计算两种状态的 偏移距离, 然后利用 transform: translate(X px, Y px) 在移动回去, 让视觉上看起来实际没有移动。(这其实就是所谓的 “初始状态”)

接下来就是让动画动起来,就是要设置 结束动画属性,当前位置不就是结束位置么?压根不用动,直接把 位移值设置为 0 - transform: translate(0px, 0px) 即可. 开始-结束 都有了,动画不就自动开始了。

这个时候你如过直接设置,可能会发现毫无效果,为啥呢??你这样直接设置,肯定会在同一帧内渲染,根本看不到效果(具体为啥,去了解 JS 阻塞渲染 相关知识),我们可以利用一些异步方式,或者强制渲染一次,然后在第二次渲染的时候 设置结束属性,例如: requestAnimationFrame, setTimeout 等都可以。

具体 demo 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flip 动画实现</title>
<style>
body {
font-family: -apple-system, "Helvetica Neue", "Arial", "PingFang SC",
"Hiragino Sans GB", "STHeiti", "Microsoft YaHei",
"Microsoft JhengHei", "Source Han Sans SC", "Noto Sans CJK SC",
"Source Han Sans CN", "Noto Sans SC", "Source Han Sans TC",
"Noto Sans CJK TC", "WenQuanYi Micro Hei", SimSun, sans-serif;
}

.container {
width: 320px;
height: 320px;
background-color: blanchedalmond;
}

.item {
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 30px;
}

.item[data-key="1"],
.item[data-key="6"],
.item[data-key="11"],
.item[data-key="14"] {
background-color: tomato;
color: #fff;
}

.item[data-key="2"],
.item[data-key="7"],
.item[data-key="16"] {
background-color: #999933;
color: #fff;
}

.item[data-key="3"],
.item[data-key="10"],
.item[data-key="12"] {
background-color: #ff0033;
color: #fff;
}

.item[data-key="4"],
.item[data-key="9"],
.item[data-key="15"] {
background-color: #003366;
color: #fff;
}

.item[data-key="8"],
.item[data-key="13"] {
background-color: #0099cc;
color: #fff;
}

.item[data-key="8"],
.item[data-key="15"],
.item[data-key="5"] {
background-color: #996600;
color: #fff;
}

/* grid 布局 */
.grid-wrap {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
</style>
</head>

<body>
<h1>
最新看来一个新东西(对我而言是新东西)Flip
动画,秉着好奇的心理,打开看了一眼,原来是这样的!
</h1>
<p></p>
<hr />
<button id="change1">变化</button>
<div class="container normal-wrap">
<div class="item" data-key="1">1</div>
<div class="item" data-key="2">2</div>
<div class="item" data-key="3">3</div>
<div class="item" data-key="4">4</div>
</div>

<hr />
<button id="change2">变化</button>
<div class="container grid-wrap">
<div class="item" data-key="1">1</div>
<div class="item" data-key="2">2</div>
<div class="item" data-key="3">3</div>
<div class="item" data-key="4">4</div>
<div class="item" data-key="5">5</div>
<div class="item" data-key="6">6</div>
<div class="item" data-key="7">7</div>
<div class="item" data-key="8">8</div>
<div class="item" data-key="9">9</div>
<div class="item" data-key="10">10</div>
<div class="item" data-key="11">11</div>
<div class="item" data-key="12">12</div>
<div class="item" data-key="13">13</div>
<div class="item" data-key="14">14</div>
<div class="item" data-key="15">15</div>
<div class="item" data-key="16">16</div>
</div>
</body>
<script>
// const item = document.querySelector('.item[data-key="1"]')
const wrap = document.querySelector(".normal-wrap");
const btn = document.getElementById("change1");

const itemsCache = new Map();

btn.addEventListener("click", () => {
raffle();
});

function delay(d = 1000) {
const n = Date.now();
while (Date.now() - n < d) {}
}

function calcPos(dom) {
return dom.getBoundingClientRect();
}

function item(wrap, index) {
if (!itemsCache[index]) {
itemsCache[index] = wrap.querySelector(`.item[data-key="${index}"]`);
}
return itemsCache[index];
}

function itemV2(dom) {
return (k) => {
return dom.querySelector(`.item[data-key="${k}"]`);
};
}

let index = [1, 2, 3, 4];
function raffle() {
const posBegin = {};
const postLast = {};

// 初始位置
index.forEach((k) => {
posBegin[k] = calcPos(item(wrap, k));
});

// 移动元素
index = index.sort(() => Math.random() - 0.5);
index.forEach((k) => {
wrap.append(item(wrap, k));
});

// Invert 计算位移
const diff = {};
index.forEach((k) => {
// 计算移动后位置
postLast[k] = calcPos(item(wrap, k));

// 获取偏移量
diff[k] = {
x: postLast[k].left - posBegin[k].left,
y: postLast[k].top - posBegin[k].top,
};
});

Object.keys(diff).forEach((k) => {
// 设置偏移样式
item(wrap, k).style.transform = `translate(${-diff[k].x}px, ${-diff[k]
.y}px) scale(0.9)`;
item(wrap, k).style.transition = "none";
});

window.requestAnimationFrame(() => {
index.forEach((k) => {
item(wrap, k).style.transform = `translate(0,0)`;
item(wrap, k).style.transition = "transform .5s";
});
});
}

// v2 grid 布局
let index2 = Array.from({ length: 16 })
.fill(0)
.map((v, i) => i + 1);
const wrap2 = document.querySelector(".grid-wrap");
const btn2 = document.querySelector("#change2");

btn2.addEventListener("click", () => {
raffle2();
});

function raffle2() {
const _item = itemV2(wrap2);
const posBegin = {};
const postLast = {};

// 初始位置
index2.forEach((k) => {
posBegin[k] = calcPos(_item(k));
});

// 移动元素
index2 = index2.sort(() => Math.random() - 0.5);
index2.forEach((k) => {
wrap2.append(_item(k));
});

// Invert 计算位移
const diff = {};
index2.forEach((k) => {
// 计算移动后位置
postLast[k] = calcPos(_item(k));

// 获取偏移量
diff[k] = {
x: postLast[k].left - posBegin[k].left,
y: postLast[k].top - posBegin[k].top,
};
});

Object.keys(diff).forEach((k) => {
// 设置偏移样式
_item(k).style.transform = `translate(${-diff[k].x}px, ${-diff[k]
.y}px) scale(0.9)`;
_item(k).style.transition = "none";
});

window.requestAnimationFrame(() => {
index2.forEach((k) => {
_item(k).style.transform = `translate(0,0)`;
_item(k).style.transition = "transform .5s";
});
});

console.log("a");
}
</script>
</html>

这是一个简易 demo,没有通用性,只是为了演示具体原理。好多大佬封装了一些通用库来实现这个功能,可去 Github 上找找。

作者

Fat Dong

发布于

2023-10-12

更新于

2023-10-12

许可协议

flex布局应用案例-左对齐

最近在做一个类似于京东商城首页 banner 图下面分类图标展示效果, 一行四个,分两行展示. 通常情况下如果数量固定,本来是很简单的flex布局即可搞定。却高的很麻烦。

jd 使用了float属性 来布局。

实际UI效果要求(不上图了,涉及公司隐私)

  1. 每行最多四个,四个元素,中间距离一样,两端对齐,就是 justify-content:space-between 效果,
  2. 数量不固定, 可能是 1 - 12个。例如:只有两个的时候, 也要保持两端对齐的情况下,前两个元素同样的位置

使用flex布局, 不考虑两端对齐

这个是最常见的情况,使用 flex布局, 子元素固定宽度之后,会自动平铺换行。但是这种不一定会符合UI,也就是说,无法两端对齐。 对于不需要两端对齐的情况下,非常方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* 公共css */
* {
margin: 0;
padding: 0;
}
ul,
li {
list-style: none;
}

.page {
padding: 0 20px;
}

.page h5{
margin-top: 10px;
margin-bottom: 10px;
}

.wrap {
background-color: #f3f4f8;
border-radius: 7px;
margin-bottom: 18px;
padding-bottom: 20px;
}

.icon {
width: 27px;
height: 27px;
object-fit: cover;
line-height: 0;
font-size: 0;
}
.name {
font-size: 12px;
font-weight: 500;
margin-top: 10px;
}

.item {
text-align: center;
margin-top: 20px;
}
1
2
3
4
5
6
7
8
9
/* 第一种方式 v1 */
.list {
display: flex;
flex-wrap: wrap;
}

.list .item {
flex: 0 0 25%;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="page">
<div class="wrap">
<ul class="list">
<li class="item">
<img
src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
class="icon">
<p class="name">
测试
</p>
</li>
<!-- 省略其余7个 li -->
</ul>
</div>
</div>

效果图:

问题点:容器两侧保留空间太大,与UI不符合,

使用flex ,两端对齐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 第二种方式 */
.list2 {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}

.list2 .item {
flex: 0 0 25%;
}
.list2 .item-inner{
width: 30px;
margin: 0 auto;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="wrap">
<ul class="list2">
<li class="item">
<div class="item-inner">
<img src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" class="icon">
<p class="name">
测试
</p>
</div>
</li>
<!-- 省略其余7个 li -->
</ul>
</div>

方式2中,多了一层div,效果和1 一样,但是 方式2 有一个弊端: 如果数量无法保持 4n 的话,最后一行就无法左对齐。也没有实现两端对齐。

flex 动态计算 marginleft

这个是看完 软老师 博客学习,一般很少使用calc这个属性,相比较性能差点。而且做的大部分功能偏后台的,不太用得着。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.list3 {
display: flex;
flex-wrap: wrap;
padding: 0 22px;
}

.list3 .item {
flex: 0 0 30px;
}
.list3 .item:nth-child(4n+1) {
margin-left: 0;
}
.list3 .item:not(:nth-child(4n+1)) {
margin-left: calc((100% - 120px) / 3);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="wrap">
<ul class="list3">
<li class="item">
<div class="item-inner">
<img src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" class="icon">
<p class="name">
测试
</p>
</div>
</li>
<!-- 省略其余7个 li -->
</ul>
</div>

第三种方式,配合 nth-child 选择器,不用考虑数量问题,任意都可以,保持两端左对齐,但是需要根据实际需求去调整 css 属性列数 即可。

对于容器两边距离固定, 又要保持子元素两端对齐的方式,也是一种解决方式。

如果你有更好的,欢迎交流

作者

Fat Dong

发布于

2023-04-06

更新于

2023-04-06

许可协议

backdrop-filter 导致动画卡顿问题

最近在学习 tailwindcss,就是用 tailwind css 、headless UI 模仿 seeseed 做了一个网站,封装了一个modal之后,发现动画在4K显示器中特别卡顿,即使使用 translateZ(0) 开启硬件加速也没用。而在另一个1080P的显示器中正常。通过多方排查返现:是由于遮罩层加了一个css 属性 ,backdrop-filter ,这是属性的作用是添加一个毛玻璃效果。看了下兼容性,大部分现代浏览器是没问题的。

兼容性

在网上查找一番,大家都说添加backdrop-filter会卡顿,推荐使用 transform: translateZ(0); 开启GPU加速题提高性能。

我的电脑是一台 NUC8-i5-BEH , 显卡据说是核显里面还算可以的 ntel Iris Plus Graphics 655。当然比起一些独立显卡,还是比较弱,只能满足办公需求。 即使开始GPU硬件加速,依然是肉眼可见的掉帧。看来这个backdrop-filter很耗费性能啊!!!

MDN上的描述:

backdrop-filter CSS 属性可以让你为一个元素后面区域添加图形效果(如模糊或颜色偏移)。因为它适用于元素背后的所有元素,为了看到效果,必须使元素或其背景至少部分透明。以下是一些属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* 关键词值 */
backdrop-filter: none;

/* 指向 SVG 滤镜的 URL */
backdrop-filter: url(commonfilters.svg#filter);

/* <filter-function> 滤镜函数值 */
backdrop-filter: blur(2px);
backdrop-filter: brightness(60%);
backdrop-filter: contrast(40%);
backdrop-filter: drop-shadow(4px 4px 10px blue);
backdrop-filter: grayscale(30%);
backdrop-filter: hue-rotate(120deg);
backdrop-filter: invert(70%);
backdrop-filter: opacity(20%);
backdrop-filter: sepia(90%);
backdrop-filter: saturate(80%);

/* 多重滤镜 */
backdrop-filter: url(filters.svg#filter) blur(4px) saturate(150%);

/* 全局值 */
backdrop-filter: inherit;
backdrop-filter: initial;
backdrop-filter: revert;
backdrop-filter: unset;

这是一个介绍 filterbackdrop-filter 的文章
https://github.com/chokcoco/iCSS/issues/147

文章有一个点就是说: 发现其实两者并无多大性能上的差异, 这个其实是不正确的,可能作者没有在一个高分辨率的显示器中测试,在我电脑上 4K 显示器中, blur 也会有卡顿,但是比起 backdrop-filter 还是要好一点。

作者

Fat Dong

发布于

2022-11-08

更新于

2022-11-08

许可协议

css阻塞dom解析么

众所周知,js的加载会阻塞dom解析, 那么css呢??整理一下知识点

二次更新:
推荐一篇文章,光看图片就能明白了,挺不错 https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/

前言

先来一张图 HTML - DOM
HTML-DOM

我们在访问某一个网页时,浏览器是先请求 HTML, 然后才是外部资源,例如:js脚本,css样式,所以在顺序上是先构建的 DOM

例如常见的两个dom事件: onLoad, DOMContentLoaded , 这两个最大区别就在于触发的时机,load是包含了外部资源加载的时间,比如:图片、样式等等。DOMContentLoaded 是在dom数构建之后触发的。

外部资源不会影响 DOMContentLoaded 触发, 但是脚本会,默认情况下 js 是同步的,除非 加上 异步属性 deferasync 之后。

  • async 标志的脚本文件一旦加载完成就会立即执行,并且不会按照书写顺序,谁下载好了就直接执行。所以适用于那些没有代码依赖顺序,并且没有 DOM操作 的脚本文件。
  • defer 标志的脚本文件会严格按照书写顺序执行,并且,会在 DOMContentLoaded 事件之前(也就是页面DOM加载完成时)执行。适用于有 DOM操作 ,或者是有代码依赖顺序的脚本文件。

css 的阻塞

css 阻塞无非以下几种情况

  • 阻塞解析HTML
  • 阻塞渲染HTML
  • 不阻塞解析
  • 不阻塞渲染

不过,如果css 阻塞了解析,必然导致渲染会延迟。

我们可以通过开发者工具来验证一下,

  • 第一轮测试的 请求资源 4 是表示 js加载设置了4s延迟, 3是css,设置了3s延迟。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    <script type="text/javascript" src="http://localhost:9800/api/file/js/4"></script>
    <link rel="stylesheet" type="text/css" href="http://localhost:9800/api/file/css/3">
    </head>
    <body>
    <h1 class="font">^_^</h1>
    <h2 class="font">😭</h2>

    <button id="reload">xxx</button>
    <button id="reload">ooo</button>
    </body>
    </html>

js 和 css 同时加载的下:
css

可以看到 js(4) 和css(3)是同时请求加载的, 解析html是在js加载之后,

只是加载css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<!-- <script type="text/javascript" src="http://localhost:9800/api/file/js/4"></script> -->
<link rel="stylesheet" type="text/css" href="http://localhost:9800/api/file/css/3">
</head>
<body>
<h1 class="font">^_^</h1>
<h2 class="font">😭</h2>

<button id="reload">xxx</button>
<button id="reload">ooo</button>
</body>
</html>

css

可以看到 css 的加载并未导致解析html停止。

证明: css是不会阻塞解析HTML的

  • 如果我在head里面的script 放在 link 之前呢,让 css 的加载时间延长到 5s, js 的加载时间缩短到 2s呢?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    <link rel="stylesheet" type="text/css" href="http://localhost:9800/api/file/css/5">
    <script type="text/javascript" src="http://localhost:9800/api/file/js/2"></script>
    </head>
    <body>
    <h1 class="font">^_^</h1>
    <h2 class="font">😭</h2>

    <button id="reload">xxx</button>
    <button id="reload">ooo</button>
    </body>
    </html>
    css

怎么解析html 时间延后了,而且是在css加载之后,什么情况?怎么和上面的结论有出入啊?

那咱么去掉 js ,再来一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" type="text/css" href="http://localhost:9800/api/file/css/5">
<!-- <script type="text/javascript" src="http://localhost:9800/api/file/js/2"></script> -->
</head>
<body>
<h1 class="font">^_^</h1>
<h2 class="font">😭</h2>

<button id="reload">xxx</button>
<button id="reload">ooo</button>
</body>
</html>

css

可以看到解析html时间又提前了,符合第一次测试的结果了,

可见:css 的阻塞其实和js 有关联的。

css 和 js 虽然可以同步加载,但是如果css是在js之前加载的,会导致js的阻塞,从而导致了 html的解析。

  • 把css 放在 body中再 试试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<h1 class="font">^_^</h1>
<h2 class="font">😭</h2>

<link rel="stylesheet" type="text/css" href="http://localhost:9800/api/file/css/5">
<!-- <script type="text/javascript" src="http://localhost:9800/api/file/js/2"></script> -->
<button id="reload">xxx</button>
<button id="reload">ooo</button>
</body>
</html>

结果:

解析还是正常解析,并未被阻塞,但是 注意标红的地方(忽略之前的时间轴,那个是刷新之前的),按钮并未显示,而是等css 加载完成之后才展示的。 如果你在自己的浏览器重尝试的话,会明显感到按钮会闪现出来。

总结出来的几个点:

  • DOM 的解析是一个从上到下的过程
  • 所有外链资源浏览器都会已接近并发的情况来发起请求
  • CSS 会阻塞 渲染html,而且在某种情况下(后面有js的时候)还会阻塞解析,原因就是:浏览器不知道JS是否会需要查询 CSSDOM,所以需要等待CSS准备完毕。(来源于网络上的)

虽然js 、css 是近乎于同步的方式加载,但是针对 同一个域名 同时并发数量还是有限制的,数量基本上限制在 4-8 之间. 这也是你会看到大部分网站,图片、css、js有时候是分不同的域名。

注:以上测试截图环境均为: Chrome canary (x86_64) 105.0.5179.0(正式版本)

可能有不严谨的地方,欢迎大家指正

作者

Fat Dong

发布于

2022-07-14

更新于

2022-07-15

许可协议

css - inline-block的小坑

inline-block

inline-block 是 display 可选值得其中一个,简单理解就是可将 clock 的元素,以 inline 的方式呈现,并且可以设置宽高等属性。

常遇到的一些小问题

水平间隙

这个经常遇到的问题,在多个 inline-block 元素,排列的时候,会出先一个间隙。例如:

1
2
3
4
5
<div class="nav">
<div class="nav-item"><a>导航</a></div>
<div class="nav-item"><a>导航</a></div>
<div class="nav-item"><a>导航</a></div>
</div>
1
2
3
4
5
6
7
8
.nav {
background: #999;
}
.nav-item{
display:inline-block; /* 设置为inline-block */
width: 100px;
background: #ddd;
}

通常为了方便编写代码,我们会对代码进行格式化,让以一个方便阅读的方式换行展示,而这个换行符号,看起来没有东西,但是浏览器不这样认为。这个空白字符正是两个标签之间的空白的地方,也是浏览器的正常行为。

为了消除这个空白,通常使用的方法有:

  1. 去掉空白,将相邻标签的紧挨起来,去除换行和空白字符
  2. 设置font-size , 将上级的font-size设置为:0,表示不显示字符,这样空白也会没有。

对齐问题

这个问题和英文语言有一点关系,一个叫 baseline 基准线的东西,中文里没有这个东西,都是方方正正的一个小方块里面,来一个图说明一下:

img

一般常用 vertical-align: middle 来让 元素居中对齐, 想了解更多 baseline 相关 的东西,可自行搜索。

今天想说明的是一个使用场景, 这个一个简易的轮播图,页码布局。如下:

1
2
3
4
5
6
7
<div class="wrap">
<div class="page-wrap">
abcdefgh
<span class="page-dot"></span>
<span class="page-dot act"></span>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.wrap{
position: relative;
width: 500px;
height: 300px;
}
.page-wrap{
position: absolute;
height: 3px;
background: red;
left: 0;
right: 0;
bottom: 4px;
}
.page-dot{
display: inline-block;
height: 3px;
width: 12px;
border-radius: 3px;
opacity: 0.4;
background: blue;
}
.page-dot.act{
opacity: 1;
}

可以发现,span 元素并没有在 父级里面,二位跑到了 父级下面。 因为容器的高度被定死了,默认行高的情况下,文本是可定要超出容器的,而 默认的对齐方式 是以 baseline 对齐的,所以肯定会出现在容器的下方。为了让空 的span 对齐,可以这样干

  1. 可添加 vertical-align:top. 这样就能对齐到容器里面了
  2. 添加空格 &nbsp; 到span里面,

这里还涉及到了 两个属性 line-height , vertical-align . 待我我后续仔细研究一下。

其实这些东西本身没有什么难道,在制定的标准中,都给予的说明,只是我们平时没有仔细去研读英文文档,也由于语言障碍,导致很难坚持去看英文文档。

例如: W3C 制定的css,html 的一些标准,ECMA 的 ECMAScript 标准等。

这里有些关于行高的一些标准。可供参考https://www.w3.org/TR/CSS2/visudet.html#propdef-line-height

还有 ECMA 的官网 http://ecma-international.org/

作者

Fat Dong

发布于

2022-04-28

更新于

2022-04-28

许可协议