为什么`1vh` CSS 大小解析为屏幕上不同的像素大小

Mak*_*kan 7 html javascript css viewport responsive

我有三个div相同高度等于 1vh`。

我的问题是它们在屏幕上以不同的像素大小出现。有时它们看起来相等但有时不相等,特别是在调整视口大小后发生。请运行代码段查看。

.samples {
  display:flex;
}

.container{
  display:flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  margin:10px 20px;
  height: 20vh;
  width:20vh;
}

.container div{
  background: #000;
  width:100%;
}

#set1 div{
  height:.3vh;
}

#set2 div{
  height:.7vh;
}

#set3 div{
  height:.9vh;
}

#set4 div{
  height:1.1vh;
}
Run Code Online (Sandbox Code Playgroud)
<div class = "samples">

  <div class="container" id="set1" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set2" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set3" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
    <div class="container" id="set4" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
</div>
<div>
<h4>Above are four samples, each sample includes 3 identical div.</h4>
<h4>But depends on your screen size you may not see what expected</h4>
</div>
Run Code Online (Sandbox Code Playgroud)

我截取了一些屏幕截图来演示调整大小期间真正发生的事情,因为div尽管它们都有1vh高度,但您可以看到具有不同高度的外观。

在此处输入图片说明

如果我1vh在 javascript 中手动计算并将其作为四舍五入的“px”注入 CSS,那么它可以完美运行。(在代码片段中,我使用了 .3、.7、.9、1.1 vh 进行演示)

  
  const set1Height = Math.round(document.documentElement.clientHeight * .3 / 100);
  const set2Height = Math.round(document.documentElement.clientHeight * .7 / 100);
  const set3Height = Math.round(document.documentElement.clientHeight * .9 / 100);
  const set4Height = Math.round(document.documentElement.clientHeight * 1.1 / 100);
  

  document.documentElement.style.setProperty("--set1-height", `${set1Height}px`);
  document.documentElement.style.setProperty("--set2-height", `${set2Height}px`);
  document.documentElement.style.setProperty("--set3-height", `${set3Height}px`);
  document.documentElement.style.setProperty("--set4-height", `${set4Height}px`);
  
Run Code Online (Sandbox Code Playgroud)
.samples {
  display:flex;
}

.container{
  display:flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  margin:10px 20px;
  height: 20vh;
  width:20vh;
}

.container div{
  background: #000;
  width:100%;
}

#set1 div{
  height: var(--set1-height);
}

#set2 div{
  height: var(--set2-height);
}

#set3 div{
  height: var(--set3-height);
}

#set4 div{
  height: var(--set4-height);
}
Run Code Online (Sandbox Code Playgroud)
<div class = "samples">

  <div class="container" id="set1" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set2" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set3" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
    <div class="container" id="set4" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
</div>
<div>
<h4>Here, after calculating heights and round them to `px` they looks identical</h4>
</div>
Run Code Online (Sandbox Code Playgroud)

我的第一个想法是四舍五入浮点数导致这个,但如果是这种情况,为什么 CSS 将单个浮点数四舍五入为三个不同的数字?

我的问题是为什么会发生这种情况,是否有任何纯 CSS 解决方案可以安全地使用视口大小并确保它们始终按预期显示?

dav*_*wil 7

您在这里遇到的问题不在 CSS 层,而是在较低级别 - 在浏览器渲染引擎中,以及在某种程度上物理显示硬件。

为什么 CSS 将单个浮点数四舍五入为三个不同的数字?

这是不对的-在CSS正常运作,并产生准确的每组三个div的同一高度值。您可以通过检查开发工具中的元素并查看每个 div 的计算高度属性来验证这一点。

但是,该值不是整个像素,而是像素的一小部分。您遇到了计算机图形学中的一个经典问题 - 如何在具有离散像素的显示器上显示像素的一小部分?

简短的回答 -你不能,完美。这就是为什么当您调整它们的大小甚至在屏幕上移动它们时,这三个分数像素高度 div 最终呈现出看起来不同的高度。渲染引擎尽最大努力使它们看起来相同,结果却各不相同。

您在 JS 中手动“舍入”解决方案有效的原因是,它将这些高度舍入为整个像素值!当像素值是圆形时,一切都更容易完美排列(在天真的情况下,假设 div 之间没有小数像素填充、边距等),并且您不太可能看到差异。

尝试一下!如果您在舍入结果中删除Math.round或什至简单地添加0.75或某些内容,您将看到与您的 JS 解决方案完全相同的问题,即使所有计算值显然都相同。

同样,问题不在于值不同,而是浏览器/硬件对它们的呈现方式不同。唯一普遍“安全”的解决方法是确保这些值实际上是圆形像素值。

引出这个问题:

是否有任何纯 CSS 解决方案可以安全地使用视口大小

就上述而言,获得四舍五入的像素值结果,不幸的是没有。使用 CSScalc()或其他方式无法动态舍入结果。

作为一般建议,如果您需要将细线等精确渲染到像素,那么响应式 CSS 可能不是您想要使用的工具。您可能想坚持使用静态像素值,但如果您真的需要在更改视口大小时动态并增长和缩小,那么是的,您可能希望使用 JS 来更好地控制渲染。