通过 translate3d 基于 Webkit 的模糊/扭曲文本后期动画

发布于 2024-11-16 18:08:48 字数 553 浏览 3 评论 0 原文

此问题似乎会影响所有基于 WebKit 的浏览器,包括 iPhone。

首先是一些背景知识。我正在开发的网站使用基于 JavaScript 的“滑块”动画。

我正在使用 -webkit-transform:translate3d 来“增强”实际动画。与基于 JavaScript 的方法相反,使用此方法时,一旦内容被动画化,文本就会变得完全模糊。这在 iPhone 上尤其明显。

我看到的一些解决方法是删除相对定位(我这样做了),并添加了 -webkit-font-smoothing: antialiased 规则(我也这样做了)。这两项改变都没有产生丝毫影响。

我能够在没有模糊文本的情况下正常工作的唯一方法是使用常规 JavaScript 进行动画并完全绕过 translate3d。我更喜欢使用 translate3d 因为它在支持 WebKit 的设备上执行速度快得多,但我一生都无法弄清楚为什么它会影响这样的文本一个糟糕的方法。

任何建议或解决方案将不胜感激。

This issue appears to affect all WebKit-based browsers, including the iPhone.

First some background. The site I'm working on uses a JavaScript-based 'slider' animation.

I'm using -webkit-transform: translate3d to 'power' the actual animation. When using this method, as opposed to a JavaScript-based method, the text becomes all blurry once the content has been animated. This is especially noticeable on the iPhone.

A few workarounds I saw were to remove an relative positioning, which I did, and to add a rule for -webkit-font-smoothing: antialiased, which I also did. Neither change made the slightest difference.

The only way I could make this work properly without blurry text was to use regular JavaScript for the animation and bypass the translate3d altogether. I'd prefer to use translate3d because it performs much faster on WebKit-enabled devices, but for the life of me I cannot figure out why it is affecting the text in such a poor way.

Any suggestions or solutions would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

若言繁花未落 2024-11-23 18:08:48

这些似乎都不适合我,但我找到了一个稍微肮脏的解决方案,它似乎可以解决问题:

top: 49.9%;
left: 49.9%;
-webkit-transform: translate(-50.1%, -50.1%);
transform: translate(-50.1%, -50.1%);

None of these seem to have worked for me but I've found a slightly dirty solution which seemed to do the trick:

top: 49.9%;
left: 49.9%;
-webkit-transform: translate(-50.1%, -50.1%);
transform: translate(-50.1%, -50.1%);
初心 2024-11-23 18:08:48

我在 Ken Avila 的帖子中描述了完全相同的问题:CSS:转换:翻译(-50%,-50%)使文本模糊

问题当然是我使用了transform:translate(-50%,-50%)这使得我的居中内容变得模糊,但仅在 osx 上的 safari 中。

不仅文本变得模糊,整个内容(包括图像)也变得模糊。
我继续阅读: http://keithclark.co.uk/articles/ gpu-text-rendering-in-webkit/
“模糊”是由于元素在非整数边界上渲染造成的。

我还发现,我可以避免在这篇文章的居中水平部分上使用变换平移: https://coderwall.com/p/quutdq/how-to-really-center-an-html-element-via-css-position-absolute-fixed - 唯一的缺点是我必须引入一个包装器。

我发现使用transform:translateY(-50%)不会产生任何“模糊”,可能是因为我的元素有一个设定的高度,因此不会最终在非整数边界上渲染。

因此我的解决方案最终是这样的:

.wrapper {
  position: fixed;
  left: 50%;
  top: 50%;
}
.centered {
  position: relative;
  left: -50%;
  -webkit-transform: translateY(-50%);
  -ms-transform: translateY(-50%);
  transform: translateY(-50%);
}
<div class="wrapper">
  <div class="centered">
    Content
  </div>
</div>

I had the exact same problem described in Ken Avila's post: CSS: transform: translate(-50%, -50%) makes texts blurry

The problem was of course that I used transform: translate(-50%, -50%) which made my centered content become blurry, but only in safari on osx.

It is not only the text that becomes blurry, but the entire content, including images.
I read on: http://keithclark.co.uk/articles/gpu-text-rendering-in-webkit/
that the "blurryness" is due to that the element is rendered on a non-integer boundary.

I also discovered that I could avoid using transform translate on the horizontal part of my centering from this post: https://coderwall.com/p/quutdq/how-to-really-center-an-html-element-via-css-position-absolute-fixed -The only minus was that I had to introduce a wrapper.

