GOOGLE ADS

Montag, 18. April 2022

Slider mit gsap neu erstellen und reagieren

Ich versuche, diesen Codepen mit React und Gsap hier neu zu erstellen, und ich versuche seit einigen Stunden, dies neu zu erstellen, und weiß nicht einmal, wo ich anfangen soll. Ich möchte die Abschnitte in diesem Codepen nicht auf die gleiche Weise erstellen, sondern die Details aus einer Reihe von Objekten bilden, was bedeutet, dass nur eine Komponente erstellt wird, die sie TROCKEN macht. Ich bin ziemlich neu im Reagieren und würde gerne wissen, wie man so etwas in React macht, wenn ich es aus Vanillajs Perspektive betrachte. Ich weiß bereits, was vor sich geht, und ich habe es auch so erstellt, aber ich möchte eine Situation, in der ich nur minimalen Code habe und ein Array von Objekten eine Komponente bildet, die es dynamischer macht, sodass ich darauf klicken kann, um mehr Informationen darüber zu erhalten jeder Abschnitt, der hereinkommt.

HTML

<div class="slider">

<div class="slider__slide slider__slide--1">
<div class="slider__img slider__img--1"></div>
<div class="slider__text slider__text--1">
<h1 class="slider__header">Rejuvenate your, true self.</h1>
<a href="ign.com" class="cta">discover</a>
</div>
</div>

<div class="slider__slide slider__slide--2">
<div class="slider__img slider__img--2"></div>
<div class="slider__text slider__text--2">
<h1 class="slider__header">Professonial, trust-worthy, and compassionate.</h1>
<a href="google.com" class="cta">learn more</a>
</div>
</div>

<div class="slider__slide slider__slide--3">
<div class="slider__img slider__img--3"></div>
<div class="slider__text slider__text--3">
<h1 class="slider__header">Trust in us.</h1>
<a href="youtube.com" class="cta">learn more</a>
</div>
</div>

<div class="slider__slide slider__slide--4">
<div class="slider__img slider__img--4"></div>
<div class="slider__text slider__text--4">
<h1 class="slider__header">What we do.</h1>
<a href="tsn.ca" class="cta">discover</a>
</div>
</div>

<div class="slider__navigation">
<div class="slider__count slider__count--top">
<p class="count count--top count--top-1">01</p>
<p class="count count--top count--top-2">02</p>
<p class="count count--top count--top-3">03</p>
<p class="count count--top count--top-4">04</p>
</div>

<div class="slider__bar">
<div id="sliderBarDynamic" class="slider__bar--dynamic"></div>
<div class="slider__bar--static"></div>
</div>

<div class="slider__count slider__count--bottom">
<p class="count count--bottom count--bottom-1">02</p>
<p class="count count--bottom count--bottom-2">03</p>
<p class="count count--bottom count--bottom-3">04</p>
<p class="count count--bottom count--bottom-3">01</p>
</div>
</div>

</div>

CSS

@import url('https://fonts.googleapis.com/css2?family=Gilda+Display&family=Roboto&display=swap');
*,
*::before,
*::after{
padding:0;
margin:0;
box-sizing:inherit;
}
html{
font-size:16px;
box-sizing:border-box;
}
body{
font-family: 'Roboto', sans-serif;
color:#444444;
font-weight: 300;
line-height: 1.6;
}
img{
max-width:100%;
}
h1{
font-size: 100px;
color: #fff;
font-family: 'Gilda Display', serif;
font-weight: 300;
line-height: 1;
}
h2{
}
h3{
}
P{
color: #fff;
}
a{
text-decoration:none;
color:#ffffff;
font-size: 24px;
}
ul{
list-style-type:none;
}
// Slider
.slider{
width: 100%;
height: 100vh;
overflow: hidden;
position: relative;

&__slide{
width: 100%;
height: 100%;
display: flex;

position: absolute;
top: 0;
left:0;

&--1{
z-index: 4;
}

&--2{
z-index: 3;
}

&--3{
z-index: 2;
}

&--4{
z-index: 1;
}
}

&__img{
width: 100%;
height: 100%;
position: absolute;
z-index: -1;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;

&--1{
background-image: url('https://i.postimg.cc/Y0T3F1tc/about-landing.jpg');
}

&--2{
background-image: url('https://i.postimg.cc/FHHyKWyf/i-Stock-1148043788.jpg');
}

&--3{
background-image: url('https://i.postimg.cc/tTqp06QH/i-Stock-1064136816.jpg');
}

&--4{
background-image: url('https://i.postimg.cc/435R13K2/i-Stock-1179976698.jpg');
}
}

&__text{
align-self: flex-end;
padding: 0 0 5vw 15vh;
opacity: 0;
width: 80%;
max-width: 1005px;

.slider__header{
margin-bottom: 40px;
text-transform: capitalize;
}

.cta{
font-weight: 700;
text-transform: uppercase;
letter-spacing: 6px;
margin-left: 65px;
position: relative;

&:before{
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%);
left: -55px;
width: 40px;
height: 1px;
background-color: white;
}
}
}

