" 하루하루 코드를 정복해가며 발전하고 있지만 어느날 지쳐버린 나 그리고 우리를 위해 만든 동기부여 명언카드 사이트입니다. "
부모요소가 기준이 되어 자식요소들이 강강술래하듯 원근감 있게 감싸듯 배치하는 것이 어려웠다. 중심을 기준으로 배치하는 것 까진 겨우 성공했지만 * 모양이 되어서 원근감 없이 표현됬다. 해결하고자 열심히 구글링을 해보았고 부모요소에 ransform-style:preserve-3d;
을 적용하면 공감각적인 3D 표현이 가능하다는 걸 배웠다!
CSS에도 변수를 사용할 수 있다는 걸 알게됬다. "그럼 CSS변수와 JS 연결해 기능을 구현할 수 있지 않을까?" 라는 생각으로 캐러셀 구현을 CSS변수로 작성하고 JS로 조절해 양옆으로 움직이도록 구현했다. CSS변수를 사용하여 추후 유지보수 및 기능 추가가 발생하면 최대한 적은 수정으로 추가되도록 고려해보았다.
부트캠프 중에 나온 명언을 넣었더니 추억회상을 하게되는 순기능이 생겼다!ㅋㅋ 생각해보니 사용자가 직접 추가하게 만들면 나중에 지금처럼 추억을 기념하는 용도가 될 것같아 추후 보강할 예정이다.
현재 단방향적인 사이트가 아닌 사용자와 주고받을 수 있는 사이트로 수정하기 위해 생각한 기능들을 정리했다. 추후 보강해볼 예정이다.
아래의 코드는 해당 기능을 구현하는 부분만 작성한 것으로 전체 코드는 깃허브에서 확인할 수 있다.
<div class="card-wrap">
<ul class="card-list">
<!-- 카드 들어올 곳 js로 처리-->
</ul>
</div>
ul.card-list
안에는 내용이 랜덤으로 만들어진 카드들 li.card
가 js로 만들어 넣어진다.
:root{
--count:0; /*현재 보여지고 있는 카드 넘버 */
--cardNum:8; /* 카드 갯수 */
--size: 300px; /* 카드의 가로 사이즈 */
--distance: calc(var(--size) * calc(var(--cardNum) / 6)); /* 중심 축에서 멀어지는 거리 */
--bgColor: #191919;
}
.slove-cards .card-wrap{
width: var(--size);
height: calc(var(--size) * 1.4);
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
padding-top: 70px;
}
.card-wrap .card-list{
width: 100%;
height: 100%;
transform-style:preserve-3d ;
transform: rotateY(calc((360deg / var(--cardNum)) * var(--count)));
transition: all 1s;
position: relative;
}
.card-list .card{
width: 100%;
height: 100%;
position: absolute;
left: 0;
right: 0;
box-sizing: border-box;
transform: rotateY(calc((360deg / var(--cardNum)) * var(--i))) translateZ(var(--distance));
transition: all 1s;
}
div.card-wrap
으로 carousel 가운데로 정렬 및 wrappingul.card-list
가 중심이 되어 li.card
들이 강강술래처럼 둘러 쌓여서 배치 된다.transform-style:preserve-3d;
스타일 적용li.card
에서 rotateY(calc((360deg / var(--cardNum)) * var(--i)))
으로 360도로 카드들을 배치하고 translateZ(var(--distance));
으로 카드와 중심과의 거리를 설정했다.<li class="card" style="--i:0;">
::before
<div class="card-back">
<!--생략-->
</div>
</li>
.card::before{
transform: rotateY(0deg);
z-index: 2;
}
.card .card-back{
transition: all 0.8s cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: rotateY(-180deg);
z-index: 1;
}
/*card:hover*/
.card.on:hover::before {
transform: rotateY(180deg);
z-index: 1;
}
.card.on:hover .card-back{
transform: rotateY(0deg);
z-index: 2;
}
li.card
안에 .card::before
를 앞면(이미지만 보이는 부분), div.card-back
를 뒷면(내용이 들어가는 부분)을 넣었다.z-index
로 카드의 앞뒷면의 겹쳐진 순서를 조정하고 transform: rotateY(각도);
로 뒤집히는 효과를 주었다.li.card
에 클래스 .on
을 붙이고 떼는걸로 가운데에 위치한 카드만 :hover
가 적용되도록 설정했다.<div class="btn-wrap">
<button type="button" class="btn prev-btn">
<img src="./images/prev.svg" alt="왼쪽 버튼">
</button>
<button type="button" class="btn next-btn">
<img src="./images/next.svg" alt="오른쪽 버튼">
</button>
</div>
.btn-wrap .btn{
height: 100%;
width: calc((100% - var(--size)) / 2);
position: fixed;
background-color: transparent;
bottom: 0;
opacity: 0.2;
}
.btn:hover{opacity: 1;}
.btn-wrap .prev-btn{left: 0;}
.btn-wrap .next-btn{right: 0;}
const btnWrap = document.querySelector('.btn-wrap');
const cards = document.getElementsByClassName('card');
let count = 0;
let cardView = 0;
btnWrap.addEventListener('click', (e)=>{
let windowWidth =window.innerWidth / 2;
// rotate cards
if(e.clientX >= windowWidth){
rootTheme.style.setProperty('--count', --count);
}else{
rootTheme.style.setProperty('--count', ++count);
}
// view card num choice
if(count === 0 || count % 8 === 0){
cardView = 0;
}else if(count < 0){
cardView = (count % 8) * -1;
}else{
cardView = cardNum - (count % 8);
}
//cssClass 'on' REMOVE & ADD
for (const card of cards) {
card.classList.remove('on');
}
cards[cardView].classList.add('on')
});
let cardNum = 8; // 카드 갯수
const quotesArr=[
{
author : '윌리엄 포크너',
quote : '남들보다 더 잘하려고 고민하지 마라. 지금의 나보다 잘하려고 애쓰는 게 더 중요하다.',
},
// ...중략
];
// shuffle random quotesArr
quotesArr.sort((a,b) => 0.5 - Math.random());
// card put in cardList
for (let i = 0; i < cardNum; i++) {
let liEl = document.createElement('li');
let divEl = document.createElement('div')
let pEl = document.createElement('p');
let spanEl = document.createElement('span');
if(i===0){
liEl.classList.add('card','on');
}else{
liEl.classList.add('card');
}
liEl.style.setProperty('--i', i);
divEl.classList.add('card-back');
pEl.classList.add('quote');
spanEl.classList.add('author');
pEl.textContent = quotesArr[i]['quote'];
spanEl.textContent = quotesArr[i]['author'];
divEl.appendChild(pEl);
divEl.appendChild(spanEl);
liEl.appendChild(divEl);
cardList.appendChild(liEl);
}