I discovered that using transform: translateY(-50%) didn't create any "bluryness", maybe because my element has a set height and thus does not end up rendering on a non-integer boundary.

My solution therefore ended up like this:

.wrapper {
  position: fixed;
  left: 50%;
  top: 50%;
}
.centered {
  position: relative;
  left: -50%;
  -webkit-transform: translateY(-50%);
  -ms-transform: translateY(-50%);
  transform: translateY(-50%);
}
<div class="wrapper">
  <div class="centered">
    Content
  </div>
</div>

猫卆 2024-11-23 18:08:48

正如@Robert 上面提到的,有时添加背景会有所帮助,但并非总是如此。

因此,对于 Dmitry 添加的示例,这不是您必须做的唯一事情:除了后台之外,您必须告诉浏览器显式使用正确的抗锯齿功能,因此,有一个固定的 Dmitry 示例: http://jsfiddle.net/PtDVF/1/

您需要在需要修复抗锯齿的块周围(或为其)添加这些样式:

background: #FFF; /* Or the actual color of your background/applied image */
-webkit-font-smoothing: subpixel-antialiased;

As @Robert mentioned above, sometimes adding background helps, but not always.

So, for the example Dmitry added that's not the only thing you must do: except from the background, you must tell browser to explicitly use the proper anti-aliasing, so, there is a fixed Dmitry's example: http://jsfiddle.net/PtDVF/1/

You need to add these styles around (or for the) blocks where you need to fix the anti-aliasing:

background: #FFF; /* Or the actual color of your background/applied image */
-webkit-font-smoothing: subpixel-antialiased;
苍暮颜 2024-11-23 18:08:48

您要翻译的元素必须能被偶数整除。

重要的是,无论您尝试移动一半的元素,其宽度和高度都可以被二整除。与响应式图像非常相似,物体可以移动 50% 而无需分割像素。

宽度为 503px、高度为 500px 的 div 会导致模糊,无论您以何种方式移动它,或者使用 TranslateX 或 Y 时移动多少。使用 Transform,它利用 GPU 图形加速器,结果应该非常清晰、平滑边缘。设置 box-sizing: border-box; 也可能是个好主意。确保计算的宽度包括填充和边框。

使用百分比宽度时要小心。如果它与屏幕尺寸相关,则任何其他屏幕像素宽度都会导致这种模糊。

Elements you are translating must be divisible by two with even numbers.

It's important that whatever element you're trying to shift over by half is divisible by two for both it's width and height. Very similar to the responsive images, when things can be moved by 50% without splitting pixels.

A div with a width of: 503px and a height of 500px will cause blurring, no matter which way you move it or by how much when using translateX or Y. Using transform, it utilizes GPU graphics accelerator which should result is very crisp, smooth edges. It might also be a good idea to set box-sizing: border-box; to ensure calculated widths include padding and borders.

Be careful when using percentage widths. If it's relative to screen size, ever other screen pixel width will cause this blur.

泪意 2024-11-23 18:08:48

我通过在任何动画发生之前向元素添加 translate3d 样式来解决此问题。

-webkit-transform: translate3d(0,0,0); 

I fixed this problem by adding a translate3d style to the element before any animation occurs.

-webkit-transform: translate3d(0,0,0); 
凝望流年 2024-11-23 18:08:48

这是最好的解决方案
translateX(calc(-50% + 0.5px))

This is the best solution
translateX(calc(-50% + 0.5px))

千秋岁 2024-11-23 18:08:48

可能是最简单的解决方案:

transform: translate(-50%, -50%) scale(2); 
zoom:.5;

缩放负责将像素值四舍五入为整数

Probably the easiest solution:

transform: translate(-50%, -50%) scale(2); 
zoom:.5;

Scale-and-zoom takes care of rounding the pixel values to full numbers

不打扰别人 2024-11-23 18:08:48

使用CSS“round”函数解决老问题的新解决方案。

为了确保翻译后的块在整数坐标上渲染(假定父级已经在整数坐标上),我们可以使用“圆”功能。

居中示例:

left: 50%;
top: 50%
translate: translateX(round(-50%, 1px), round(-50%, 1px));

ref: https://developer.mozilla.org/en -US/docs/Web/CSS/round

A new solution to an old problem using the CSS "round" function.