// Slider Navigation
&__navigation{
width: 21px;
height: 400px;
position: fixed;
top: 50%;
transform: translateY(-50%);
left: calc(100% - 5vw);
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}

.count--top{

position: absolute;
top: 0;
left: 0;

// position:
}

.count{
opacity: 0;
}

.count:first-child{
opacity: 1;
}

.count--bottom{
position: absolute;
bottom: 0;
left: 0;
}

&__bar{
width: 2px;
height: 250px;
position: relative;

&--dynamic{
width: 100%;
height: 100%;
background-color: #FF69B4;
transform-origin: top center;

position: absolute;
top: 0;
left: 0;
z-index: 2;
}

&--static{
width: 100%;
height: 100%;
background-color: darkgrey;

position: absolute;
top: 0;
left: 0;
}
}
}
// Slider end

Javascript

/*
*/
// timeline to control animations everytime the timeline restarts/repeats
let tlRepeat = gsap.timeline();
// Need first slides elements - img and text to animate on each repeat of timeline
let repeatBeginning = ()=>{
gsap.set(bgImage[0], {opacity: 0, scale: 1.2, webkitFilter:"blur(" + 6 + "px)"})
tlRepeat
.add("slide1-in")
.fromTo([countTop[0], countBottom[0]], {opacity: 0}, {duration: 0.3, opacity: 1, ease: "Power2.easeIn"}, "slide1-in")
.to(bgImage[0], {duration: 1.8, scale: 1, opacity: 1, webkitFilter:"blur(" + 0 + "px)"}, "slide1-in")
.fromTo(text[0], {opacity: 0, x: -30, ease: "Power2.easeIn"}, {duration: 0.8, opacity: 1, x: 0}, "-=1")
}
// On start animations
// let onStartSlide1Animations = ()=>{
// // gsap.to(text[0], {duration: 0.7, opacity: 1, x: -15, ease: "Power2.easeIn"})
// }
// Variables
let slides = document.querySelectorAll('.slider__slide'),
dynamicBar = document.querySelector('#sliderBarDynamic'),
countTop = document.querySelectorAll(".count--top"),
countBottom = document.querySelectorAll(".count--bottom"),
bgImage = document.querySelectorAll(".slider__img"),
text = document.querySelectorAll(".slider__text"),
tl = gsap.timeline({repeat: 0, delay: 1, paused: false, onRepeat: repeatBeginning});

// Push all text back and only make first one visible
gsap.set(text, {x: -30});
gsap.set(text[0], {opacity: 1});
// Animate slide's elements but not the first one.
// Make first slide's elements animate when timeline is repeating,
// Follow the flow of rest of the slide's animations
slides.forEach((slide, i) =>{

tl
.fromTo(dynamicBar, {scaleY: 0}, {duration: 1.4, scaleY: 1}, "+=2")
.set(dynamicBar, {transformOrigin: "bottom center"})
.to(dynamicBar, {duration: 1, scaleY: 0}, "+=0.4")
.set(dynamicBar, {transformOrigin: "top center"})
.add("elements-in-out")
.to([countTop[i], countBottom[i]], {opacity: 0}, "elements-in-out")
.to([countTop[i+1], countBottom[i+1]], {opacity: 1}, "elements-in-out")
.to(bgImage[i], {duration: 0.2, opacity: 0}, "elements-in-out")
.set(bgImage[i+1], {scale: 1.2, webkitFilter:"blur(" + 6 + "px)"}, "elements-in-out")
.to(bgImage[i+1], {duration: 1.8, scale: 1, webkitFilter:"blur(" + 0 + "px)"}, "elements-in-out")
.to(text[i], {duration: 0.3, opacity: 0}, "elements-in-out")
.to(text[i+1], {duration: 0.8, opacity: 1, x: 0}, "-=1")
})


