๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
์‹œ๋„/๊ตญ๋น„์ง€์›

[D+51] Front-end ๋ฏธ๋‹ˆํ”„๋กœ์ ํŠธ 7์ผ์ฐจ : ๋ฆฌ์ฝ”๋”ฉ ์‹œ์ž‘ ๋ฐ ์„น์…˜0 ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ค์ •

by ๐Ÿ‡๋ฐ•๋ด‰๋ด‰๐Ÿ‡ 2022. 12. 5.

 

๊ตญ๋น„์ง€์› D+51

Front-end ๋ฏธ๋‹ˆํ”„๋กœ์ ํŠธ 7์ผ์ฐจ

- ๋ฆฌ์ฝ”๋”ฉ ์‹œ์ž‘ ๋ฐ ์„น์…˜0 ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ค์ • -

 


 

์˜ค๋Š˜ ํ•œ ์ผ

- global nav, local nav ์ œ์ž‘

- section ๋ ˆ์ด์•„์›ƒ ์„ค์ •

- section0 ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ค์ •

 

ํŒŒ์ผ ๊ตฌ์„ฑ ๋ฐ ๋‚ด์šฉ

 


• style.css

@charset 'utf-8';

html {
  font-family: 'Noto Sans KR', sans-serif;
  font-size: 14px;
}

body {
  word-spacing: -0.08rem;
  letter-spacing: -0.03rem;
  overflow-x: hidden;
}

a {
  text-decoration: none;
  font-size: 0.9rem;
  color: white;
}

.global {
  /* absolute - section์˜์—ญ์„ค์ •์„ ์œ„ํ•œ ๋…๋ฆฝ์˜์—ญ์ƒ์„ฑ */
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 44px;
  padding: 0 5% 0 5%;
  background-color: black;
}

.global-container {
  /* flex - global-container์•ˆ global-item๋“ค์˜ ๋ฐฐ์น˜ ์ˆ˜ํ‰์  ๊ตฌ์กฐ ๋ชฉ์  */
  display: flex;
  max-width: 1000px;
  height: 100%;
  align-items: center;
  justify-content: space-between;
  margin: 0 auto;
}

.local {
  /* absolute - section์˜์—ญ์„ค์ •์„ ์œ„ํ•œ ๋…๋ฆฝ์˜์—ญ์ƒ์„ฑ */
  position: absolute;
  top: 44px;
  left: 0;
  width: 100%;
  height: 52px;
  padding: 0 5% 0 5%;
  border-bottom: 1px solid gray;
}

.local-container {
  /* flex - global-container์•ˆ global-item๋“ค์˜ ๋ฐฐ์น˜ ์ˆ˜ํ‰์  ๊ตฌ์กฐ ๋ชฉ์  */
  display: flex;
  max-width: 1000px;
  height: 100%;
  align-items: center;
  justify-content: right;
  margin: 0 auto;
}

.local-item-main {
  margin-right: auto;
  font-size: 1.5rem;
}

.local-item {
  margin-left: 1em;
}

.local-item, .local-item-main {
  color: black;
  font-weight: bold;
}

/* static - section์€ ๊ธฐ์กด๋ฌธ์„œ์˜ ํ๋ฆ„์„ ๋”ฐ๋ฅด๋„๋ก ํ•œ๋‹ค. */

.section0-main {
  padding-top: 2em;
  text-align: center;
  font-size: 6rem;
}

.section0-message {
  /* fixed - ์Šคํฌ๋กค์ด๋ฒคํŠธ ๋ฐœ์ƒ์‹œ ์• ๋‹ˆ๋ฉ”์ด์…˜ํšจ๊ณผ ์ถ”๊ฐ€ํ•  ๊ฒƒ */
  position: fixed;
  width: 100%;
  display: none;
  text-align: center;
  font-size: 5rem;
  font-weight: bold;
  opacity: 0;
}

.show-section0 .section0-message {
  display: block;
}

.section1, footer {
  border: 2px solid red;
}

 

• index.html

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <!-- ์›นํฐํŠธ -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;700&display=swap" rel="stylesheet">

  <!-- ์Šคํƒ€์ผ -->
  <link rel="stylesheet" href="./reset.css">
  <link rel="stylesheet" href="./style.css">
