Слайдер 3D Blogger

Увидела на сайте https://atuin.ru/ интересную карусель изображений, которая легко встала на  Blogger. Слайдер 3D с перспективой. Каждое изображение имеет заголовок и описание, если они не нужны, их можно убрать. Слайдер работает на JS. Всего в слайдере можно вставить 6 изображений.
Карусель можно установить как гаджет, например в подвале. Заходим в Дизайн — Добавить гаджет — HTML/JavaScript.
Или в статье — добавляем код в редактор Блоггера в режиме HTML.
слайдер

Добавление кода в блог

Код:
<div class="slider" id="slider"> <div class="slider-content" id="slider-content"> <div class="sl-img"> <div class="sl-img-item sl-img-item-active" data-id="1"><img src="фото 1"/></div> <div class="sl-img-item" data-id="2"><img src="фото 2"/></div> <div class="sl-img-item" data-id="3"><img src="фото 3"/></div> <div class="sl-img-item" data-id="4"><img src="фото 4"/></div> <div class="sl-img-item" data-id="5"><img src="фото 5"/></div> <div class="sl-img-item" data-id="6"><img src="фото 6"/></div> </div> <div class="sl-text"> <div class="sl-text-item sl-text-item-active" data-id="1"> <div class="sl-text-item-head"> <h3>Название 1</h3> </div> <div class="sl-text-item-info"> <p>Описание 1</p> </div> </div> <div class="sl-text-item" data-id="2"> <div class="sl-text-item-head"> <h3>Название 2</h3> </div> <div class="sl-text-item-info"> <p>Описание 2</p> </div> </div> <div class="sl-text-item" data-id="3"> <div class="sl-text-item-head"> <h3>Название 3</h3> </div> <div class="sl-text-item-info"> <p>Описание 3</p> </div> </div> <div class="sl-text-item" data-id="4"> <div class="sl-text-item-head"> <h3>Название 4</h3> </div> <div class="sl-text-item-info"> <p>Описание 4</p> </div> </div> <div class="sl-text-item" data-id="5"> <div class="sl-text-item-head"> <h3>Название 5</h3> </div> <div class="sl-text-item-info"> <p>Описание 5</p> </div> <div class="sl-text-item-info"></div> </div> <div class="sl-text-item" data-id="6"> <div class="sl-text-item-head"> <h3>Название 6</h3> </div> <div class="sl-text-item-info"> <p>Описание 6</p> </div> </div> </div> </div> <div class="slider__nav"> <div class="sl-nav-arrows"> <div class="sl-nav-arrow sl-nav-arrow-left" id="left">Лево</div> <div class="sl-nav-arrow sl-nav-arrow-right" id="right">Право</div> </div> <div class="sl-nav-dots" id="sl-nav-dots"> <div class="sl-nav-dot sl-nav-dot-active" data-id="1"></div> <div class="sl-nav-dot" data-id="2"></div> <div class="sl-nav-dot" data-id="3"></div> <div class="sl-nav-dot" data-id="4"></div> <div class="sl-nav-dot" data-id="5"></div> <div class="sl-nav-dot" data-id="6"></div> </div> </div> </div> <style>:root { --z-distance: 150px; --from-left: 1; --mobile-bkp: 650px; --slider-height: 600px; } .slider *, .slider *::before, .slider *::after { box-sizing: border-box; } .slider { width: 100%; margin: 20px 0; height: var(--slider-height); display: flex; perspective: 1000px; transform-style: preserve-3d; position: relative; } .slider::before, .slider::after { content: ''; left: 0; top: 0; display: block; position: absolute; width: 100%; height: var(--slider-height); background-position: center; background-size: cover; will-change: opacity; z-index: -1; box-shadow: 0 0 0 50vmax rgba(0, 0, 0, 0.3) inset; } .slider::before { background-image: var(--img-prev); } .slider::after { transition: opacity 0.7s; opacity: 0; background-image: var(--img-next); } .slider--bg-next::after { opacity: 1; } .slider-content { margin: auto; width: 65%; height: 65%; will-change: transform; transform-style: preserve-3d; pointer-events: none; transform: translateZ(var(--z-distance)); } .sl-img { overflow: hidden; position: absolute; width: 100%; height: calc(100% - 50px); z-index: 0; box-shadow: 0 0 30px #000; } .sl-img-item { position: absolute; top: 0; left: 0; height: 100%; width: 100%; will-change: transform; transition-timing-function: ease-in; visibility: hidden; } .sl-img-item img { display: block; position: relative; left: -30px; top: -30px; width: calc(100% + 60px); max-width: calc(100% + 60px); height: calc(100% + 60px); object-fit: cover; will-change: transform; } .sl-img-item-active { z-index: 20; visibility: visible; } .sl-img-item-subactive { z-index: 15; visibility: visible; } .sl-img-item-next { transform: translateX(100%); } .sl-img-item-prev { transform: translateX(-100%); } .sl-img-item-transit { transition: transform 0.7s, opacity 0.7s; } .sl-text { position: relative; height: 100%; } .sl-text-item { position: absolute; width: 100%; height: 100%; padding: 10px; perspective: 1000px; transform-style: preserve-3d; } .sl-text-item > * { overflow: hidden; position: absolute; } .sl-text-item h3, .sl-text-item p { transition: transform 0.35s ease-out; overflow: hidden; padding: 10px 20px; margin: 0; font-family: 'Roboto', sans-serif; font-weight: normal; text-align: center; } .sl-text-item h3 { background-color: rgba(191, 226, 255, 0.9); font-size: 30px; text-transform: uppercase; color: #000; position: relative; transform: translateX(-100%); } .sl-text-item p { color: #FFF; font-size: 20px; background-color: rgba(51, 122, 183, 0.9); transform: translateX(100%); } .sl-text-item h3::before, .sl-text-item p::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform: translateX(0); transition: transform 0.35s ease-out 0.28s; } .sl-text-item-head { top: -10px; left: -10px; transform: translateZ(20px); } .sl-text-item-info { bottom: 40px; right: 0; max-width: 75%; min-width: min-content; transform: translateZ(20px); } .sl-text-item-active h3, .sl-text-item-active p { transform: translateX(0); } .sl-text-item-active h3::before { transform: translateX(102%); } .sl-text-item-active p::before { transform: translateX(-102%); } .sl-text-item-backwards h3::before, .sl-text-item-backwards p::before { transition: transform 0.35s ease-in; } .sl-text-item-backwards h3, .sl-text-item-backwards p { transition: transform 0.35s ease-in 0.35s; } .slider__nav { position: absolute; left: 0; top: 0; width: 100%; height: var(--slider-height); text-align: center; } .sl-nav-arrows { display: flex; justify-content: space-between; width: 100%; position: absolute; top: 0; left: 0; height: var(--slider-height); } .sl-nav-arrow { height: calc(var(--slider-height) - 100px); width: 50vw; text-indent: -9999px; white-space: nowrap; } .sl-nav-arrow-left { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 4 4'%3E %3Cpolyline points='3 1 1 2 3 3' stroke='white' stroke-width='.6' stroke-opacity='.6' fill='none'%3E%3C/polyline%3E %3C/svg%3E"); cursor: var(--arrow) 30 30, auto; } .sl-nav-arrow-right { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 4 4'%3E %3Cpolyline points='1 1 3 2 1 3' stroke='white' stroke-width='.6' stroke-opacity='.6' fill='none'%3E%3C/polyline%3E %3C/svg%3E"); cursor: var(--arrow) 30 30, auto; } .sl-nav-dots { top: calc(var(--slider-height) - 80px); display: inline-flex; position: relative; padding: 12px; pointer-events: none; } .sl-nav-dots::before { content: ''; position: absolute; left: 22px; top: 12px; width: 20px; height: 20px; background-color: rgba(51, 122, 183, 0.9); transition: transform 0.7s ease-out; transform: translateX(calc(40px * (var(--from-left) - 1))); } .sl-nav-dot { margin: 0 10px; width: 20px; height: 20px; border: 2px solid rgba(191, 226, 255, 0.9); cursor: pointer; pointer-events: all; display: inline-block; transition: border-color 0.3s ease-out; } .sl-nav-dot:hover { border-color: rgba(255, 255, 255, 1); } .sl-nav-dot:active { border-color: rgba(255, 255, 255, 1); } @media only screen and (max-width: 650px) { .slider::before, .slider::after { display: none; } .slider-content { width: 100%; height: var(--slider-height); transform: translateZ(0); } .sl-img { height: 100%; box-shadow: none; } .sl-text-item-info { bottom: 116px; left: 50%; transform: translate(-50%, 0); } .sl-text-item-info p { padding: 20px; } .sl-text-item-head { top: 40px; left: 40px; transform: translateZ(0); } .sl-text-item-head h3 { font-size: 26px; } .sl-nav-dots { background-color: rgba(0, 0, 0, 0.3); } .sl-nav-arrow { width: 10%; position: relative; cursor: auto; height: var(--slider-height); } .sl-nav-arrow::before { content: ''; background-image: var(--arrow); background-size: cover; width: 40px; height: 40px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .sl-nav-arrow-left { background-image: linear-gradient(to right, rgba(0, 0, 0, 0.7) 0, transparent 100%); } .sl-nav-arrow-left:active { background-image: linear-gradient(to right, rgba(0, 0, 0, 0.9) 0, transparent 100%); } .sl-nav-arrow-right { background-image: linear-gradient(to left, rgba(0, 0, 0, 0.7) 0, transparent 100%); } .sl-nav-arrow-right:active { background-image: linear-gradient(to left, rgba(0, 0, 0, 0.9) 0, transparent 100%); } /* Фикс для ресайза */ .slider-content, .sl-img-item img { transform: none!important; } } </style> <script>function lerp({ x, y }, { x: targetX, y: targetY }) { const fraction = 0.1; x += (targetX - x) * fraction; y += (targetY - y) * fraction; return { x, y }; } class Slider { constructor (el) { const imgClass = this.IMG_CLASS = 'sl-img-item'; const textClass = this.TEXT_CLASS = 'sl-text-item'; const activeImgClass = this.ACTIVE_IMG_CLASS = `${imgClass}-active`; const activeTextClass = this.ACTIVE_TEXT_CLASS = `${textClass}-active`; this.el = el; this.contentE0 = document.getElementById('slider'); this.contentEl = document.getElementById('slider-content'); this.onMouseMove = this.onMouseMove.bind(this); this.activeImg = el.getElementsByClassName(activeImgClass); this.activeText = el.getElementsByClassName(activeTextClass); this.images = el.getElementsByTagName('img'); document.getElementById('sl-nav-dots').addEventListener('click', this.onDotClick.bind(this)); document.getElementById('left').addEventListener('click', this.prev.bind(this)); document.getElementById('right').addEventListener('click', this.next.bind(this)); window.addEventListener('resize', this.onResize.bind(this)); this.onResize(); this.length = this.images.length; this.lastX = this.lastY = this.targetX = this.targetY = 0; } onResize () { const htmlStyles = getComputedStyle(document.documentElement); const mobileBreakpoint = htmlStyles.getPropertyValue('--mobile-bkp'); const isMobile = this.isMobile = matchMedia(`only screen and (max-width: ${mobileBreakpoint})`).matches; this.halfWidth = this.contentE0.offsetWidth / 2; this.halfHeight = this.contentE0.offsetHeight / 2; this.zDistance = htmlStyles.getPropertyValue('--z-distance'); if (!isMobile && !this.mouseWatched) { this.mouseWatched = true; this.el.addEventListener('mousemove', this.onMouseMove); this.el.style.setProperty( '--img-prev', `url(${this.images[+this.activeImg[0].dataset.id - 1].src})` ); this.contentEl.style.setProperty('transform', `translateZ(${this.zDistance})`); } else if (isMobile && this.mouseWatched) { this.mouseWatched = false; this.el.removeEventListener('mousemove', this.onMouseMove); this.contentEl.style.setProperty('transform', 'none'); } } getMouseCoefficients ({ clientX, clientY } = {}) { const halfWidth = this.halfWidth; const halfHeight = this.halfHeight; const xCoeff = ((clientX || this.targetX) - halfWidth) / halfWidth; const yCoeff = (halfHeight - (clientY || this.targetY)) / halfHeight; return { xCoeff, yCoeff } } onMouseMove ({ clientX, clientY }) { this.targetX = clientX - this.contentE0.getBoundingClientRect().left; this.targetY = clientY - this.contentE0.getBoundingClientRect().top; if (!this.animationRunning) { this.animationRunning = true; this.runAnimation(); } } runAnimation () { if (this.animationStopped) { this.animationRunning = false; return; } const maxX = 10; const maxY = 10; const newPos = lerp({ x: this.lastX, y: this.lastY }, { x: this.targetX, y: this.targetY }); const { xCoeff, yCoeff } = this.getMouseCoefficients({ clientX: newPos.x, clientY: newPos.y }); this.lastX = newPos.x; this.lastY = newPos.y; this.positionImage({ xCoeff, yCoeff }); this.contentEl.style.setProperty('transform', ` translateZ(${this.zDistance}) rotateX(${maxY * yCoeff}deg) rotateY(${maxX * xCoeff}deg) `); if (this.reachedFinalPoint) { this.animationRunning = false; } else { requestAnimationFrame(this.runAnimation.bind(this)); } } get reachedFinalPoint () { const lastX = ~~this.lastX; const lastY = ~~this.lastY; const targetX = this.targetX; const targetY = this.targetY; return (lastX == targetX || lastX - 1 == targetX || lastX + 1 == targetX) && (lastY == targetY || lastY - 1 == targetY || lastY + 1 == targetY); } positionImage ({ xCoeff, yCoeff }) { const maxImgOffset = 1; const currentImage = this.activeImg[0].children[0]; currentImage.style.setProperty('transform', ` translateX(${maxImgOffset * -xCoeff}em) translateY(${maxImgOffset * yCoeff}em) `); } onDotClick ({ target }) { if (this.inTransit) return; const dot = target.closest('.sl-nav-dot'); if (!dot) return; const nextId = dot.dataset.id; const currentId = this.activeImg[0].dataset.id; if (currentId == nextId) return; this.startTransition(nextId); } transitionItem (nextId) { function onImageTransitionEnd (e) { e.stopPropagation(); nextImg.classList.remove(transitClass); self.inTransit = false; this.className = imgClass; this.removeEventListener('transitionend', onImageTransitionEnd); } const self = this; const el = this.el; const currentImg = this.activeImg[0]; const currentId = currentImg.dataset.id; const imgClass = this.IMG_CLASS; const textClass = this.TEXT_CLASS; const activeImgClass = this.ACTIVE_IMG_CLASS; const activeTextClass = this.ACTIVE_TEXT_CLASS; const subActiveClass = `${imgClass}-subactive`; const transitClass = `${imgClass}-transit`; const nextImg = el.querySelector(`.${imgClass}[data-id='${nextId}']`); const nextText = el.querySelector(`.${textClass}[data-id='${nextId}']`); let outClass = ''; let inClass = ''; this.animationStopped = true; nextText.classList.add(activeTextClass); el.style.setProperty('--from-left', nextId); currentImg.classList.remove(activeImgClass); currentImg.classList.add(subActiveClass); if (currentId < nextId) { outClass = `${imgClass}-next`; inClass = `${imgClass}-prev`; } else { outClass = `${imgClass}-prev`; inClass = `${imgClass}-next`; } nextImg.classList.add(outClass); requestAnimationFrame(() => { nextImg.classList.add(transitClass, activeImgClass); nextImg.classList.remove(outClass); this.animationStopped = false; this.positionImage(this.getMouseCoefficients()); currentImg.classList.add(transitClass, inClass); currentImg.addEventListener('transitionend', onImageTransitionEnd); }); if (!this.isMobile) this.switchBackgroundImage(nextId); } startTransition (nextId) { function onTextTransitionEnd(e) { if (!e.pseudoElement) { e.stopPropagation(); requestAnimationFrame(() => { self.transitionItem(nextId); }); this.removeEventListener('transitionend', onTextTransitionEnd); } } if (this.inTransit) return; const activeText = this.activeText[0]; const backwardsClass = `${this.TEXT_CLASS}-backwards`; const self = this; this.inTransit = true; activeText.classList.add(backwardsClass); activeText.classList.remove(this.ACTIVE_TEXT_CLASS); activeText.addEventListener('transitionend', onTextTransitionEnd); requestAnimationFrame(() => { activeText.classList.remove(backwardsClass); }); } next () { if (this.inTransit) return; let nextId = +this.activeImg[0].dataset.id + 1; if (nextId > this.length) nextId = 1; this.startTransition(nextId); } prev () { if (this.inTransit) return; let nextId = +this.activeImg[0].dataset.id - 1; if (nextId < 1) nextId = this.length; this.startTransition(nextId); } switchBackgroundImage (nextId) { function onBackgroundTransitionEnd (e) { if (e.target === this) { this.style.setProperty('--img-prev', imageUrl); this.classList.remove(bgClass); this.removeEventListener('transitionend', onBackgroundTransitionEnd); } } const bgClass = 'slider--bg-next'; const el = this.el; const imageUrl = `url(${this.images[+nextId - 1].src})`; el.style.setProperty('--img-next', imageUrl); el.addEventListener('transitionend', onBackgroundTransitionEnd); el.classList.add(bgClass); } } const sliderEl = document.getElementById('slider'); const slider = new Slider(sliderEl); let timer = 0; function autoSlide () { requestAnimationFrame(() => { slider.next(); }); timer = setTimeout(autoSlide, 4000); } function stopAutoSlide () { clearTimeout(timer); this.removeEventListener('touchstart', stopAutoSlide); this.removeEventListener('mousemove', stopAutoSlide); } sliderEl.addEventListener('mousemove', stopAutoSlide); sliderEl.addEventListener('touchstart', stopAutoSlide); timer = setTimeout(autoSlide, 4000); </script>
Размеры изображения для слайдера не имеют значения, поскольку края обрезаются по видимой области.
В код вставляем адреса своих изображений — выделила красным цветом.
Меняем название фотографий в коде выделила синим цветом.
Пишем своё описание фото - зелёным цветом.
Просмотреть работу слайдера можно на  тестовом блоге, в подвале сайта.

Ваши комментарии:

Комментарии со спамом удаляются.