To ensure that the translated block is rendered on integer coordinates (given that the parent is already on integer coordinates), we can use the "round" function.

centering example:

left: 50%;
top: 50%
translate: translateX(round(-50%, 1px), round(-50%, 1px));

ref: https://developer.mozilla.org/en-US/docs/Web/CSS/round

゛清羽墨安 2024-11-23 18:08:48

这些答案都不适合我,但使用却

display: inline-table;

成功了

None of these answers worked for me but using

display: inline-table;

did the trick

剩一世无双 2024-11-23 18:08:48

Neil Taylor 的解决方案是最好的,但它仍然可以改进:

transform:translateX(-50%)translateX(.5px)

这样它有 2 个优点:

  • 它可以在像 IE11 这样的蹩脚浏览器中工作(不支持翻译内的计算)
  • 它仅在解析时计算,而不是每次浏览器计算时计算。

Neil Taylor's solution was the best, but it can still be improved:

transform: translateX(-50%) translateX(.5px)

This way it has 2 advantages:

  • It works in crappy browsers like IE11 (which doesn't support calc inside translate)
  • It only calculates at parse time, not every time the browser evaluates.
回眸一笑 2024-11-23 18:08:48

我希望这是将对象居中到屏幕的正中心。
变换时会发生模糊:translate(-50%,-50%);

因此,

position: absolute;
margin:0;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);

我尝试使用 javascript 将样式注入到元素中。 (React.js)

const node = ReactDOM.findDOMNode(this);
var width = node.offsetWidth;
var height = node.offsetHeight;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;

style={
    left : (windowWidth/2) - (this.state.width/2) + 'px',
    right:  (windowWidth/2) - (this.state.width/2) + 'px',
    top: (windowHeight/2) - (this.state.height/2) + 'px',
    bottom: (windowHeight/2) - (this.state.height/2) + 'px'
}

通过 javascript 样式将样式注入到元素中,

例如。

export default class Dialog extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            width: '0px',
            height: '0px'
        };
    }

    setWidthhandHeight(node){
        if (this.state.width !== node.offsetWidth) {
            this.setState({
                width: node.offsetWidth,
                height: node.offsetHeight
            });
        }
    }

    componentDidMount() {
        this.setWidthhandHeight(node);
    }

    render() {
        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;
        return (
            <dialog className={this.props.className + " dialog"}
                    style={{
                        left : (windowWidth/2) - (this.state.width/2) + 'px',
                        right:  (windowWidth/2) - (this.state.width/2) + 'px',
                        top: (windowHeight/2) - (this.state.height/2) + 'px',
                        bottom: (windowHeight/2) - (this.state.height/2) + 'px'
                    }}>
                {this.props.title ? (
                    <header><span>{this.props.title}</span></header>
                    )
                    : null
                }
                {this.props.children}
            </dialog>
        );
    }
}

I hope this is about centering the object into exact center of the screen.
Blurring happens with the transform: translate(-50%,-50%);

so instead doing

position: absolute;
margin:0;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);

I tried injecting style in to element using javascript. (React.js)

const node = ReactDOM.findDOMNode(this);
var width = node.offsetWidth;
var height = node.offsetHeight;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;

style={
    left : (windowWidth/2) - (this.state.width/2) + 'px',
    right:  (windowWidth/2) - (this.state.width/2) + 'px',
    top: (windowHeight/2) - (this.state.height/2) + 'px',
    bottom: (windowHeight/2) - (this.state.height/2) + 'px'
}

inject style into element by javascript style

Eg.

export default class Dialog extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            width: '0px',
            height: '0px'
        };
    }

    setWidthhandHeight(node){
        if (this.state.width !== node.offsetWidth) {
            this.setState({
                width: node.offsetWidth,
                height: node.offsetHeight
            });
        }
    }

    componentDidMount() {
        this.setWidthhandHeight(node);
    }

    render() {
        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;
        return (
            <dialog className={this.props.className + " dialog"}
                    style={{
                        left : (windowWidth/2) - (this.state.width/2) + 'px',
                        right:  (windowWidth/2) - (this.state.width/2) + 'px',
                        top: (windowHeight/2) - (this.state.height/2) + 'px',
                        bottom: (windowHeight/2) - (this.state.height/2) + 'px'
                    }}>
                {this.props.title ? (
                    <header><span>{this.props.title}</span></header>
                    )
                    : null
                }
                {this.props.children}
            </dialog>
        );
    }
}
你的笑 2024-11-23 18:08:48

