Webkit-based blurry/distorted text post-animation via translate3d

Viewed 50504

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.

19 Answers

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.

Using zoom solved it for me.

I just added zoom: 1.04;

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>
        );
    }
}

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.

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

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;

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

@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.

Related