为什么 `1vh` CSS 大小解析为屏幕上不同的像素大小
Why `1vh` CSS size resolve to different pixel size on screen
我有三个 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;
}
<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>
我截取了一些屏幕截图来演示调整大小期间实际发生的情况,如您所见 div
看起来高度不同,尽管它们都有 1vh
高度。
如果我在 javascript 中手动计算 1vh
并将其作为四舍五入的 '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`);
.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);
}
<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>
我的第一个想法是将浮点数四舍五入,但如果是这种情况,为什么 CSS 将单个浮点数四舍五入为三个不同的数字?
我的问题是为什么会发生这种情况,是否有任何纯粹的 CSS 解决方案来安全地使用视口大小并确保它们始终按预期显示?
我用 'px' 代替 'vh'
解决了这个问题
.container div{
background: #000;
width:100%;
height:6px;
}
由于'vh'是相对于视口的高度,因此在调整视口大小时它可能会波动。
• 'px'为绝对单位;但是 'vh' 是一个相对单位。
对我来说,它看起来像下面这样。结果相差 1px。这是因为 div 的计算高度不是整数,它是具有子像素值的浮点数。屏幕不能显示子像素。因此,如果浏览器决定舍入为更低或更高的值,则取决于屏幕上的位置。
您在此处 运行 遇到的问题不在 CSS 层中,而是在较低级别 - 在浏览器渲染引擎中,在某种程度上在物理显示硬件中。
why CSS rounds a single float number to three different numbers?
这是不对的 - CSS 是 的正确行为,并且为每组中的所有三个 div 生成完全相同的高度值.您可以通过检查开发工具中的元素并查看每个 div.
的计算高度 属性 来验证这一点
但是,该值不是完整像素,而是像素的一小部分。您遇到了计算机图形学中的一个经典问题 - 如何在具有离散像素的显示器上显示像素的分数?
简短回答 -- 你不能,非常好。这就是为什么当您调整它们的大小甚至在屏幕上四处移动时,这三个小数像素高度 div 最终会以 看起来 不同的高度呈现。这是渲染引擎尽最大努力使它们看起来相同,但结果不同。
您的 JS 手动 'rounding' 解决方案之所以有效,是因为它会将这些高度四舍五入为整个像素值!当像素值是圆形时,一切都更容易完美排列(在天真的情况下,假设 divs 之间没有小数像素填充,边距等)并且你不太可能看到差异.
试试吧!如果您删除 Math.round
或什至只是将 0.75
或其他内容添加到舍入结果中,您将看到与您的 JS 解决方案完全相同的问题,即使所有计算值显然相同。
同样,问题不在于值不同,而在于您的浏览器/硬件对它们的呈现方式不同。唯一通用的 'safe' 解决方法是确保这些值实际上是圆形像素值。
进入这个问题:
is there any pure CSS solution to safely use viewport sizes
就上述而言,不幸的是没有得到四舍五入的像素值结果。 CSS calc()
无法动态舍入结果。
作为一般性建议,如果您需要精确渲染细线等像素,响应式 CSS 可能不是您想要使用的工具。您可能想坚持使用静态像素值,但如果您真的需要动态的东西,并且随着视口大小的变化而增长和缩小,那么是的,您可能希望让 JS 参与进来以更好地控制渲染。
它很奇怪,但对我来说总是有效使用 vw 也用于高度和宽度。并尝试最小高度
我有三个 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;
}
<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>
我截取了一些屏幕截图来演示调整大小期间实际发生的情况,如您所见 div
看起来高度不同,尽管它们都有 1vh
高度。
如果我在 javascript 中手动计算 1vh
并将其作为四舍五入的 '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`);
.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);
}
<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>
我的第一个想法是将浮点数四舍五入,但如果是这种情况,为什么 CSS 将单个浮点数四舍五入为三个不同的数字?
我的问题是为什么会发生这种情况,是否有任何纯粹的 CSS 解决方案来安全地使用视口大小并确保它们始终按预期显示?
我用 'px' 代替 'vh'
解决了这个问题.container div{
background: #000;
width:100%;
height:6px;
}
由于'vh'是相对于视口的高度,因此在调整视口大小时它可能会波动。
• 'px'为绝对单位;但是 'vh' 是一个相对单位。
对我来说,它看起来像下面这样。结果相差 1px。这是因为 div 的计算高度不是整数,它是具有子像素值的浮点数。屏幕不能显示子像素。因此,如果浏览器决定舍入为更低或更高的值,则取决于屏幕上的位置。
您在此处 运行 遇到的问题不在 CSS 层中,而是在较低级别 - 在浏览器渲染引擎中,在某种程度上在物理显示硬件中。
why CSS rounds a single float number to three different numbers?
这是不对的 - CSS 是 的正确行为,并且为每组中的所有三个 div 生成完全相同的高度值.您可以通过检查开发工具中的元素并查看每个 div.
的计算高度 属性 来验证这一点但是,该值不是完整像素,而是像素的一小部分。您遇到了计算机图形学中的一个经典问题 - 如何在具有离散像素的显示器上显示像素的分数?
简短回答 -- 你不能,非常好。这就是为什么当您调整它们的大小甚至在屏幕上四处移动时,这三个小数像素高度 div 最终会以 看起来 不同的高度呈现。这是渲染引擎尽最大努力使它们看起来相同,但结果不同。
您的 JS 手动 'rounding' 解决方案之所以有效,是因为它会将这些高度四舍五入为整个像素值!当像素值是圆形时,一切都更容易完美排列(在天真的情况下,假设 divs 之间没有小数像素填充,边距等)并且你不太可能看到差异.
试试吧!如果您删除 Math.round
或什至只是将 0.75
或其他内容添加到舍入结果中,您将看到与您的 JS 解决方案完全相同的问题,即使所有计算值显然相同。
同样,问题不在于值不同,而在于您的浏览器/硬件对它们的呈现方式不同。唯一通用的 'safe' 解决方法是确保这些值实际上是圆形像素值。
进入这个问题:
is there any pure CSS solution to safely use viewport sizes
就上述而言,不幸的是没有得到四舍五入的像素值结果。 CSS calc()
无法动态舍入结果。
作为一般性建议,如果您需要精确渲染细线等像素,响应式 CSS 可能不是您想要使用的工具。您可能想坚持使用静态像素值,但如果您真的需要动态的东西,并且随着视口大小的变化而增长和缩小,那么是的,您可能希望让 JS 参与进来以更好地控制渲染。
它很奇怪,但对我来说总是有效使用 vw 也用于高度和宽度。并尝试最小高度