不定宽元素的宽度计算

本文所讨论的中心点为: 如果"不定宽元素"内有"宽度为百分数的 img", 浏览器将如何计算容器和 img 的实际宽度.

注意:
1 除非提及,本文所有代码以 Chrome75 的效果为准.
2 本文中的"不定宽元素"是一个自造词,详见"不定宽元素"一节.
另外,本文是 stackoverflow 上这个讨论的总结,推荐直接去看原文.

举例:
有一个浮动元素(以下记为container):

1
<div class="container" style="float: left"></div>

container 中有一些图片, 当图片的 width 值为百分比时,浏览器如何计算 container 和 img 的宽度?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<style>
body {
margin: 0;
font-size: 0;
}
</style>
</head>
<body>
<div id="container" style="position:absolute;">
<!-- #img1的宽度为300x200px -->
<img id="img1" src="https://i.imgur.com/fH2hTRa.jpg" style="width: 100%" />
<!-- #img2的宽度为200x100px -->
<img id="img2" src="https://i.imgur.com/Ed0juok.jpg" style="width: 50%" />
</div>
</body>
</html>

puppeteer入门

puppeteer 是一个 Google 出品的 Node 库,可以用它来操纵 Chrome.
puppeteer 这个单词的发音为 [ˌpʌpɪˈtɪə], 意思是"操纵木偶的人".

安装

安装 puppeteer 时会自动下载 chrome,需要有全局代理.

1
yarn add puppeteer

如果无法下载 puppeteer, 可以在根目录下新建文件 .yarnrc, 填入如下内容:

1
puppeteer_download_host "https://storage.googleapis.com.cnpmjs.org"

例子

新建 index.js, 填入如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 载入puppeteer
const puppeteer = require('puppeteer');

// 打开浏览器
// launch方法返回一个Promise对象
puppeteer.launch({headless: false}).then(async browser => {
// 打开一个页面
const page = await browser.newPage();
// 打开百度
await page.goto('https://www.baidu.com');
await page.screenshot({path: 'baidu.png'});
// 关闭浏览器
// await browser.close();
});

最后,进入文件所在路径, 执行 node index.js 命令即可.

函数声明与函数表达式

偶然看到了一道题, 问如下代码中的console输出什么:

1
2
3
4
5
var a = 1;
(function a(){
a = 2;
console.log(a)}
)()

结果console输出的不是数值2,而是函数本身:

1
2
3
4
ƒ a(){
a = 2;
console.log(a)
}

(Android Chrome兼容)修复定位元素导致的地址栏上移

移动端浏览器的地址栏是可动的,用户向上滑动页面时, 地址栏也会向上移动,直到隐藏.
如果想固定地址栏,可以使用如下样式:

1
2
3
4
5
6
7
8
9
10
html {
height: 100%;
overflow: hidden;
}

body {
height: 100%;
margin: 0;
overflow-y: scroll;
}

表现

在chrome(android 73)中,上面这个办法可能会失效.
如果某个可滚动的绝对定位元素的尺寸和浏览器窗口一样大,可能会导致导航栏上移.
该bug仅能在android中复现, ios系统的chrome无此问题.

(Safari兼容)overflow和overflow-scrolling导致fixed元素不显示

当元素同时拥有overflow:scroll和-webkit-overflow-scrolling:touch两个属性时, 可能会导致内部的fixed元素无法显示.

表现

有如下Dom结构及CSS样式
html结构:

1
2
3
<div class="wrapper">
<div class="inner"></div>
</div>

css样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
.wrapper {
width: 300px;
height: 300px;
background-color: red;
}
.inner {
position: fixed;
top: 150px;
left: 150px;
width: 300px;
height: 300px;
background-color: yellow;
}

wrapper的背景色为红色.
inner是一个fixed元素, 背景色为黄色.
54279d8e.png

阻止滚动穿透

当滚动元素滚动到顶/底时, 如果其外层还有可滚动的元素,则会触发外层可滚动元素的滚动.
a.gif

这是个feature, 但有时这个feature会给开发者带来麻烦.
特别是safari, 如果某个可滚动元素设置了-webkit-overflow-scrolling: touch,滑动到头的时候经常会被卡住.

(动画效果)跟随下拉放大图像

a.gif

原理

监控用户touch事件, 根据移动距离修改图像的高度及缩放尺寸.
图像的放大要配合修改height和scale来进行,不能单独使用scale.因为缩放并不会占用文本流位置,这会导致图像覆盖下面的内容.

缓动函数(easing function)

网页设计经常会用到各种动画效果.
现实世界的大多数运动都是变速的.与变速运动相比,匀速运动就显得很生硬,给人一种不自然的感觉.

css可以用timing-function参数来实现变速运动.
但不是所有的动画都能用css来解决, 例如下拉刷新, 要用js来根据touchmove的距离来绘制动画效果.
这时就可以用缓动公式来实现各种动画效果.

-webkit-overflow-scrolling导致元素消失

在ios系统的浏览器中, 如果想让可滚动元素(例如有overflow: scroll属性的元素)带有弹性效果, 往往会给可滚动元素添加-webkit-overflow-scrolling: touch属性.
但这个属性有个bug, 可能会导致其内部的某些元素不显示.看起来就好象给元素加上了visibility:hidden一样.

为了修复这个bug, 需要给"某些"后代元素添加transform: translate3d(0,0,0)属性.

1
2
3
4
5
6
7
div {
overflow: scroll;
-webkit-overflow-scrolling: touch;
div {
transform: translate3d(0,0,0)
}
}

这里之所以称"某些",是因为无法确定到底应该加到哪些元素之上.
因为translate3d会产生很多副作用, 例如会改变元素的z-index, 要依具体情况而定.
需注意的是这个方法也不一定总是有效.