CSS rem 单位的粒度如何?

How granular are CSS rem units?

我正在开发一个可扩展的 mobile/desktop 友好网站,使用 CSS rem 单位基于网站的平均视口大小。

我一直在为某些填充和边距将 rem 大小设置为低至 0.001rem,这在我的 Firefox 浏览器中工作正常...但它是否适用于所有现代浏览器?

我只是质疑使用 0.001rem 单位的能力,因为我在千分之一之前看到的最高粒度是百分之一的不透明度......例如 opacity:0.25

rem 单位可以降到多低?现代浏览器可以接受 0.00000001rem 值吗?

JSBin 上的一个简单示例显示 1.001 rem 的高度呈现为 18.0156 px,而 1.0001 rem 的高度呈现 18 px(这将与仅使用 1 rem).

相同

这意味着您可以精确到 3 位小数(至少在 Chrome 的桌面版本和常规字体大小下)。

我也试图写一个 JavaScript 测试来衡量准确性,但是 element.offsetHeight 它是一个整数,所以它对这件事没有用。除非有不同的方法以像素为单位测量元素尺寸(带小数位)。

编辑 1:根据 CSS 规范(参见 this and this),小数位数似乎没有限制。

但最后,我认为您受限于设备的像素密度。屏幕上的物理像素是不可分割的,因此所有计算的尺寸都四舍五入到最接近的整数。

"CSS theoretically supports infinite precision and infinite ranges for all value types; however in reality implementations have finite capacity. UAs should support reasonably useful ranges and precisions." w3.org

然而在实践中,我的结论是:在Chrome中,你可以得到到千分位 无限精度,直到小数部分的像素值低于 0.015.

编辑:一旦字体大小增加到更大的数字,原始结论就发现有缺陷。

自己测试一下(我用的是Element.getBoundingClientRect()):

var l = [
  "normal",
  "tens",
  "hundreds",
  "thousands",
  "ten-thousands",
  "hundred-thousands"
];
var o = document.getElementById("output");

for (var i = 0; i < l.length; i++) {
  o.innerHTML += l[i] + ": " + document.getElementById(l[i]).getBoundingClientRect().height + "px<br>";
}
body,
html {
  font-size: 1000px;
}
#normal {
  height: 1rem;
}
#tens {
  height: 1.1rem;
}
#hundreds {
  height: 1.01rem;
}
#thousands {
  height: 1.001rem;
}
#ten-thousands {
  height: 1.0001rem;
}
#hundred-thousands {
  height: 1.00001rem;
}
#output {
  font-size: 16px;
}
<div id="output"></div>
<br>
<div id="normal">Hello</div>
<div id="tens">Hello</div>
<div id="hundreds">Hello</div>
<div id="thousands">Hello</div>
<div id="ten-thousands">Hello</div>
<div id="hundred-thousands">Hello</div>

我的输出是:

normal: 1000px
tens: 1100px
hundreds: 1010px
thousands: 1001px
ten-thousands: 1000.09375px
hundred-thousands: 1000px

说明千分之一位(0.00001)超出了我的浏览器支持的精度

在进一步增加字体大小并尝试使用它之后,我无法找到一个值来生成小数部分 < 0.015 的像素值。 (尝试设置 font-size: 1556px1557px

最终,您的粒度为 1 个物理像素(从技术上讲,现代浏览器中的子像素,但出于本次讨论的目的,我将忽略它)。您可以根据 emrem 计算出不同的 像素值,甚至精确到几位数。然后你 运行 进入现实世界的问题,在渲染时,当浏览器最终四舍五入以适应可用像素时,小数精度将丢失,无论设备像素密度是相对于参考像素密度(96ppi) ).

本质上,这个参考像素是 1/96 英寸。因此 CSS 术语中的 1px 基本上表示 1/96" 在 96ppi。在像素密度较高的屏幕上(比如许多 Apple "retina" 屏幕的 326 ppi),会进行缩放以转换CSS 参考像素到物理像素。对于提到的视网膜显示,这个比例因子将是 ~3.4。所以如果你指定一个 CSS 规则来设置 10px,视网膜显示浏览器应该显示在34 个物理像素(假设没有其他 HTML 变化(即元元素)会改变显示行为)。由于这种缩放行为,元素的物理尺寸仍然是 10/96",这完全相同物理尺寸,就像在 96ppi 屏幕上呈现元素一样。

现在让我们将 emrem 添加到组合中。因此,让我们使用 10px 根元素字体大小的示例,并在 .001rem 的某些其他元素上进行声明。这意味着您正在尝试以 0.01 (10px * .001rem) 参考像素渲染此元素,这将转换为视网膜显示器中的 0.034 物理像素。您可以清楚地看到 rem 值 0.001 与在物理显示上产生显着差异至少相差一个数量级,因为在这种情况下 .01rem 将转换为 0.34 物理像素 - 当四舍五入显示比 "more precise" .001rem 规范。

所以我认为您定义的基于 rem 的 CSS 规则比绘制物理像素时在现实世界中实际所能容纳的规则要具体得多,除非您有一个非常高的根元素尺寸定义 and/or 你有一个像素密度比视网膜显示器大一个数量级的物理屏幕。我猜后一种情况不是真的。

仅仅因为 CSS 可以计算到 3 位小数的精度或其他任何东西,这并不意味着物理渲染可以以相同的精度级别进行。