<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=">
<title>Button effect</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
html,
body {
margin: 0;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
.container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
.btn {
appearance: none;
cursor: pointer;
position: relative;
overflow: hidden;
padding: 16px 32px;
border: none;
border-radius: 3px;
color: #222;
font-weight: bold;
background-color: #eee;
transform: scale(1);
transition: background-color .3s ease, transform .2s ease;
&:hover {
transform: scale(1.075);
background-color: #ddd;
}
&:active {
transform: scale(1);
}
&:focus {
outline: none;
}
}
.page-line {
display: block;
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #000;
transform: translateY(-100%);
animation: slide-in-out 1000ms ease;
}
@keyframes slide-in-out {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(100%);
}
}
View Compiled
const { CSSTransition, TransitionGroup } = ReactTransitionGroup;
const useOverlayLines = () => {
const [lines, setLines] = React.useState([]);
const linesLastKey = React.useRef(1);
const addLine = React.useCallback(
(key) => {
setLines((oldLines) => [oldLines, linesLastKey.current++]);
},
[setLines, linesLastKey]
);
const removeLine = React.useCallback(
(key) => {
setLines((oldLines) => {
let index = oldLines.indexOf(key);
if (index > -1) {
const newLines = [oldLines];
newLines.splice(index, 1);
return newLines;
}
return oldLines;
});
},
[setLines]
);
return {
lines,
addLine,
removeLine,
};
};
const OverlayLinesAnimation = ({ lines, onRemoveLine = () => {} }) => {
return (
<TransitionGroup>
{lines &&
lines.map((key) => (
<CSSTransition
key={key}
timeout={500}
onEntered={() => onRemoveLine(key)}
unmountOnExit
>
<div className="page-line"></div>
</CSSTransition>
))}
</TransitionGroup>
);
};
const Button = ({ children, otherProps }) => {
return (
<button type="button" className="btn" {otherProps}>
{children}
</button>
);
};
const App = () => {
const { lines, addLine, removeLine } = useOverlayLines();
return (
<div className="container">
<OverlayLinesAnimation lines={lines} onRemoveLine={removeLine} />
<Button onClick={addLine}>Кнопка</Button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("app"));
View Compiled
This Pen doesn't use any external CSS resources.