Пост-анимация размытого / искаженного текста на основе Webkit через translate3d

Эта проблема затрагивает все браузеры на базе WebKit, включая iPhone.

Сначала немного предыстории. Сайт, над которым я работаю, использует анимацию слайдера на основе JavaScript, которая в основном идентична этой: http://www.assistly.com/product-tour/

Разница лишь в том, что я использую -webkit-transform: translate3d для "питания" фактической анимации. При использовании этого метода, в отличие от метода на основе JavaScript, текст становится размытым после анимации содержимого. Это особенно заметно на iPhone.

Я нашел несколько обходных путей, чтобы удалить относительное позиционирование, которое я сделал, и добавить правило для -webkit-font-smoothing: antialiasedчто я и сделал. Ни одно изменение не имело ни малейшего значения.

Единственный способ сделать эту работу правильно, без размытого текста, это использовать обычный JavaScript для анимации и обойти translate3d в целом. Я бы предпочел использовать translate3d потому что он работает намного быстрее на устройствах с поддержкой WebKit, но я не могу понять, почему он так плохо влияет на текст.

Любые предложения или решения будут с благодарностью.

16 ответов

Решение

Как упоминалось выше @Robert, иногда помогает добавление фона, но не всегда.

Таким образом, для примера, добавленного Дмитрием, это не единственное, что вы должны сделать: кроме фона, вы должны указать браузеру явно использовать правильное сглаживание, поэтому есть пример исправленного Дмитрия: http://jsfiddle.net/PtDVF/1/

Вам нужно добавить эти стили вокруг (или для) блоков, где вам нужно исправить сглаживание:

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

Похоже, что ничего из этого не сработало для меня, но я нашел немного грязное решение, которое, похоже, помогло:

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

У меня была точно такая же проблема, описанная в посте Кена Авила: CSS: transform: translate(-50%, -50%) делает текст размытым

Конечно, проблема заключалась в том, что я использовал transform: translate(-50%, -50%), из-за чего мое центрированное содержимое стало размытым, но только в сафари на osx.

Размыто не только текст, но и весь контент, включая изображения. Я прочитал: http://keithclark.co.uk/articles/gpu-text-rendering-in-webkit/ что "размытость" связана с тем, что элемент отображается на нецелой границе.

Я также обнаружил, что я могу избежать использования transform translate в горизонтальной части моего центрирования из этого поста: 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>

Элементы, которые вы переводите, должны делиться на два с четными числами.

Важно, чтобы любой элемент, который вы пытаетесь сместить на половину, делился на два по ширине и высоте. Очень похоже на отзывчивые изображения, когда вещи можно перемещать на 50% без разделения пикселей.

Элемент div с шириной: 503px и высотой 500px вызовет размытие, независимо от того, каким образом вы перемещаете его или на сколько при использовании translateX или Y. При использовании transform он использует графический ускоритель графического процессора, что должно быть очень четким, плавным кромки. Также может быть хорошей идеей установить размер блока: border-box; чтобы обеспечить расчетную ширину, включая отступы и границы.

Будьте осторожны при использовании процентной ширины. Если это относительно размера экрана, любая другая ширина пикселя экрана вызовет это размытие.

Я исправил эту проблему, добавив translate3d стиль элемента, прежде чем происходит какая-либо анимация.

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

Это лучшее решениеtranslateX(calc(-50% + 0.5px))

См. WebKit: Размытый текст с css scale + translate3d для решения. Это прекрасно работает, но вы должны многое настроить.

Наверное, самое простое решение:

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

Scale-and-zoom заботится о округлении значений пикселей до полных чисел

Решение Нила Тейлора было лучшим, но его все еще можно улучшить:

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

Таким образом, у него есть 2 преимущества:

  • Он работает в дрянных браузерах, таких как IE11 (который не поддерживает calc внутри translate)
  • Он вычисляет только во время синтаксического анализа, а не каждый раз, когда браузер оценивает.

Ни один из этих ответов не работал для меня, но с использованием

display: inline-table;

сделал трюк

Сброс масштаба Chrome до 100% сработал для меня.

Я надеюсь, что речь идет о центрировании объекта в точном центре экрана. Размытие происходит с преобразованием: перевод (-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>
        );
    }
}

У меня также была такая же проблема, когда я использовал translateZ, я решил ее, используя translateX и translateY вместе и не используя translateZ, как это

transform: translateX(-50%) translateY(-50%);

также работает с прозрачным фоном

Если процентное значение используется для анимации, это все еще приемлемо, если мы также учитываем его производительность, но когда вы не используете translate для анимации все будет иначе, потому что текст всегда будет размытым.

При использовании процента возможно использование дробного числа, например 0.5pxи это причина, по которой текст был размытым. В моем эксперименте с использованиемtranslate(0.5px, 0.5px) сделает текст очень размытым, поэтому вам следует избегать дробного числа между 0.3px <=> 0.7px пока 0.2px and 0.8px все еще приемлемо.

Мое предложение заключается в использовании JavaScript и превращении процента в округленный пиксель для анимации элемента и использовании пикселя вместо процента, еслиtranslate используется для позиционирования элемента.

Другая альтернатива - использоватьleft а также topчтобы установить начальную позицию в процентах, используйтеtransform: translate()с пикселем для целевой позиции и анимироватьtransform только с transition-property: transform;

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.

Просто исправить это с помощью простого трюка, который я не знаю, причина. Здесь вы можете увидеть разные.

Первоначально я стилизовал элемент следующим образом:

top: 50%;
left: 50%;
transform: translate(-50%, -50%);

Что приводит к расплывчатому тексту... После случайной пробы я помещаю стиль в стиль класса и заставляю процессор CSS использовать этот стиль вместо стиля элемента (так как я использую компоненты React, стили, установленные React, станут элемент стиля)

Это то, что я сделал.

.class-name {
    top: 50% !important;
    left: 50% !important;
    transform: translate(-50%, -50%) !important;
}

Я действительно хочу знать, почему перемещение этого стиля из стиля элемента в стиль класса исправило бы это. Любая идея?

@kizu Эти ответы и предложения не помогают. Для вашего jsfiddle вам нужно добавить

-webkit-перспективное происхождение: 50% 50%; -Вебкит-перспектива: 1400px;

к родительскому элементу элемента, на котором вы хотите использовать translate3d, иначе перевод оси Z на самом деле ничего не делает. В этом случае вы применяете его к нажатой кнопке, я думаю, вы хотели применить его к контенту.

Но в любом случае, добавление их для активации изменения оси z приводит к размытию кнопки в вашем примере.

Я бы тоже хотел найти решение этой проблемы, боюсь, что его нет.

Для альтернативного решения попробуйте:

-webkit-text-stroke: 0.35px

Решение, найденное в моем случае, заключалось в height значение первого дочернего элемента

С помощью zoom решил это для меня.

Я только добавил zoom: 1.04;

Я использую will-change в таких типах проблем обычно решаются проблемы масштабирования или ошибки округления, например, например, в виде белой линии, разделяющей элементы размером 1 пиксель.

will-change: transform;

Узнайте больше здесь: https://developer.mozilla.org/en-US/docs/Web/CSS/will-change

Использование doctype HTML5 решило проблему для меня.

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
Другие вопросы по тегам