Слайдер с анимацией при наведении курсора (HTML код)
<div id="app"></div>
Слайдер с анимацией при наведении курсора (CSS код)
@import url("https://fonts.googleapis.com/css?family=Playfair+Display:700|IBM+Plex+Sans:500&display=swap");
:root {
--color-primary: #6B7A8F;
--color-secondary: #101118;
--color-accent: #1D1F2F;
--color-focus: #6D64F7;
--base-duration: 600ms;
--base-ease: cubic-bezier(0.25, 0.46, 0.45, 0.84);
}
*, *:before, *:after {
box-sizing: border-box;
}
html, body {
height: 100%;
}
body {
font-family: "IBM Plex Sans", sans-serif;
background-color: var(--color-secondary);
}
#app {
align-items: center;
display: flex;
height: 100%;
justify-content: center;
overflow-x: hidden;
width: 100%;
}
h1, h2, h3 {
font-family: "Playfair Display", serif;
}
.visuallyhidden {
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute !important;
white-space: nowrap;
width: 1px;
}
.icon {
fill: var(--color-primary);
width: 100%;
}
.btn {
background-color: var(--color-primary);
border: none;
border-radius: 0.125rem;
color: white;
cursor: pointer;
font-family: inherit;
font-size: inherit;
padding: 1rem 2.5rem 1.125rem;
}
.btn:focus {
outline-color: var(--color-focus);
outline-offset: 2px;
outline-style: solid;
outline-width: 3px;
}
.btn:active {
transform: translateY(1px);
}
.slider__controls {
display: flex;
justify-content: center;
position: absolute;
top: calc(100% + 1rem);
width: 100%;
}
.slider__controls .btn {
--size: 3rem;
align-items: center;
background-color: transparent;
border: 3px solid transparent;
border-radius: 100%;
display: flex;
height: var(--size);
padding: 0;
width: var(--size);
}
.slider__controls .btn:focus {
border-color: var(--color-focus);
outline: none;
}
.slider__controls .btn--previous > * {
transform: rotate(180deg);
}
.slider {
--slide-size: 70vmin;
--slide-margin: 4vmin;
height: var(--slide-size);
margin: 0 auto;
position: relative;
width: var(--slide-size);
}
.slider__wrapper {
display: flex;
margin: 0 calc(var(--slide-margin) * -1);
position: absolute;
transition: transform var(--base-duration) cubic-bezier(0.25, 1, 0.35, 1);
}
.slide {
align-items: center;
color: white;
display: flex;
flex: 1;
flex-direction: column;
height: var(--slide-size);
justify-content: center;
margin: 0 var(--slide-margin);
opacity: 0.25;
position: relative;
text-align: center;
transition: opacity calc(var(--base-duration) / 2) var(--base-ease), transform calc(var(--base-duration) / 2) var(--base-ease);
width: var(--slide-size);
z-index: 1;
}
.slide--previous:hover, .slide--next:hover {
opacity: 0.5;
}
.slide--previous {
cursor: w-resize;
}
.slide--previous:hover {
transform: translateX(2%);
}
.slide--next {
cursor: e-resize;
}
.slide--next:hover {
transform: translateX(-2%);
}
.slide--current {
--x: 0;
--y: 0;
--d: 50;
opacity: 1;
pointer-events: auto;
-webkit-user-select: auto;
-moz-user-select: auto;
-ms-user-select: auto;
user-select: auto;
}
@media (hover: hover) {
.slide--current:hover .slide__image-wrapper {
transform: scale(1.025) translate(calc(var(--x) / var(--d) * 1px), calc(var(--y) / var(--d) * 1px));
}
}
.slide__image-wrapper {
background-color: var(--color-accent);
border-radius: 1%;
height: 100%;
left: 0%;
overflow: hidden;
position: absolute;
top: 0%;
transition: transform calc(var(--base-duration) / 4) var(--base-ease);
width: 100%;
}
.slide__image {
--d: 20;
height: 110%;
left: -5%;
-o-object-fit: cover;
object-fit: cover;
opacity: 0;
pointer-events: none;
position: absolute;
top: -5%;
transition: opacity var(--base-duration) var(--base-ease), transform var(--base-duration) var(--base-ease);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
width: 110%;
}
@media (hover: hover) {
.slide--current .slide__image {
transform: translate(calc(var(--x) / var(--d) * 1px), calc(var(--y) / var(--d) * 1px));
}
}
.slide__headline {
font-size: 8vmin;
font-weight: 600;
position: relative;
}
.slide__content {
--d: 60;
opacity: 0;
padding: 4vmin;
position: relative;
transition: transform var(--base-duration) var(--base-ease);
visibility: hidden;
}
.slide--current .slide__content {
-webkit-animation: fade-in calc(var(--base-duration) / 2) var(--base-ease) forwards;
animation: fade-in calc(var(--base-duration) / 2) var(--base-ease) forwards;
visibility: visible;
}
@media (hover: hover) {
.slide--current .slide__content {
transform: translate(calc(var(--x) / var(--d) * -1px), calc(var(--y) / var(--d) * -1px));
}
}
.slide__content > * + * {
margin-top: 2rem;
}
@-webkit-keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
Слайдер с анимацией при наведении курсора (JS код)
const slideData = [
{
index: 0,
headline: 'New Fashion Apparel',
button: 'Shop now',
src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/225363/fashion.jpg' },
{
index: 1,
headline: 'In The Wilderness',
button: 'Book travel',
src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/225363/forest.jpg' },
{
index: 2,
headline: 'For Your Current Mood',
button: 'Listen',
src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/225363/guitar.jpg' },
{
index: 3,
headline: 'Focus On The Writing',
button: 'Get Focused',
src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/225363/typewriter.jpg' }];
// =========================
// Slide
// =========================
class Slide extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.handleSlideClick = this.handleSlideClick.bind(this);
this.imageLoaded = this.imageLoaded.bind(this);
this.slide = React.createRef();
}
handleMouseMove(event) {
const el = this.slide.current;
const r = el.getBoundingClientRect();
el.style.setProperty('--x', event.clientX - (r.left + Math.floor(r.width / 2)));
el.style.setProperty('--y', event.clientY - (r.top + Math.floor(r.height / 2)));
}
handleMouseLeave(event) {
this.slide.current.style.setProperty('--x', 0);
this.slide.current.style.setProperty('--y', 0);
}
handleSlideClick(event) {
this.props.handleSlideClick(this.props.slide.index);
}
imageLoaded(event) {
event.target.style.opacity = 1;
}
render() {
const { src, button, headline, index } = this.props.slide;
const current = this.props.current;
let classNames = 'slide';
if (current === index) classNames += ' slide--current';else
if (current - 1 === index) classNames += ' slide--previous';else
if (current + 1 === index) classNames += ' slide--next';
return /*#__PURE__*/(
React.createElement("li", {
ref: this.slide,
className: classNames,
onClick: this.handleSlideClick,
onMouseMove: this.handleMouseMove,
onMouseLeave: this.handleMouseLeave }, /*#__PURE__*/
React.createElement("div", { className: "slide__image-wrapper" }, /*#__PURE__*/
React.createElement("img", {
className: "slide__image",
alt: headline,
src: src,
onLoad: this.imageLoaded })), /*#__PURE__*/
React.createElement("article", { className: "slide__content" }, /*#__PURE__*/
React.createElement("h2", { className: "slide__headline" }, headline), /*#__PURE__*/
React.createElement("button", { className: "slide__action btn" }, button))));
}}
// =========================
// Slider control
// =========================
const SliderControl = ({ type, title, handleClick }) => {
return /*#__PURE__*/(
React.createElement("button", { className: `btn btn--${type}`, title: title, onClick: handleClick }, /*#__PURE__*/
React.createElement("svg", { className: "icon", viewBox: "0 0 24 24" }, /*#__PURE__*/
React.createElement("path", { d: "M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z" }))));
};
// =========================
// Slider
// =========================
class Slider extends React.Component {
constructor(props) {
super(props);
this.state = { current: 0 };
this.handlePreviousClick = this.handlePreviousClick.bind(this);
this.handleNextClick = this.handleNextClick.bind(this);
this.handleSlideClick = this.handleSlideClick.bind(this);
}
handlePreviousClick() {
const previous = this.state.current - 1;
this.setState({
current: previous < 0 ?
this.props.slides.length - 1 :
previous });
}
handleNextClick() {
const next = this.state.current + 1;
this.setState({
current: next === this.props.slides.length ?
0 :
next });
}
handleSlideClick(index) {
if (this.state.current !== index) {
this.setState({
current: index });
}
}
render() {
const { current, direction } = this.state;
const { slides, heading } = this.props;
const headingId = `slider-heading__${heading.replace(/\s+/g, '-').toLowerCase()}`;
const wrapperTransform = {
'transform': `translateX(-${current * (100 / slides.length)}%)` };
return /*#__PURE__*/(
React.createElement("div", { className: "slider", "aria-labelledby": headingId }, /*#__PURE__*/
React.createElement("ul", { className: "slider__wrapper", style: wrapperTransform }, /*#__PURE__*/
React.createElement("h3", { id: headingId, class: "visuallyhidden" }, heading),
slides.map(slide => {
return /*#__PURE__*/(
React.createElement(Slide, {
key: slide.index,
slide: slide,
current: current,
handleSlideClick: this.handleSlideClick }));
})), /*#__PURE__*/
React.createElement("div", { className: "slider__controls" }, /*#__PURE__*/
React.createElement(SliderControl, {
type: "previous",
title: "Go to previous slide",
handleClick: this.handlePreviousClick }), /*#__PURE__*/
React.createElement(SliderControl, {
type: "next",
title: "Go to next slide",
handleClick: this.handleNextClick }))));
}}
ReactDOM.render( /*#__PURE__*/React.createElement(Slider, { heading: "Example Slider", slides: slideData }), document.getElementById('app'));
//# sourceURL=pen.js
Слайдер с анимацией при наведении курсора (Результат кода)
Comments