</head>
<body class ="show-section0">
  
  <!-- global nav -->
  <nav class="global">
    <div class="global-container">
      <a href="#" class="global-item">Home</a>
      <a href="#" class="global-item">History</a>
      <a href="#" class="global-item">Store</a>
      <a href="#" class="global-item">Contact</a>
    </div>
  </nav>
  
  <!-- local nav -->
  <nav class="local">
    <div class="local-container">
      <a href="#" class="local-item-main">RealApplePeach</a>
      <a href="#" class="local-item">Overview</a>
      <a href="#" class="local-item">Compare</a>
      <a href="#" class="local-item">Buy</a>
    </div>
  </nav>

  <!-- section0 -->
  <section class="section0">
    <div class="section0-main"><h1>Apple taste</h1></div>

    <div id="section0-message-0" class="section0-message">
      <p>์˜จ์ „ํžˆ ๋น ์ ธ๋“ค๊ฒŒ ํ•˜๋Š” ๋น›๊น”</p>
    </div>
    <div id="section0-message-1" class="section0-message">
      <p>๋‚˜์˜ ๊ฑด๊ฐ•์„ ์ฑ„์›Œ์ฃผ๋Š” ํ–ฅ๊ธฐ</p>
    </div>
    <div id="section0-message-2" class="section0-message">
      <p>๊นจ๋—ํ•œ ์ž์—ฐ์˜ ์‹ ์„ ํ•จ</p>
    </div>
    <div id="section0-message-3" class="section0-message">
      <p>์ƒˆ๋กญ๊ฒŒ ์ž…๊ฐ€๋ฅผ ์ฐพ์•„์˜จ ๋งคํ˜น</p>
    </div>
  </section>

  <!-- section1 -->
  <section class="section1">
    <div class="section1-message">
      <p>
        ์ง„์งœ ์‚ฌ๊ณผ ์ด์•ผ๊ธฐ
        ์‚ฌ๊ณผ๋ฅผ ๋งค์ผ ํ•˜๋‚˜์”ฉ ๋จน์œผ๋ฉด ์˜์‚ฌ ๋ณผ ์ผ์ด ์—†๋‹ค
        (an apple a day keeps the doctor away)๋ž€ ์†๋‹ด์ด ์žˆ์„ ์ •๋„๋กœ 
        ์œ ๋ช…ํ•œ ๊ฐ€์„ ๊ณผ์ผ ์ค‘ ํ•˜๋‚˜๋‹ค. ๋น„์Šทํ•œ ์†๋‹ด์ด ํ† ๋งˆํ† ์—๋„ ์žˆ๋‹ค. 
        ๊ทธ๋งŒํผ ๋น„ํƒ€๋ฏผC์™€ ๋ฌด๊ธฐ์งˆ์ด ๋งŽ์•„ ๊ฐ„์‹ ๋Œ€์šฉ์œผ๋กœ ์‚ฌ๊ณผ๋ฅผ ํ•œ ์•Œ ๋จน๋Š”๋‹ค๋ฉด 
        ๋น„ํƒ€๋ฏผC ๋ถ€์กฑ์— ์‹œ๋‹ฌ๋ฆด ์ผ์€ ์—†๋‹ค. ๋‹ค๋งŒ ๊ณผ๋‹น์ด ๋งŽ์•„์„œ ํ†ต์ƒ์ ์ธ ์ด๋ฏธ์ง€์™€๋Š” 
        ๋‹ฌ๋ฆฌ ๋‹ค์ด์–ดํŠธ ์‹ํ’ˆ์œผ๋กœ์„œ๋Š” ๊ทธ๋‹ค์ง€ ํšจ๋Šฅ์ด ์ข‹์ง€ ์•Š์€๋ฐ, ๋‹จ์œ„ ์ค‘๋Ÿ‰ ๋‹น ์—ด๋Ÿ‰์€ 
        ์•„๋ณด์นด๋„๋‚˜ ๋ฐ”๋‚˜๋‚˜ ๋“ฑ๊ณผ ํ•จ๊ป˜ ์ œ๋ฒ• ๋†’์€ ํŽธ์— ์†ํ•œ๋‹ค. 
        ๋‹น์—ฐํžˆ ์‚ฌ๊ณผ์˜ ํฌ๊ธฐ์™€ ์˜์–‘์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅด์ง€๋งŒ 300g ์ •๋„ ๋‚˜๊ฐ€๋Š” ํ•œ ์•Œ์ด 
        200kcal๋Š” ๋„˜์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
        ๋น„ํƒ€๋ฏผ C๊ฐ€ ํ’๋ถ€ํ•œ ๋งŒํผ ๊ฐ๊ธฐ ์˜ˆ๋ฐฉ์— ํšจ๊ณผ์ ์ด๋‚˜, ํ•œ์˜ํ•™์ ์œผ๋กœ ์‚ฌ๊ณผ๋Š”
        ์ฐจ๊ฐ€์šด ์„ฑ์งˆ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ชฉ๊ฐ๊ธฐ๋‚˜ ๊ธฐ์นจ์— ์ข‹์ง€ ์•Š๋‹ค๊ณ  ํ•œ๋‹ค. 
        ๊ฐ๊ธฐ์— ์ข‹๋‹ค๊ณ  ํ•˜๋Š” ๊ณผ์ผ์€ ๋ฐฐ, ๊ทธ๋ฆฌ๊ณ  ๊ทค๋„ ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค. 
        ๋ฐฐ๋Š” ๊ณผ์ผ ์ค‘์—์„œ๋„ ํŠนํžˆ ์ˆ˜๋ถ„, ๋ฌด๊ธฐ์งˆ์ด ๋งŽ์€ ๊ณผ์ผ ์ค‘ ํ•˜๋‚˜์ด๊ธฐ ๋•Œ๋ฌธ์— 
        ๊ฐ๊ธฐ์— ๊ฑธ๋ ธ์„ ๋•Œ ์ˆ˜๋ถ„ ๋ณด์ถฉ์— ์•„์ฃผ ์ ์ ˆํ•œ ์‹ํ’ˆ์ด๋‹ค.
      </p>
    </div>
  </section>
  
  <!-- footer -->
  <footer>
    <div>
      <p>Copyleft 2022 PARK SUHYEON Allright reserved.</p>
    </div>
  </footer>

  <script src="./main.js"></script>
