使用transform: scale避免模糊渲染

10
我正在使用 transform 属性将一个 div 进行缩放,但我想保持其子元素(具有 1px 宽度或高度)的大小不变。我通过反向缩放它们 0.5,期望的结果是一个 1px 的元素经过 2 倍缩放,再经过 0.5 缩放后应该回到 1px,但它们最终变成了模糊的 2px。
以下是缩放前的盒子:

.container {
    width: 200px;
    height: 200px;
    margin: 100px;
    background-color: #EEE;
    position: absolute;
}

.outline {
    position: absolute;
    background: #1899ef;
    z-index: 999999;
    opacity: 1 !important;
}

.outlineBottom, .outlineTop {
  width: 100%;
  height: 1px;
}

.outlineLeft, .outlineRight {
    height: 100%;
    width: 1px;
}

.outlineRight {
    right: 0px;
}

.outlineBottom {
    bottom: 0px;
}
<div class="container">
    <div class="outline outlineTop"></div>
    <div class="outline outlineRight"></div>
    <div class="outline outlineBottom"></div>
    <div class="outline outlineLeft"></div>
</div>

正如您所看到的,边缘处的元素是清晰、深色的1px蓝色。不过,在缩放之后,这个框看起来像这样:

.container {
    width: 200px;
    height: 200px;
    margin: 100px;
    background-color: #EEE;
    position: absolute;
    transform: scale(2);
}

.outline {
    position: absolute;
    background: #1899ef;
    z-index: 999999;
    opacity: 1 !important;
    transform: scale(.5);
}

.outlineBottom, .outlineTop {
  width: 100%;
  height: 1px;
  transform: scale(1,.5);
}

.outlineLeft, .outlineRight {
    height: 100%;
    width: 1px;
    transform: scale(.5,1);
}

.outlineRight {
    right: 0px;
}

.outlineBottom {
    bottom: 0px;
}
<div class="container">
    <div class="outline outlineTop"></div>
    <div class="outline outlineRight"></div>
    <div class="outline outlineBottom"></div>
    <div class="outline outlineLeft"></div>
</div>

这是来自我正在运行的Chrome 41.0.2272.89 Mac的后缩放渲染图

添加transform-3d(0, 0, 0)似乎没有帮助。找到了一个解决方案, 使用了zoom属性, 但由于zoom支持不好,我想避免使用它。添加filter: blur(0px);也似乎没有任何效果。

有人在聊天中提出,也许孩子们首先被缩放到.5,然后才加倍,导致它们被缩小到.5px,然后再从那里放大。 有没有办法确保它们呈现的顺序会先被放大到2px,然后再减半?尽管我不太确定,但我试图使用JS强制渲染顺序,但并不奇怪的是,这没有任何效果(尽管有趣的是,底部元素仍保持其原始颜色)。

如果失败了,还有其他解决方案吗? 我肯定不是唯一遇到这个问题的人。


有没有可能展示一下之前和之后的情况?现在问题不是很清楚。 - Adjit
缩放前/后?不确定我理解你的问题。 - Elliot Bonneville
是的,在缩放之前和之后。我并没有真正看到您目前拥有的框中存在任何问题-但这可能是因为我不清楚所需的效果。 - Adjit
@Adjit 希望这能为你解决问题。 - Elliot Bonneville
我很高兴你终于找到了解决方案,而且它离昨天的测试(近在咫尺,又似乎很遥远:P)。 - Alvaro Montoro
谢谢,@AlvaroMontoro,我也很感激昨天的帮助。 - Elliot Bonneville
1个回答

11
涉及到缩放元素的默认transform-origin。对于任何被转换的元素,它默认为50% 50%,但是当缩小1px值时,它必须在半个像素中心处居中缩放,从此渲染元素会出现问题。将transform-origin移动到每个项的相关极端点,您可以在此处查看其工作情况。
稍微玩一下就会发现,在任何维度上,如果缩放最终减少了一半像素,则缩放的元素会出现相同的模糊效果。

body {
    padding: 1em;
}

.container {
    width: 200px;
    height: 200px;
    margin: 100px;
    background-color: #EEE;
    position: absolute;
    transform: scale(2);
}

.outline {
    position: absolute;
    background: #1899ef;
    z-index: 999999;
    opacity: 1 !important;
}

.outlineBottom, .outlineTop {
    width: 100%;
    height: 1px;
    transform: scale(1, 0.5);
}

.outlineBottom {
    bottom: 0;
    transform-origin: 0 100%;
}

.outlineTop {
    transform-origin: 0 0;
}

.outlineLeft, .outlineRight {
    height: 100%;
    width: 1px;
    transform: scale(.5,1);
}

.outlineRight {
    right: 0px;
    transform-origin: 100% 0;
}

.outlineLeft {
    left: 0px;
    transform-origin: 0 0;
}
<div class="container">
    <div class="outline outlineTop"></div>
    <div class="outline outlineRight"></div>
    <div class="outline outlineBottom"></div>
    <div class="outline outlineLeft"></div>
</div>


啊哈,看起来很漂亮。谢谢! - Elliot Bonneville
没关系,我以前从未遇到过这个问题,但稍微尝试了一下后,我觉得这种情况有点合理……我认为这是一种特性而不是错误,因为在这些情况下你不希望猜测变换的起点! - RichieAHB
这是一个非常干净的解决方案。而且非常简单 :) - Alvaro Montoro
12
您能详细说明一下实际解决方案是什么吗?我看到您根据元素将“transform-origin”设置为不同的值,但我不太理解背后的思路。 - balu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接