Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

吃一堑长一智系列:你知道 HTML 的默认背景色是什么吗 #25

Open
soda-x opened this issue Mar 18, 2021 · 1 comment
Open
Assignees
Labels
gravity bundless 解决方案

Comments

@soda-x
Copy link
Owner

soda-x commented Mar 18, 2021

html

TLDR;

教条一:不管是 html 元素还是 body 元素,它们都是透明的。
教条二:如需全局背景色,请将背景色设置于 body 元素上。
教条三:UI Library 作者需要设置元素的背景色,同时最好在 body 元素上设置好基调色。
教条四:习惯设置背景色是个好习惯,嗯,你是个好孩子

既然事情总结的如此简单,那还有必要专门写一篇文章吗?! 答案是:有,经过测试这里还有不少坑


名词解释

Riddle: 一个前端代码片段分享平台,支持但不限于 React 代码的在线编辑和演示,当前 Riddle 演示功能的实现依托于嵌入的 Gravity iframe,即 Riddle 加载到实例代码后会发消息给 Gravity,而 Gravity 会通过约定的消息拿到代码后开始编译,并加载对应的入口文件,最终由 Gravity 实现预览。

Gravity: 基于浏览器技术的 bundless 方案。

背景

前一阵子,Riddle 联合 CloudIDE 的第一期合作发布,其中有一项变更是将原先的 Light 模式升级到了 Dark 模式。升级之后遭到了用户的投诉,原因是 Dark 模式影响了他们的展现。

反馈

起先我是感到委屈的,因为非常确定在完成编译之后我没有给嵌入的 iframe 设置颜色。第一反应就是,难道 HTML 默认是透明的,不是白色的?!内心飘过三个字。

出了问题肯定是要刨根问底的,那接下来就是弄明白时间。

探索

探索第一步:验证是透明的,并尽可能遍历应用场景防再踩坑

编写测试案例。

注明:
Body区域: Body 以内,后简写为 B
HTML区域: HTML 以内,后简写为 H
ViewPort区域: 整个可视区域,后简写为 V
Drag区域: 由拖拽而展现出来的区域(通常是页面的最上端和最下端由于拖拽而展现区域),后简写为 D

过程一: 单一 html

(1) 没有设置背景色 html-none-body-none
(2) html 未设置背景色 body 设置红色 html-none-body-red
(3) html 设置黄色 body 未设置颜色 html-yellow-body-none
(4) html 设置黄色 body 设置红色 html-yellow-body-red

直接进入总结环节:

案例 chrome 桌面 chrome 移动 Safari 桌面 Safari 移动
html-none-body-none B: 白 H: 白 V: 白 D: 白 B: 白 H: 白 V: 白 D: 白 B: 白 H: 白 V: 白 D: 白 B: 白 H: 白 V: 白 D: 白
html-none-body-red B: 红 H: 红 V: 红 D: 红 B: 红 H: 红 V: 红 D: 红 B: 红 H: 红 V: 红 D: 红 B: 红 H: 红 V: 红 D: 红
html-yellow-body-none B: 黄 H: 黄 V: 黄 D: 黄 B: 黄 H: 黄 V: 黄 D: 黄 B: 黄 H: 黄 V: 黄 D: 黄 B: 黄 H: 黄 V: 黄 D: 黄
html-yellow-body-red B: 红 H: 黄 V: 黄 D: 黄 B: 红 H: 黄 V: 黄 D: 红 B: 红 H: 黄 V: 黄 D: 红 B: 红 H: 黄 V: 黄 D: 红

这里我们发现

1. body 的颜色优先级为 body -> html
2. html 的颜色优先级为 html -> body
3. viewport 的颜色优先级为 html -> body
4. drag 区域颜色在同时设置 html 和 body 背景色时存在兼容性问题。 如果移动为先的思路,优先级应该是 body > html

过程二 - 嵌套 iframe

讨论完了第一 p,那我们再来看看第二 p,嵌套 iframe 也是一种非常常见的场景

注明:以下颜色记录均为 iframe

(1) html-none-body-none 嵌套 html-none-body-none 的 iframe
(2) html-none-body-red 嵌套 html-none-body-none 的 iframe
(3) html-none-body-none 嵌套 html-yellow-body-red 的 iframe