Lösung des Problems

Also zunächst einmal, um sich ein beliebiges HTML-Snippet in Bezug auf ReactJS neu vorzustellen, versuchen Sie, im Snippet nach Ähnlichkeiten / Wiederholungen zu suchen. Sobald Sie das getan haben, erhalten Sie eine Art Überblick darüber, was als einzelne Komponenten getrennt werden kann und wie alles zusammenhängt.

Wenn wir uns jetzt das HTML-Snippet ansehen, können wir sehen, dass sich die Folien wiederholen, sodass sie als separate Komponente beibehalten werden können. Wir sehen auch, dass jede Folie eine eindeutige Überschrift und Absatztext anzeigt und auch ein Farbschema hat. Um unsere SlideKomponente dynamisch zu machen, können wir diese als Requisiten an die Komponente übergeben.

Unser data, das die gesamte SliderKomponente (zusammengesetzt aus Slide's) erstellt, sieht also ungefähr so ​​​​aus:

const sliderData = [
{
id: '1',
headerText: `I'm the first Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#500033',
sliderIllustration: '#FF0077',
sliderInner: 'rgba(255, 0, 119, 0.4)',
sliderButton: '#FF0077',
},
},
...
]

Als nächstes stellen wir fest, dass ein Teil der Benutzeroberfläche mit CSS erstellt wurde, was hauptsächlich dazu führte, dass das gesamte Snippet statisch war. Um also Dynamik zu erreichen, haben wir basierend auf den Daten, die wir erhalten, einige Stile in der/den Komponente(n) gerendert. So was:

<style
dangerouslySetInnerHTML={{
__html: [
`
.slider {
display: flex;
width: ${sliderData.length * 100}%; /*(this value in css was static 500%, to rendered only 5 slides)*/
height: 55rem;
transition: all 0.25s ease-in;
transform: translateX(0);
}
.trail {
bottom: 5%;
left: 50%;
transform: translateX(-50%);
width: 60%;
display: grid;
grid-template-columns: repeat(${sliderData.length}, 1fr); /*this value was also static in css to display only 5 bars/pages.*/
gap: 1rem;
text-align: center;
font-size: 1.5rem;
}`,
].join('\n'),
}}
></style>

Außerdem wurde jeder Folie eine statische Klasse wie box1, box2... etc. Daher müssen diese Stile für jede Folie wie folgt gerendert werden:

<style
dangerouslySetInnerHTML={{
__html: [
`.slider.box${data.id} {
background-color: ${data.colors.sliderBox};
}
.slider.box${data.id}.illustration.inner {
background-color: ${data.colors.sliderIllustration};
}
.slider.box${data.id}.illustration.inner::after,.slider.box${data.id}.illustration.inner::before {
background-color: ${data.colors.sliderInner};
}
.slider.box${data.id} button {
background-color: ${data.colors.sliderButton};
}`,
].join('\n'),
}}
></style>

(Beachten Sie, dass das Objekt dataim obigen Snippet dem Objekt in unserem Array entspricht sliderData, das die gesamte Slider-Komponente formt).

Sobald wir unsere Benutzeroberfläche fertig hatten, war die Einführung von GSAP-Animationen einfach. Zuerst erstellten wir refsdie UI-Elemente, die von GSAP im Animationsprozess verwendet wurden.

Als nächstes lösten wir die Animationen aus, genau wie Sie es in einfachem Javascript tun würden. Der einzige Unterschied besteht hier darin, dass wir sie in dem useEffectHook ausgeführt haben, der ausgeführt wird, sobald die funktionale Komponente geladen ist (leeres Abhängigkeitsarray).

Außerdem gab es ein paar hartcodierte Sachen, die nur die fünf Folien animierten. Was wir durch die Einführung dynamisiert habenlet ratio = 100 / sliderData.length

Das ganze Bauteil:

import React, { useEffect, useRef } from 'react'
import './styleNew.css'
import { gsap } from 'gsap'
const sliderData = [
{
id: '1',
headerText: `I'm the first Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#500033',
sliderIllustration: '#FF0077',
sliderInner: 'rgba(255, 0, 119, 0.4)',
sliderButton: '#FF0077',
},
},
{
id: '2',
headerText: `I'm the second Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#000050',
sliderIllustration: '#0033FF',
sliderInner: 'rgba(0, 51, 255, 0.4)',
sliderButton: '#0033FF',
},
},
{
id: '3',
headerText: `I'm the third Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#00501D',
sliderIllustration: '#00FF44',
sliderInner: 'rgba(0, 255, 68, 0.4)',
sliderButton: '#00FF44',
},
},
{
id: '4',
headerText: `I'm the fourth Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#554D00',
sliderIllustration: '#FF4E00',
sliderInner: 'rgba(255, 78, 0, 0.4)',
sliderButton: '#FF4E00',
},
},
{
id: '5',
headerText: `I'm the fifth Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#300050',
sliderIllustration: '#8000FF',
sliderInner: 'rgba(128, 0, 255, 0.4)',
sliderButton: '#8000FF',
},
},
{
id: '6',
headerText: `I'm the sixth Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#000050',
sliderIllustration: '#0033FF',
sliderInner: 'rgba(0, 51, 255, 0.4)',
sliderButton: '#0033FF',
},
},
{
id: '7',
headerText: `I'm the seventh Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#00501D',
sliderIllustration: '#00FF44',
sliderInner: 'rgba(0, 255, 68, 0.4)',
sliderButton: '#00FF44',
},
},
{
id: '8',
headerText: `I'm the eighth Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#554D00',
sliderIllustration: '#FF4E00',
sliderInner: 'rgba(255, 78, 0, 0.4)',
sliderButton: '#FF4E00',
},
},
{
id: '9',
headerText: `I'm the ninth Box`,
paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer lacinia dui lectus. Donec scelerisque ipsum
diam, ac mattis orci pellentesque eget. `,
buttonText: 'Check Now',
colors: {
sliderBox: '#300050',
sliderIllustration: '#8000FF',
sliderInner: 'rgba(128, 0, 255, 0.4)',
sliderButton: '#8000FF',
},
},
]
export default function SliderNew() {
const slider = useRef(undefined)
const prevButton = useRef(undefined)
const nextButton = useRef(undefined)
const trail = useRef([])
useEffect(() => {
console.log('sliders', slider)
console.log('trail', trail)
console.log('nextButton.current', nextButton.current)
console.log('prevButton.current', prevButton.current)
startGsapAnimations()
}, [])
const startGsapAnimations = () => {
// Transform value
let value = 0
// trail index number
let trailValue = 0
// interval (Duration)
let interval = 10000
let ratio = 100 / sliderData.length
const tl = gsap.timeline({
defaults: { duration: 0.6, ease: 'power2.inOut' },
})
tl.from('.bg', { x: '-100%', opacity: 0 })
.from('p', { opacity: 0 }, '-=0.3')
.from('h1', { opacity: 0, y: '30px' }, '-=0.3')
.from('button', { opacity: 0, y: '-40px' }, '-=0.8')
// function to restart animation
const animate = () => tl.restart()
const slide = (condition) => {
// CLear interval
clearInterval(start)
// update value and trailValue
condition === 'increase'? initiateINC(): initiateDEC()
// move slide
move(value, trailValue)
// Restart Animation
animate()
// start interal for slides back
start = setInterval(() => slide('increase'), interval)
}
// function for increase(forward, next) configuration
const initiateINC = () => {
// Remove active from all trails
sliderData.forEach((_item, index) =>
trail[index].classList.remove('active'),
)
// increase transform value
// console.log('initialInc~value', value)
// console.log('initialInc~calc', (sliderData.length - 1) * ratio)
// console.log(
// 'initialInc~eq',
// Math.round(value) === Math.round((sliderData.length - 1) * ratio),
// )
Math.round(value) === Math.round((sliderData.length - 1) * ratio)
? (value = 0)
: (value += ratio)
// update trailValue based on value
trailUpdate()
}
// function for decrease(backward, previous) configuration
const initiateDEC = () => {
// Remove active from all trails
sliderData.forEach((_item, index) =>
trail[index].classList.remove('active'),
)
// decrease transform value
Math.round(value) === 0
? (value = (sliderData.length - 1) * ratio)
: (value -= ratio)
// update trailValue based on value
trailUpdate()
}
// function to transform slide
const move = (S, T) => {
// transform slider
slider.current.style.transform = `translateX(-${S}%)`
//add active class to the current trail
console.log('trail', T)
trail[Math.round(T)].classList.add('active')
}
const trailUpdate = () => {
trailValue = value / ratio
console.log('trailUpdate', trailValue)
}
// Start interval for slides
let start = setInterval(() => slide('increase'), interval)
nextButton.current.addEventListener('click', () => slide('increase'))
prevButton.current.addEventListener('click', () => slide('decrease'))
const clickCheck = (e) => {
// CLear interval
clearInterval(start)
// Get selected trail
const check = e.target
// remove active class from all trails
sliderData.forEach((_item, index) => {
trail[index].classList.remove('active')
if (check === trail[index]) {
value = index * ratio
}
})
// add active class
check.classList.add('active')
// update trail based on value
trailUpdate()
// transfrom slide
move(value, trailValue)
// start animation
animate()
// start interval
start = setInterval(() => slide('increase'), interval)
}
// Add function to all trails
sliderData.forEach((_item, index) =>
trail[index].addEventListener('click', (ev) => clickCheck(ev)),
)
}
return (
<>
<style
dangerouslySetInnerHTML={{
__html: [
`
.slider {
display: flex;
width: ${sliderData.length * 100}%;
height: 55rem;
transition: all 0.25s ease-in;
transform: translateX(0);
}

.trail {
bottom: 5%;
left: 50%;
transform: translateX(-50%);
width: 60%;
display: grid;
grid-template-columns: repeat(${sliderData.length}, 1fr);
gap: 1rem;
text-align: center;
font-size: 1.5rem;
}`,
].join('\n'),
}}
></style>
<div className="container">
<div className="slider" ref={slider}>
{sliderData.map((item, index) => (
<Slide key={index} data={item} />
))}
</div>
<Svg
ref={prevButton}
compClass="prev"
compTransform="translate(0 91) rotate(-90)"
/>
<Svg
ref={nextButton}
compClass="next"
compTransform="translate(56.898) rotate(90)"
/>
<div className="trail">
{sliderData.map((item, index) => (
<div
ref={(ref) => {
trail[index] = ref
}}
key={index}
className={index == 0? `box${item.id} active`: `box${item.id}`}
>
{item.id}
</div>
))}
</div>
</div>
</>
)
}
function Slide(props) {
const { data } = props
return (
<>
<style
dangerouslySetInnerHTML={{
__html: [
`.slider.box${data.id} {
background-color: ${data.colors.sliderBox};
}
.slider.box${data.id}.illustration.inner {
background-color: ${data.colors.sliderIllustration};
}
.slider.box${data.id}.illustration.inner::after,.slider.box${data.id}.illustration.inner::before {
background-color: ${data.colors.sliderInner};
}
.slider.box${data.id} button {
background-color: ${data.colors.sliderButton};
}`,
].join('\n'),
}}
></style>
<div className={`box${data.id} box`}>
<div className="bg"></div>
<div className="details">
<h1>{data.headerText}</h1>
<p>{data.paragraphText}</p>
<button>{data.buttonText}</button>
</div>
<div className="illustration">
<div className="inner"></div>
</div>
</div>
</>
)
}
const Svg = React.forwardRef((props, ref) => {
console.log('Svg', props)
return (
<svg
ref={ref}
xmlns="http://www.w3.org/2000/svg"
width="56.898"
height="91"
className={props.compClass}
viewBox="0 0 56.898 91"
>
<path
fill="#fff"
d="M45.5,0,91,56.9,48.452,24.068,0,56.9Z"
transform={props.compTransform}
></path>
</svg>
)
})

Die styleNew.css:

*,
*:before,
*:after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
html {
box-sizing: border-box;
font-family: "Roboto", sans-serif;
font-size: 62.5%;
}
@media only screen and (max-width: 800px) {
html {
font-size: 57%;
}
}
body {
background-color: #000;
color: #fff;
padding: 8rem;
}
@media only screen and (max-width: 1000px) {
body {
padding: 0;
}
}
.container {
position: relative;
overflow: hidden;
border-radius: 5rem;
}
@media only screen and (max-width: 1000px) {
.container {
border-radius: 0;
}
}
@media only screen and (max-width: 1000px) {
.slider {
height: 100vh;
}
}
.slider.box {
height: 100%;
width: 100%;
display: grid;
grid-template-columns: repeat(2, 1fr);
align-items: center;
overflow: hidden;
position: relative;
}
@media only screen and (max-width: 650px) {
.slider.box {
grid-template-columns: 1fr;
grid-template-rows: repeat(2, 1fr);
}
}
.slider.box.bg {
padding: 2rem;
background-color: rgba(0, 0, 0, 0.2);
width: 55%;
transform: skewX(7deg);
position: absolute;
height: 100%;
left: -10%;
padding-left: 20rem;
transform-origin: 0 100%;
}
@media only screen and (max-width: 800px) {
.slider.box.bg {
width: 65%;
}
}
@media only screen and (max-width: 650px) {
.slider.box.bg {
width: 100%;
left: 0;
bottom: 0;
height: 54%;
transform: skewX(0deg);
}
}
.slider.box.bg::before {
content: "";
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: inherit;
pointer-events: none;
transform: skewX(10deg);
}
@media only screen and (max-width: 650px) {
.slider.box.bg::before {
width: 120%;
bottom: 0;
transform: skewX(0deg);
}
}
.slider.box.details {
padding: 5rem;
padding-left: 10rem;
z-index: 100;
grid-column: 1/span 1;
grid-row: 1/-1;
}
@media only screen and (max-width: 650px) {
.slider.box.details {
grid-row: 2/span 1;
grid-column: 1/-1;
text-align: center;
padding: 2rem;
transform: translateY(-9rem);
}
}
.slider.box.details h1 {
font-size: 3.5rem;
font-weight: 500;
margin-bottom: 0.5rem;
}
.slider.box.details p {
display: inline-block;
font-size: 1.3rem;
color: #B5B4B4;
margin-bottom: 2rem;
margin-right: 5rem;
}
@media only screen and (max-width: 800px) {
.slider.box.details p {
margin-right: 0;
}
}
.slider.box.details button {
padding: 1rem 3rem;
color: #fff;
border-radius: 2rem;
outline: none;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
.slider.box.details button:hover {
opacity: 0.8;
}
.slider.box.details button:focus {
outline: none;
border: none;
}
.slider.illustration {
grid-column: 2/-1;
grid-row: 1/-1;
justify-self: center;
}
@media only screen and (max-width: 650px) {
.slider.illustration {
grid-row: 1/span 1;
grid-column: 1/-1;
display: flex;
justify-content: center;
align-items: center;
}
}
.slider.illustration div {
height: 25rem;
width: 18rem;
border-radius: 3rem;
background-color: #FF0077;
position: relative;
transform: skewX(-10deg);
}
@media only screen and (max-width: 800px) {
.slider.illustration div {
height: 20rem;
width: 15rem;
}
}
.slider.illustration div::after,.slider.illustration div::before {
content: "";
position: absolute;
height: 100%;
width: 100%;
border-radius: 3rem;
top: 0;
left: 0;
}
.slider.illustration div::after {
transform: translate(4rem, -1rem);
}
.slider.illustration div::before {
transform: translate(2rem, -2rem);
}
.prev,
.next,
.trail {
z-index: 10000;
position: absolute;
}
.prev,
.next {
width: 4rem;
cursor: pointer;
opacity: 0.2;
transition: all 0.3s ease;
}
@media only screen and (max-width: 650px) {
.prev,
.next {
display: none;
}
}
.prev:hover,
.next:hover {
opacity: 1;
}
.prev {
top: 50%;
left: 2%;
transform: translateY(-50%);
}
.next {
top: 50%;
right: 2%;
transform: translateY(-50%);
}
@media only screen and (max-width: 650px) {
.trail {
width: 90%;
bottom: 13%;
}
}
.trail div {
padding: 2rem;
border-top: 3px solid #fff;
cursor: pointer;
opacity: 0.3;
transition: all 0.3s ease;
}
.trail div:hover {
opacity: 0.6;
}
@media only screen and (max-width: 650px) {
.trail div {
padding: 1rem;
}
}
.active {
opacity: 1!important;
}

Keine Kommentare:

Kommentar veröffentlichen

Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...