</body>
</html>

 

• main.js

(() => {
	/*
  currentScrollY : ํ˜„์žฌ scrollY ์œ„์น˜๊ฐ’
  currentSection : ํ˜„์žฌ ์„น์…˜์œ„์น˜
  sectionYOffset : ํ˜„์žฌ ์„น์…˜์— ๋”ฐ๋ฅธ scrollY ์ƒ๋Œ€๊ฐ’
  */
	let currentScrollY = 0;
	let currentSection = 0;
	let sectionYOffset = 0;

	// sectionSet : n๋ฒˆ์งธ ์„น์…˜์— ๋Œ€ํ•œ ๊ฐ์ข… ์ •๋ณด์ง‘ํ•ฉ
	const sectionSet = [
		// section0
		{
			height: 0,
			multiplyValue: 5,
			elemInfo: {
				section: document.querySelector(".section0"),
				message: [
					document.querySelector("#section0-message-0"),
					document.querySelector("#section0-message-1"),
					document.querySelector("#section0-message-2"),
					document.querySelector("#section0-message-3"),
				],
			},
			opacitySettingsValues: {
				message0_opacity_out: [0, 1, { start: 0.05, end: 0.14 }],
				message0_opacity_in: [1, 0, { start: 0.15, end: 0.24 }],

				message1_opacity_out: [0, 1, { start: 0.25, end: 0.34 }],
				message1_opacity_in: [1, 0, { start: 0.35, end: 0.44 }],

				message2_opacity_out: [0, 1, { start: 0.45, end: 0.54 }],
				message2_opacity_in: [1, 0, { start: 0.55, end: 0.64 }],

				message3_opacity_out: [0, 1, { start: 0.65, end: 0.74 }],
				message3_opacity_in: [1, 0, { start: 0.75, end: 0.84 }],
			},
		},
		// section1
		{
			height: 0,
			multiplyValue: 3,
			elemInfo: {
				section: document.querySelector(".section1"),
			},
		},
	];

	/////////////////////////////////////////////////////////
	// ์ผ๋ฐ˜ ํ•จ์ˆ˜

	// setLayout : window์ฐฝ ํฌ๊ธฐ์— ๋Œ€ํ•œ  section ์‚ฌ์ด์ฆˆ ์˜์—ญ ์„ค์ •
	//  - parameter : x
	//  - return : x
	const setLayout = function () {
		const currentHeight = window.innerHeight;

		for (let i = 0; i < sectionSet.length; i++) {
			sectionSet[i].height = currentHeight * sectionSet[i].multiplyValue;
			sectionSet[i].elemInfo.section.style.height = `${sectionSet[i].height}px`;
		}
	};

	// getCurrentSection : scrollY ์œ„์น˜์— ๋”ฐ๋ฅธ ํ˜„์žฌ section ์œ„์น˜ ๊ตฌํ•˜๊ธฐ
	//  - parameter : x
	//  - return : ํ˜„์žฌ ์„น์…˜ ๊ฐ’
	const getCurrentSection = function () {
		let value = 0;
		let sum = 0;
		let index = 0;

		for (let i = 0; i < sectionSet.length; i++) {
			sum = sum + sectionSet[i].height;

			if (currentScrollY <= sum) {
				value = index;
				break;
			}
			index++;
		}

		return value;
	};

	// getSectionYOffset : ํ˜„์žฌ ์„น์…˜ ์œ„์น˜์— ๋”ฐ๋ฅธ scrollY์˜ ์ƒ๋Œ€๊ฐ’ ๊ตฌํ•˜๊ธฐ
	//  - parameter : x
	//  - return : ํ˜„์žฌ ์„น์…˜ ์œ„์น˜์— ๋”ฐ๋ฅธ scrollY ์ƒ๋Œ€๊ฐ’
	const getSectionYOffset = function () {
		let value = currentScrollY;

		for (let i = 0; i < currentSection; i++) {
			value = value - sectionSet[i].height;
		}

		return value;
	};

	// setBodyClass : ํ˜„์žฌ ์„น์…˜ ์œ„์น˜์— ๋”ฐ๋ฅธ body class ์—…๋ฐ์ดํŠธ
	//                section0์˜ ๋‚ด์šฉ์ด ๋‹ค๋ฅธ ์„น์…˜์— ์œ„์น˜ํ•˜๊ฒŒ ํ–ˆ์„ ๋•Œ ์•ˆ๋ณด์ด๊ฒŒ ํ•˜๊ธฐ์œ„ํ•œ ๊ฒƒ
	//  - parameter : x
	//  - return : x
	const setBodyClass = function () {
		document.body.className = `show-section${currentSection}`;
	};

	// calcValue : ์• ๋‹ˆ๋ฉ”์ด์…˜์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ’์„ CSSํ™” ํ•œ๋‹ค.
	//  - parameter : ๊ฐ์˜์—ญ์˜ ํˆฌ๋ช…๋„์„ค์ •๊ฐ’ ([0, 1, { start: 0.05, end: 0.14 }])
	//  - return : CSSํ™”ํ•œ ๊ฐ’
	const calcValue = function (opacityValue) {
		let rate;
		let result;
		let height = sectionSet[currentSection].height;

		let startValue = height * opacityValue[2].start;
		let endValue = height * opacityValue[2].end;
		let heightValue = endValue - startValue;

		rate = (sectionYOffset - startValue) / heightValue;

		result = rate * (opacityValue[1] - opacityValue[0]) + opacityValue[0];

		if (result < 0) {
			result = 0;
		} else if (result > 1) {
			result = 1;
		}

		return result;
	};

	// playAnimation : ์„น์…˜์— ๋”ฐ๋ฅธ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋™์ž‘ ์‹œํ‚ค๊ธฐ
	//  - parameter : x
	//  - return : x
	const playAnimation = function () {
		let value;
		let opacityValue;
		let messageValue;

		const yOffsetRate = sectionYOffset / sectionSet[currentSection].height;

		switch (currentSection) {
			case 0:
				sectionSet[0].elemInfo.message.map((el) => {
					el.style.opacity = 0;
				});

				opacityValue = sectionSet[0].opacitySettingsValues;
				messageValue = sectionSet[0].elemInfo.message;

				if (yOffsetRate < 0.15) {
					value = calcValue(opacityValue.message0_opacity_out);
					messageValue[0].style.opacity = value;
				} else if (yOffsetRate >= 0.15 && yOffsetRate < 0.25) {
					value = calcValue(opacityValue.message0_opacity_in);
					messageValue[0].style.opacity = value;
				} else if (yOffsetRate >= 0.25 && yOffsetRate < 0.35) {
					value = calcValue(opacityValue.message1_opacity_out);
					messageValue[1].style.opacity = value;
				} else if (yOffsetRate >= 0.35 && yOffsetRate < 0.45) {
					value = calcValue(opacityValue.message1_opacity_in);
					messageValue[1].style.opacity = value;
				} else if (yOffsetRate >= 0.45 && yOffsetRate < 0.55) {
					value = calcValue(opacityValue.message2_opacity_out);
					messageValue[2].style.opacity = value;
				} else if (yOffsetRate >= 0.55 && yOffsetRate < 0.65) {
					value = calcValue(opacityValue.message2_opacity_in);
					messageValue[2].style.opacity = value;
				} else if (yOffsetRate >= 0.65 && yOffsetRate < 0.75) {
					value = calcValue(opacityValue.message3_opacity_out);
					messageValue[3].style.opacity = value;
				} else if (yOffsetRate >= 0.75 && yOffsetRate < 0.85) {
					value = calcValue(opacityValue.message3_opacity_in);
					messageValue[3].style.opacity = value;
				} else {
				}
				break;

			case 1:
				break;
		}
	};
	/////////////////////////////////////////////////////////
	// ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ

	window.addEventListener("load", () => {
		setLayout();

		currentScrollY = window.scrollY;
		currentSection = getCurrentSection();
		sectionYOffset = getSectionYOffset();

		setBodyClass();
	});

	window.addEventListener("scroll", () => {
		currentScrollY = window.scrollY;
		currentSection = getCurrentSection();
		sectionYOffset = getSectionYOffset();

		setBodyClass();

		playAnimation();
	});
})();

 

 


๊ฒฐ๊ณผํ™”๋ฉด

 

 

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€