Эффект CSS Ripple с псевдоэлементом, вызывающим переформатирование

Я пытаюсь создать эффект пульсации материала с помощью стилизованных компонентов (который не может импортировать миксины веб-компонентов материала). Я хочу использовать элемент after для эффекта переднего плана, чтобы дерево доступности оставалось нетронутым.

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

Вот мой код (я использую некоторые реквизиты для настройки пульсации, но вы можете жестко настроить их, если хотите воспроизвести): [Вот устаревшая версия кода]

Спасибо за внимание.

Изменить: ошибка возникает только тогда, когда я добавляю к кнопке эффект наведения, что очень странно. Ниже приведена ссылка и образец кода (к сожалению, вам придется настроить репозиторий реакции, чтобы воспроизвести его)

https://github.com/Eduardogbg/ripple-hover-reflow-bug

import React, { useRef, useReducer } from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components'

const ButtonBase = styled.button`
  cursor: pointer;

  width: 250px;
  height: 6vh;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  outline: none;
  position: relative;
  overflow: hidden;
  border-width: 0;

  background-color: cyan;

  :hover {
    filter: brightness(1.06);
  }

  ::after {
    content: '';
    pointer-events: none;
    
    width: ${({ ripple }) => ripple.size}px;
    height: ${({ ripple }) => ripple.size}px;

    display: none;
    position: absolute;
    left: ${({ ripple }) => ripple.x}px;
    top: ${({ ripple }) => ripple.y}px;

    border-radius: 50%;
    background-color: ${({ ripple }) => ripple.color};

    opacity: 0;
    animation: ripple ${({ ripple }) => ripple.duration}ms;
  }

  :focus:not(:active)::after {
    display: block;
  }
  
  @keyframes ripple {
    from {
      opacity: 0.75;
      transform: scale(0);
    }
    to {
      opacity: 0;
      transform: scale(2);
    }
  }
`

const rippleReducer = ref => (ripple, event) => {
  const { x, y, width, height } = ref.current.getBoundingClientRect()
  const size = Math.max(width, height) 
  
  return {
    ...ripple,
    size, 
    x: event.pageX - x - size / 2,
    y: event.pageY - y - size / 2
  }
}

const DEFAULT_RIPPLE = {
  size: 0,
  x: 0,
  y: 0,
  color: 'white',
  duration: 850
}

const Button = props => {
  const ref = useRef(null)

  const [ripple, dispatch] = useReducer(
    rippleReducer(ref),
    { ...DEFAULT_RIPPLE, ...props.ripple }
  )

  return (
    <ButtonBase
      ref={ref}
      className={props.className}
      ripple={ripple}
      onClick={event => {
        event.persist()
        dispatch(event)
      }}
    >
      {props.children}
    </ButtonBase>
  )
}

ReactDOM.render(
  <div style={{
    backgroundColor: 'red',
    width: '500px', height: '500px',
    display: 'grid',
    placeItems: 'center'
  }}>
    <Button>
      <span style={{ fontSize: '30px' }}>
        abacabadabaca
      </span>
    </Button>
  </div>,
  document.getElementById('root')
);

person eduardogbg    schedule 22.09.2020    source источник
comment
Пожалуйста, добавьте обработанный HTML - как бы начать тестировать это с тем, что вы здесь дали? Прочтите как создать минимально воспроизводимый пример.   -  person disinfor    schedule 22.09.2020
comment
ну, я не понимаю, чем может помочь HTML. Я сделал это так, что нужно было скопировать-вставить для воспроизведения в репозитории реакции со стилями-компонентами. Но я могу просто удалить реагирующий материал и уйти с CSS, тогда это будет вопрос применения класса к кнопке.   -  person eduardogbg    schedule 23.09.2020
comment
Нам не нужно выполнять работу по тестированию вашего кода. Обработанные HTML и CSS позволят нам протестировать вашу кнопку, а затем помочь вам.   -  person disinfor    schedule 23.09.2020
comment
конечно, знаю, что устанавливать зависимости неудобно. Я пытался свести это к простому CSS, но этого не произошло. Возможно, это связано с каким-то написанным мной JS. Я выложу минимальное репо, которое его воспроизводит   -  person eduardogbg    schedule 23.09.2020
comment
Я не смог воспроизвести ошибку, потому что кажется, что это происходит только тогда, когда я добавляю эффект наведения. Не ожидал этого. Обновлю вопрос   -  person eduardogbg    schedule 23.09.2020


Ответы (1)


Проблема, похоже, связана с этой хромовой ошибкой, которая предположительно была решена несколько лет назад: Изображение перемещается при наведении курсора при смене фильтра в Chrome

Установка transform: translate3d(0,0,0); выглядит как исправление, хотя мой глаз не идеален.

person eduardogbg    schedule 23.09.2020