将容器中应用变换平移属性的任何元素的垂直边距(顶部边距或底部边距)或高度减少 1 个像素。

Reduce the vertical margin(margin-top or margin-bottom) or height of any element in the container on which transform translate property is being applied by just 1 pixel.

独木成林 2024-11-23 18:08:48

将 Chrome 的缩放重置为 100% 对我来说很有效。

Resetting Chrome's zoom to 100% worked for me.

情泪▽动烟 2024-11-23 18:08:48

如果百分比用于动画,如果我们还考虑它的性能,那么它仍然可以接受,但是当您不使用 translate 进行动画时,它会有所不同,因为文本总是模糊的。

使用百分比时,可能会出现小数,例如 0.5px文本模糊的原因。在我的实验中,使用 translate(0.5px, 0.5px) 会使文本非常模糊,因此您应该避免使用 0.3px <=> 之间的小数。 0.7px0.2px 和 0.8px 仍然可以接受。

我的建议是使用 JavaScript 并将百分比转换为圆角像素以对元素进行动画处理,如果使用 translate 来定位元素,则使用像素而不是百分比。

另一种选择是使用lefttop设置带有百分比的初始位置,然后使用transform:使用目标位置的像素翻译(),并仅使用transition-property:transform;变换进行动画处理

If the percentage is used for animation it still acceptable if we also consider it's performance, but when you're not using translate for animation it would different because the text will always blurry.

When using percentage it's possible of having fractional number like 0.5px and that the reason why the text was blurry. On my experiment using translate(0.5px, 0.5px) would make the text very blurry, so you should avoid fractional number between 0.3px <=> 0.7px while 0.2px and 0.8px still acceptable.

My suggestion is using JavaScript and turn the percentage into rounded pixel for animating the element, and using pixel instead of percentage if translate is being used for positioning the element.

The other alternative is using left and top to set the initial position with percentage then use transform: translate() with pixel for the target position and animate the transform only with transition-property: transform;

天涯离梦残月幽梦 2024-11-23 18:08:48

对于替代解决方案,请尝试:

-webkit-text-stroke: 0.35px

For an alternative solution try:

-webkit-text-stroke: 0.35px
云之铃。 2024-11-23 18:08:48

使用 zoom 为我解决了这个问题。

我刚刚添加了 zoom: 1.04;

Using zoom solved it for me.

I just added zoom: 1.04;

∞琼窗梦回ˉ 2024-11-23 18:08:48

在我的案例中找到的解决方案是设置第一个子元素的高度值

Solution found in my case was setting a height value of the first child element

旧话新听 2024-11-23 18:08:48

@kizu
这些答案和建议没有帮助。对于您的 jsfiddle,您需要添加

-webkit-perspective-origin: 50% 50%;
-webkit 透视:1400px;

到要使用translate3d 的元素的父元素,否则平移z 轴实际上不会执行任何操作。在这种情况下,您将其应用到您单击的按钮,我认为您的意思是将其应用到内容。

但无论如何,添加这些来激活 z 轴更改会导致示例中的按钮模糊。

我也很想找到解决这个问题的办法,恐怕没有。

@kizu
These answers and suggestions do not help. For your jsfiddle you need to add

-webkit-perspective-origin: 50% 50%;
-webkit-perspective: 1400px;

to the parent element of the element you want to use translate3d on, otherwise translating the z-axis doesn't actually do anything. In this case you are applying it to the button you click, I think you meant to apply it to the content.

But anyway, adding those to activate z-axis change causes the blur to the button in your example.

I would love to find a solution to this as well, I fear there isn't one.

蓝眸 2024-11-23 18:08:48

我在这些类型的问题上使用 will-change ,它通常可以解决缩放问题或舍入错误,例如看到分隔元素的 1px 白线。

will-change:transform;

在此处阅读更多内容:
https://developer.mozilla.org/en-US/文档/Web/CSS/will-change

I use will-change on these types of issues, it usually solves scaling issues or rounding errors, such as seeing a 1px white line separating elements for example.

will-change: transform;

Read more here:
https://developer.mozilla.org/en-US/docs/Web/CSS/will-change

じее 2024-11-23 18:08:48

使用 HTML5 文档类型为我解决了这个问题。

<!doctype html>
<html>
<head>
<meta charset="UTF-8">

Using the HTML5 doctype solved the issue for me.

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文