
https://www.youtube.com/watch?v=FAK-43mw3x8
위 강의 영상을 보고 js와 css를 이용해 animated smoke를 만들어보자.
https://unruffled-golick-8fbba0.netlify.app
JS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Smoke</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section>
<p class = "text">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores enim minima molestiae nihil? Pariatur beatae libero aliquid iure laborum labore aut amet voluptatibus, error consequuntur ratione aspernatur nostrum cum similique!
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Soluta sint, qui sit blanditiis beatae delectus maiores explicabo, labore modi odio reprehenderit quidem itaque vero quisquam officiis fugiat, quaerat rem nihil.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Totam quos culpa eveniet a vel est id iure odio quibusdam non. Quo adipisci optio hic impedit! Dolore doloremque dicta voluptate architecto!
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Adipisci reiciendis sed, quibusdam nemo fuga eaque maxime quasi facilis quod voluptatum, debitis assumenda quaerat repellendus soluta incidunt inventore totam. Quas, deserunt.
</p>
</section>
<script>
// now split text into letters
const text = document.querySelector('.text'); // 클래스 이름이 text 선택
// 문자열을 알파벳 하나씩 분리. 정규표현식
// 모든 문자 하나하나를 <span>$&</span>로 치환
// $& 패턴은 앞에서 대응된(일치한) 전체 문자열 가리킴
text.innerHTML = text.textContent.replace(/\S/g, "<span>$&</span>");
// now add active class on hovered <span> tag
const letters = document.querySelectorAll('span');
for (let i=0; i<letters.length; i++) {
letters[i].addEventListener('mouseover', function() { // https://www.youtube.com/watch?v=9XyowP9VjDo
letters[i].classList.add('active'); // onmouse하면 span에 class명이 'active'인 class 생김
})
}
</script>
</body>
</html>
string.replace(serchVal, newVal)
string에서 serchVal을 찾아 newVal로 치환한다.
let str = 'aaa, bbb, ccc, bbb';
let newStr = str.replace('bbb', 'new!');
console.log(str); // aaa, bbb, ccc, bbb
console.log(newStr); // aaa, new!, ccc, bbb
단 첫번째로 발견된 것만 치환함.
g : 모든 패턴 체크(global)
\s : 하나의 공백 문자(스페이스, 탭, 줄 바꿈 등)에 대응
\S : 공백 문자 아닌 하나의 문자에 대응
$ : 입력의 끝 부분과 대응
$& : 앞에서 대응된(일치한) 전체 문자열 가리킴
.replace(/\s/g, "") // 문자열 내의 모든 공백 제거 == /\s/g를 ""로 치환
.replace(/\S/g, "") // 문자열 내 모든 문자 제거
<li id='active' class='marked current>hello</li>
다음 엘리멘트가 있을 때
let active = document.getElementById('active')
active.classList[0] // marked
active.classList[1] // current
active.calssList.length // 2
active.classList.add('important') // 클래스값 추가
active.classList.remove('important') // 클래스값 제거
active.classList.toggle('important') // on, off 스위치 처럼 없으면 만들고, 있으면 지우는 기능.
css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
section {
/* 별도 지정 안하면 기본값인 static 적용(원래 있어야 할 위치).
relative(상대적)로 설정하면 요소를 원래 위치에서 벗어나게 배치 가능. */
position: relative;
display: flex;
justify-content: center;
align-items: center;
/* viewport height. 실행중 스크린 크기에 맞춰 상대적으로 크기 반환
100vh, 100vw가 전체 화면 기준. 현재 스크린 height가 1000px라면 50vh는 500px */
min-height: 100vh;
background: #111;
/* 블록에서 넘치는 부분은 숨김. vidible은 블록 밖에서 존재, scroll은 스크롤 가능 */
overflow: hidden;
}
section .text {
position: relative;
text-align: center;
color: #fff;
margin: 40px;
max-width: 800px;
/* 텍스트 선택(드래그) x. */
user-select: none;
font-size: 2em;
}
section .text span {
position: relative;
display: inline-block;
/* 커서 모양을 포인터로 */
cursor: pointer;
}
section .text span.active {
/* css 애니메이션 속성 */
/* 이름 지정되면 해당 이름 키 프레임 사용 됨 */
animation-name: mySmoke;
/* 애니메이션 지속 시간. 이름과 함께 필수 속성 */
animation-duration: 2s;
/* 애니메이션 속도 곡선 지정. */
animation-timing-function: linear;
/* none: 애니메이션 스타일은 기본 스타일에 영향 미치지 않음.
요소는 애니메이션 시작 전에 기본 스타일로 설정되고 애니메이션 끝난 후 기본 스타일로 돌아감.
애니메이션 스타일은 @keyframes{} 안에 지정된 스타일.
따라서 none은 연기 애니메이션 끝나면 글자 다시 생김.
forwards: 애니메이션 키프레임이 100%에 도달했을 때 마지막 키 프레임 유지. 즉 사라진 채 유지 */
animation-fill-mode: forwards;
/*transform에 대한 원정 지정.*/
transform-origin: bottom;
/*animation: mySmoke 2s linear forwards;*/
}
@keyframes mySmoke
{
0%
{/* transform: matrix(1,2,3,4,5,6);
matrix 는 다른 Transform 함수들의 기초가 되는 함수. but 직관적이지 않음.
1 3 5
matrix[1,2,3,4,5,6] = 2 4 6
0 0 1
---------------------------
a 0 0
scale(a) = 0 a 0
0 0 1
---------------------------
x 0 0
scaleX(x) = 0 1 0
0 0 1
---------------------------
1 0 0
scaleY(y) = 0 y 0
0 0 1
---------------------------
1 0 0
translateY(y) = 0 1 y
0 0 1
---------------------------
1 0 x
translateX(x) = 0 1 0
0 0 1
---------------------------
1 0 x
translate(x,y) = 0 1 y
0 0 1
즉 transform: matrix(2,0,0,2,0,0)과 transform: scale(2)는 같은 모습
*/
opacity: 1;
filter: blur(0);
/* translate(tx, ty) : 좌표평면에서 2D이동(translation) 함수
translateX(tx) : 요소를 X축 따라 tx만큼 이동
translateY(ty) : 요소를 Y축 따라 ty만큼 이동 */
transform: translateX(0) translateY(0)
/* 요소를 자신의 원점 또는 transform-origin 기준으로 설정한 각도만큼 시계방향 회전 */
rotate(0deg)
/* scale(sx, sy) : 2D 크기 변환 함수. sy 없다면 sx와 동일값으로 간주
scaleX(sx) : scale(sx, 1)과 같은 모습
scaleY(sy) : scale(1, sy)과 같은 모습 */
scale(1);
}
50%
{
opacity: 1;
/* html 요소에 정의된 클릭, 상태(hover, active등), 커서 옵션 비활성화*/
pointer-events: none;
}
100%
{
opacity: 0;
filter: blur(8px);
transform: translateX(300px) translateY(-300px) rotate(720deg)
scale(4);
}
}
css 선택자
결합자
div span 은 <div>안에 위치한 모든 <span> 요소ul > li 은 <ul>바로 아래 모든 <li> 요소position 속성
html문서 상 요소 배치되는 방식
별도 지정 안하면 기본값인 static 적용(원래 있어야 할 위치).
relative(상대적)로 설정하면 요소를 원래 위치에서 벗어나게 배치 가능.
top, bottom, left, right 사용해 원래 있어야 할 위치에서 얼마나 떨어지게 할지 지정 가능.
https://unruffled-golick-8fbba0.netlify.app
In the heart of a memorable night, surrounded by friends and the calming gurgle of a hookah, I've found some of my most peaceful moments. The range of hookah models I've encountered is as diverse as the flavors of shisha I've savored. From the simplest, no-frills designs to opulent creations that seem fit for royalty, each has its own charm. What truly makes a hookah worth its price is the craftsmanship of its components. A well-crafted stem, akin to a maestro's baton, can lead your smoking session to new heights. Customizing your hookah by choosing individual parts not only personalizes the experience but also makes it more affordable. The perfect blend of design and function transforms the act of smoking into an art form, turning each draw into a symphony of relaxation. For those interested in exploring a wide selection of hookahs and shisha tobacco, visit https://iconhookah.com/collections/hookah-and-shisha-tobacco. It’s a delightful journey for anyone passionate about enhancing their hookah experience.