案例 (父/子) chrome 桌面 chrome 移动 Safari 桌面 Safari 移动
html-none-body-none/html-none-body-none B: 白 H: 白 V: 白 D: 白 B: 白 H: 白 V: 白 D: 白 B: 白 H: 白 V: 白 D: 白 B: 白 H: 白 V: 白 D: 白
html-none-body-red/html-none-body-none B: 红 H: 红 V: 红 D: 红 B: 红 H: 红 V: 红 D: 红 B: 红 H: 红 V: 红 D: 红 B: 红 H: 红 V: 红 D: 红
html-none-body-none/html-yellow-body-red B: 红 H: 黄 V: 黄 D: / B: 红 H: 黄 V: 黄 D: 白 B: 红 H: 黄 V: 黄 D: 白 B: 红 H: 黄 V: 黄 D: 白

综合第一 P,这里我们发现:

1. html,body,viewport,drag 区域默认是透明的
2. iframe 中的 drag 区域是透明的,这里和 1 中有差别

过程三 - 嵌套 iframe 的疑惑表现

这里产生困惑,iframe 区域的 drag 区域如何设置颜色呢

(1) html-none-body-none 嵌套 html-yellow-body-red 的 iframe,且设置 iframe 的 background-color: green

案例 (父/子) chrome 桌面 chrome 移动 Safari 桌面 Safari 移动
html-none-body-none/html-yellow-body-red B: 红 H: 黄 V: 黄 D: / B: 红 H: 黄 V: 黄 D: 绿 B: 红 H: 黄 V: 黄 D: 绿 B: 红 H: 黄 V: 黄 D: 绿

从此可以得出

iframe 的 drag 区域颜色由 iframe 的颜色决定,当未设定时,其就是透明的。

过程四 - background-color 和 background-image 之间的影响

(1) html 设置黄色和图梵高星空 body 设置红色和图梵高睡莲 html-yellow-image(记为星)-body-red-image(记为莲)

案例 chrome 桌面 chrome 移动 Safari 桌面 Safari 移动
html-yellow-星-body-red-莲 B: 莲 H: 星 V: 星 D: 黄 B: 莲 H: 星 V: 星 D: 红 B: 莲 H: 星 V: 星 D: 星 B: 莲 H: 星 V: 星 D: 红
html-yellow-body-red-莲 B: 莲 H: 黄 V: 黄 D: 黄 B: 莲 H: 黄 V: 黄 D: 红 B: 莲 H: 黄 V: 黄 D: 红 B: 莲 H: 黄 V: 黄 D: 红
html-none-body-red-莲 B: 莲 H: 莲 V: 莲 D: 红 B: 莲 H: 莲 V: 莲 D: 红 B: 莲 H: 莲 V: 莲 D: 莲 B: 莲 H: 莲 V: 莲 D: 红

(2) 嵌套场景 html-none-body-none/html-yellow-星-body-red-莲

注明:以下颜色记录均为 iframe

案例 (父/子) chrome 桌面 chrome 移动 Safari 桌面 Safari 移动
html-none-body-none/html-yellow-星-body-red-莲 B: 莲 H: 星 V: 星 D: / B: 莲 H: 星 V: 星 D: 白 B: 莲 H: 星 V: 星 D: 白 B: 莲 H: 星 V: 星 D: 白

从此可以得出

1. 当设置 background-image 时,兼容性问题依旧存在,html 的优先级为 html > body,body 的优先级为 body > html
2. viewport 区域的的优先级为 html > body,这里的意思是如果未对 html 做相关背景色或者背景图设置,viewport 的将被 body 的 html 颜色或者背景图填充
3. 嵌套模式下,drag 区域依旧为透明色
4. 由于存在兼容性问题需要谨慎设置背景图平铺

探索第三步:W3C 求理论

在做完上面的探索之后,其实内心有了个想法就是想要确定下,我们的标准到底是怎么样的。

于是我在 W3C 上找到了一些答案 -》 W3C

The document canvas is the infinite surface over which the document is rendered.

If the canvas background is not opaque, the canvas surface below it shows through. The texture of the canvas surface is UA-dependent (but is typically an opaque white).

The background of the root element becomes the canvas background and its background painting area extends to cover the entire canvas. However, any images are sized and positioned relative to the root element as if they were painted for that element alone. (In other words, the background positioning area is determined as for the root element.) The root element does not paint this background again, i.e., the used value of its background is transparent.

