์ค์ต: ํ ๋ผ๋ฅผ ์ฐพ์๋ผ, ์ขํ ์ฐพ์ 007 '์ฑ๋ฅ ๊ฐ์ ', ์ผํ ๋ชฉ๋ก ์ฑ ๋ง๋ค๊ธฐ
DOM / CCSOM / Render Tree / Critical rendering path / ์ฑ๋ฅ ๊ฐ์ / CSS ๋ฐฐ๊ฒฝ ์์ ๊ทธ๋ผ๋ฐ์ด์ / ํ ๋๋ฆฌ ๊ทธ๋ฆผ์ / ๋ค์ฌ์ฐ๊ธฐ&๋ด์ด์ฐ๊ธฐ / ENTER ํค ์ด๋ฒคํธ
<html>
<head>
<style>
body {
background-color: black;
}
button {
display: block;
margin: 0 auto;
margin-bottom: 40px;
background-color: lightcoral;
color: white;
border-style: none;
border-radius: 5px;
padding: 10px 10px;
font-size: 20px;
cursor: pointer;
}
.find-rabbit {
display: inline;
width: 20px;
vertical-align: middle;
}
img {
display: block;
margin: 0 auto;
width: 150px;
}
</style>
</head>
<body>
<button>Find a rabbit <img src="img/rabbit.png" class="find-rabbit" alt="ํ ๋ผ๋ฅผ ์ฐพ์๋ผ"></button>
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/rabbit.png" class = "rabbit" alt="ํ ๋ผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<img src="img/carrot.png" alt="๋น๊ทผ">
<script>
const button = document.querySelector('button');
const rabbit = document.querySelector('.rabbit');
button.addEventListener('click', () => {
rabbit.scrollIntoView({behavior: 'smooth', block: 'center', inline: 'nearest'});
});
</script>
</body>
</html>
๐ก ์๋ ์ฝ๋
const circle = document.querySelector('.circle');
const horizon = document.querySelector('.horizon');
const vertical = document.querySelector('.vertical');
const coord = document.querySelector('.coord');
document.addEventListener('mousemove', (event) => {
const clientX = event.clientX;
const clientY = event.clientY;
circle.style.left = `${clientX}px`;
circle.style.top = `${clientY}px`;
horizon.style.top = `${clientY}px`;
vertical.style.left = `${clientX}px`;
coord.style.left = `${clientX}px`;
coord.style.top = `${clientY}px`;
coord.innerHTML = `${clientX}px, ${clientY}px`;
});
left์ top
๋ ๊ทธ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค layout๋ถํฐ ์๋ก ๋ง๋ค์ด paint, composition ๋จ๊ณ๋ฅผ ๊ฑฐ์ณ์ผ ํ๋ค. ๋ฐ๋ผ์ ์์ ์ฝ๋๋ mousemove ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ์ด ๋จ๊ณ๋ฅผ ๊ฑฐ์น๊ฒ ๋๋ฏ๋ก ๋นํจ์จ์ ์ด๋ค.
๋์ ์ translate
๋ฅผ ์ด์ฉํ๋ ๊ฒ์ด ์ข๋ค. translate๋ ๊ทธ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด๋ composition ๊ณผ์ ๋ฐ์ ์ผ์ด๋์ง ์์ผ๋ฏ๋ก ๋ ํจ์จ์ ์ด๋ค. (CSS Triggers ์ฐธ๊ณ )
์ค์ ๋ก ์ฑ๋ฅ์ด ๊ฐ์ ๋์๋์ง๋ ๊ฐ๋ฐ์ ๋๊ตฌ์ ์ฑ๋ฅ ํญ
์์ ๊ฒ์ฌํด๋ณผ ์ ์๋ค. (ctrl+shift+p ๋๋ฌ์ '๋ ์ด์์ ๋ณ๊ฒฝ ์ง์ญ ํ์' ์ ํ ํ ๋ง์ฐ์ค ๋๋ ค๋ณด๋ฉด ํ์๊ฐ ์ ๋ฌ๋ค.) 1 ํ๋ ์์ ๋ ๋๋งํ๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ด 16.67ms์ ๋์ง ์๋๋ก ๋ง๋ค์ด์ฃผ๋ ๊ฒ ์ข๋ค.
๐ก ์์ ํ ์ฝ๋
๐ JavaScript
const horizon = document.querySelector('.horizon');
const vertical = document.querySelector('.vertical');
const circle = document.querySelector('.circle');
const coord = document.querySelector('.coord');
const rectHalfWidth = circle.getBoundingClientRect().width / 2;
const rectHalfHeight = circle.getBoundingClientRect().height / 2;
document.addEventListener('mousemove', event => {
const x = event.clientX;
const y = event.clientY;
horizon.style.transform = `translateY(${y}px)`;
vertical.style.transform = `translateX(${x}px)`;
circle.style.transform = `translate(${x - rectHalfWidth}px, ${y - rectHalfHeight}px)`;
coord.style.transform = `translate(${x}px, ${y}px)`;
coord.innerHTML = `${x}px, ${y}px`;
;});
๐ CSS
body {
background-color: black;
margin: 0; /* ์ด๋ฒคํธ ๋ฆฌ์ค๋์ transform์ ์ํด line์ด ์์ง์ด๋ ์์์ ์ ์ํฅ์ ๋ฏธ์น๋ฏ๋ก ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ margin ์ ๊ฑฐ */
}
.line {
background-color: white;
position: absolute;
}
.horizon {
width: 100%;
height: 1px;
/* ๊ธฐ๋ณธ ์์น ์ค์ ํด์ค top ์ ๊ฑฐ */
}
.vertical {
width: 1px;
height: 100%;
/* ๊ธฐ๋ณธ ์์น ์ค์ ํด์ค left ์ ๊ฑฐ */
}
.circle {
position: absolute;
/* ๊ธฐ๋ณธ ์์น ์ค์ ํด์ค left, top ์ ๊ฑฐ */
/* transform: translate(-50%, -50%) ์ ๊ฑฐ (๋ ์ด์ ์ ์ฉ x) */
}
.coord {
color: white;
position: absolute;
font-size: 30px;
/* ๊ธฐ๋ณธ ์์น ์ค์ ํด์ค left, top ์ ๊ฑฐ */
/* transform: translate(-50%, -50%) ์ ๊ฑฐ (๋ ์ด์ ์ ์ฉ x) */
margin: 30px;
}
background: linear-gradient(45deg, red, blue);
box-shadow: 0 0 5px 1px gray; // ๊ฐ๋ก ๊ฑฐ๋ฆฌ, ์ธ๋ก ๊ฑฐ๋ฆฌ, ํ๋ฆผ ์ ๋, ํผ์ง ์ ๋, ์์
text-indent: 0.5em; // ๋ค์ฌ์ฐ๊ธฐ
text-indent: -0.5em; // ๋ด์ด์ฐ๊ธฐ
ENTER ํค ์ด๋ฒคํธ
if (event.keyCode === 13)
๋๋
if (event.key === "Enter")
๐ก ์์ ์ , ์ต์ด ๊ฒฐ๊ณผ๋ฌผ
๐ HTML
<html>
<body>
<section>
<header>
<h1>Shopping List</h1>
</header>
<div id="container">
<div id="container-lists"></div>
<input id="container-input" type="container-text">
</div>
<footer>
<button><i class="fas fa-plus-circle"></i></button>
</footer>
</section>
</body>
</html>
๐ CSS
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
font-family: "Gowun Batang", serif;
}
section {
width: 450px;
margin: 100px auto;
border-radius: 20px;
box-shadow: 0 0 10px gray;
}
header {
background: linear-gradient(70deg, rgb(255, 215, 210), rgb(217, 255, 253));
border-radius: 20px 20px 0 0;
text-align: center;
height: 60px;
position: relative;
}
h1 {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: rgb(65, 65, 65);
}
#container {
height: 500px;
}
#container-lists {
height: 460px;
background-color: rgb(252, 245, 239);
padding: 10px 30px;
overflow: auto;
}
#container-input {
width: 100%;
line-height: 40px;
border-style: none;
font-family: "Gowun Batang", serif;
font-weight: bold;
text-indent: 0.5em;
}
#container-input:focus {
outline: none;
box-shadow: 0.05em 0.05em 0.2em 0.1em rgb(201, 201, 201) inset;
}
footer {
background: linear-gradient(70deg, rgb(255, 215, 210), rgb(217, 255, 253));
border-radius: 0 0 20px 20px;
text-align: center;
height: 60px;
position: relative;
}
button {
border-style: none;
background-color: transparent;
cursor: pointer;
}
.fa-plus-circle {
display: block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 40px;
color: rgb(65, 65, 65);
border-radius: 50%;
}
.fa-plus-circle:hover {
opacity: 0.7;
transition: all 300ms;
}
๐ JavaScript
const lists = document.querySelector('#container-lists');
const input = document.querySelector('#container-input');
const button = document.querySelector('button');
function add (name) {
if (input.value === '') {
removeEventListener(name, this);
} else {
const set = document.createElement('div');
set.style.display = 'flex';
set.style.justifyContent = 'space-between';
set.style.alignItems = 'center';
set.style.margin = '15px 0';
set.classList.add('set');
set.innerHTML = `
<p>${input.value}<p>
<i class="far fa-trash-alt"></i>`;
lists.appendChild(set);
input.value = '';
const sets = document.querySelectorAll('.set');
const removeBtns = document.querySelectorAll('.far');
for(let i = 0; i < sets.length; i++) {
removeBtns[i].style.cursor = 'pointer';
removeBtns[i].addEventListener('click', () => sets[i].remove());
}
}
}
button.addEventListener('click', add); // click ์ด๋ฒคํธ
input.addEventListener('keyup', e => { // keyup ์ด๋ฒคํธ
if (e.keyCode === 13) {
add('keyup');
} else {
removeEventListener('keyup', this);
}
});