For documents whose root element is an HTML HTML element or an XHTML html element [HTML]: if the computed value of background-image on the root element is none and its background-color is transparent, user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY or XHTML body child element. The used values of that BODY element’s background properties are their initial values, and the propagated values are treated as if they were specified on the root element. It is recommended that authors of HTML documents specify the canvas background for the BODY element rather than the HTML element.

这里其实可以总结为一个图:

模型

但是这里要表达的是 W3C 制定的标准和浏览器厂商的实现是有一定的差距的,这里存在不少兼容性的问题。同时如果认真把文章读下来,或者有认真比对 DEMO 展现的话,这里其实有一个很迷的东西(viewport),这个概念在 W3C 的表述里是不存在的,在标准中更加倾向于把 viewport 理解为 canvas ,但是我们在测试过程中能比较明显感觉到 canvas 的表现并不能简简单单的把 viewport 画上等号 (典型案例:在移动端 html-yellow-body-red,如果我们限制了 html 元素的高度,但是可视区域依旧是会被渲染为黄色,但是可拖拽区显示为红色,这就非常不符合 canvas 层的定义,反而 chrome 的 pc 端反而更加符合标准)。

乱入 CSS 属性 mix-blend-mode

在翻阅资料的时候,看到了一个有趣的且容易掉坑的 CSS 属性 - mix-blend-mode,该CSS 属性描述了元素的内容应该与元素的直系父元素的内容和元素的背景如何混合。

这里为了说明问题,我们就讲一个 mix-blend-mode: difference,difference 的意思是取反,即反色。举例我们现在有一个色彩 色值为 rgb(255, 0, 255),紫色,那它在白色的反色就是 rgb(0, 255, 0) 绿色。

  .div {color: rgb(255, 0, 255);mix-blend-mode: difference;font-weight: bold;font-size: 30px}
  <div class="div">文字颜色</div>
案例 chrome 桌面 chrome 移动 Safari 桌面 Safari 移动
html-none-body-none 绿 绿 绿

这里其实我们预期的是得到的是 粉,因为背景色为透明色,而 chrome 移动 Safari 桌面 Safari 移动显然是以白色为基础的反色了。

嵌套 iframe

注明一下颜色为,iframe 内文字颜色

案例 chrome 桌面 chrome 移动 Safari 桌面 Safari 移动
html-none-body-none

这里和上诉单纯的 html 一比较发现存在的差异,iframe 中的文字清一色的变为了粉色。

综上总结:

- mix-blend-mode: difference 兼容性存在很大的问题,甚至存在 position 的设定也会影响具体的表现。那如何避免呢,方案很简单,对自己所需的元素设置背景色,不要依赖外界。

如何设置浏览器底色

Firefox 可以很轻松设置,CMD + ,,相信你可以很快找到。

为什么会有这种需求呢,我想了下,确实有这种场景,比如现在的 Dark Mode 并没有真正意义上的实现 Dark Mode,因为我们没法控制软件层的底色,根据这次测试来看,即使你操作系统设置了 Dark Mode,但是你的软件的背景色还是白色。所以在一些特殊场景下,你还是能看到那个白。

这里也衍生出了一种网站设计的流派,原先我也不太清楚,那就是透明派,比如 vimeo。我觉得初衷是好的,因为他们想要尊重用户的选择(我猜的),但是事实上,这绝对不是一个明智的方式,因为用户的偏好很可能违背你的设计(假设设计设计了 Light Mode,正常黑色字体,而如果用户偏好 Dark Mode,那么用户就啥也看不到了),因此我对透明的制作思路保留我自己的看法。

总结

教条一:不管是 html 元素还是 body 元素,它们都是透明的。
教条二:如需全局背景色,请将背景色设置于 body 元素上。
教条三:UI Library 作者需要设置元素的背景色,同时最好在 body 元素上设置好基调色。
教条四:习惯设置背景色是个好习惯,嗯,你是个好孩子

以下是所有的测试 demo

test.zip

@soda-x soda-x self-assigned this Mar 18, 2021
@soda-x soda-x added the gravity bundless 解决方案 label Mar 18, 2021
@0326
Copy link

0326 commented Mar 22, 2021

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gravity bundless 解决方案
Projects
None yet
Development

No branches or pull requests

2 participants