Skip to content

This repository is website challenge by frontend mentor and make to JavaScript and Tailwind CSS

Notifications You must be signed in to change notification settings

DrunkenNeoguri/multistepform-challenge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

16 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Frontend Mentor - Multi-step form solution

This is a solution to the Multi-step form challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.

๋ชฉ์ฐจ

๊ฐœ์š”

์ฑŒ๋ฆฐ์ง€ ์•ˆ๋‚ด

์ œ์ž‘์ž๋Š” ์•„๋ž˜์˜ ๋‚ด์šฉ์„ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

  • ๊ฐ ์Šคํ…์˜ ์ˆœ์„œ๋ฅผ ์™„์„ฑํ•  ๊ฒƒ
  • ๋งˆ์ง€๋ง‰ ์Šคํ…์— ์œ ์ €์˜ ์„ ํƒ์„ ํƒ์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์š”์•ฝํ•ด ๋ณด์—ฌ์ฃผ๊ณ , ๊ทธ๋“ค์˜ ์š”์ฒญ์„ ํ™•์ธํ•ด ์ค„ ๊ฒƒ
  • ๊ฐ ์œ ์ €๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๊ธฐ์˜ ์Šคํฌ๋ฆฐ์— ๋งž๋Š” ์ตœ์ ํ™”๋œ ๋ ˆ์ด์•„์›ƒ์„ ๋ณด์—ฌ์ค„ ๊ฒƒ
  • ํŽ˜์ด์ง€๋งˆ๋‹ค ์ƒํ˜ธ ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์š”์†Œ๋Š” hover๋‚˜ foucs ๋“ฑ์„ ์ ์šฉ์‹œ์ผœ์ค„ ๊ฒƒ

๊ตฌํ˜„ ์˜ˆ์‹œ (์Šคํฌ๋ฆฐ์ƒท ๋˜๋Š” ์˜์ƒ)

๋ฐ์Šคํฌํƒ‘ ๋ฒ„์ „ Desktop Version

๋ชจ๋ฐ”์ผ ๋ฒ„์ „

Mobile Version

๋งํฌ

์ž‘์—… ์‚ฌํ•ญ

๊ธฐ์ˆ  ์Šคํƒ

  • HTML5
  • CSS3
  • JavaScript
  • Tailwind CSS - Utility-first ๊ธฐ๋ฐ˜์˜ CSS ํ”„๋ ˆ์ž„์›Œํฌ

ํ•™์Šต ๋ฐ ๋ฌธ์ œ ํ•ด๊ฒฐ ์‚ฌํ•ญ

1๏ธโƒฃ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜์‹œ์ผœ์ฃผ๋Š” ๋งŒ๋“ค์–ด์ฃผ๋Š” Array.from()

Array.from() ๋ฉ”์†Œ๋“œ๋Š” ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋‚˜ ๋ฌธ์ž์—ด๊ณผ ๊ฐ™์€ โ€˜์œ ์‚ฌ ๋ฐฐ์—ด(Array-like) ํ˜•ํƒœโ€™๋ฅผ ๊ฐ€์ง„ ๊ฐ’๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜์‹œ์ผœ์ฃผ๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.

Array.from() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ๋ก€๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒƒ๋“ค์ด ์žˆ๋‹ค.

  • Iterable Object, ์ฆ‰ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด
  • ๋ฌธ์ž์—ด
  • DOM ์š”์†Œ๋“ค์ด ๋‚˜์—ด๋œ HTMLCollection
  • ๋ฐฐ์—ด์™€ ์œ ์‚ฌํ•œ(Array-like) ๊ฐ์ฒด
    • ์˜ˆ์‹œ: {0: โ€œaโ€, 1: โ€œbโ€, 2: โ€œcโ€, length: 3}

Array.from() ๋ฉ”์†Œ๋“œ๋Š” ์•„๋ž˜์˜ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง„๋‹ค.

Array.from(**์œ ์‚ฌ ๋ฐฐ์—ด**, Array.map(ํ•จ์ˆ˜), thisArg)
// Array.from(์œ ์‚ฌ ๋ฐฐ์—ด).map(ํ•จ์ˆ˜, thisArg) ์™€ ๋™์ผํ•˜๋‹ค.
  • ์œ ์‚ฌ ๋ฐฐ์—ด
    • ํ•„์ˆ˜ ์š”์†Œ์ด๋‹ค. ๋ฐฐ์—ด๊ณผ ์œ ์‚ฌํ•œ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง„ ๊ฐ’์ด ์žˆ์–ด์•ผ, ํ•ด๋‹น ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • Array.map(ํ•จ์ˆ˜)
    • ๋ถ€๊ฐ€ ์š”์†Œ์ด๋ฉฐ, ๋ฐฐ์—ด์— ์“ฐ์ด๋Š” map() ๋ฉ”์†Œ๋“œ ์•ˆ์˜ ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
    • ์ฆ‰, map() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ ๋„ ๋‘ ๋ฒˆ์งธ ์ธ์ž์— map() ๋ฉ”์†Œ๋“œ ์•ˆ์— ๋“ค์–ด๊ฐˆ ํ•จ์ˆ˜๋ฅผ ๋ฐฐ์น˜ํ•ด map() ๋ฉ”์†Œ๋“œ๋ฅผ ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • thisArg
    • ๋ถ€๊ฐ€ ์š”์†Œ์ด๋‹ค. ์•ž์˜ map() ๋ฉ”์†Œ๋“œ ํ•จ์ˆ˜์—์„œ ๋ฐ›์•„์˜ฌ this์˜ ๊ฐ’์„ ๋ฐฐ์น˜ํ•œ๋‹ค. ์—†์œผ๋ฉด this์˜ ๊ฐ’์€ map() ๋ฉ”์†Œ๋“œ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฐ์—ด ์ž์‹ ์ด ๋œ๋‹ค.

ํ•ด๋‹น ์ฑŒ๋ฆฐ์ง€ ๊ตฌํ˜„ํ•  ๋•Œ ๋‹น์‹œ, step3 ํŽ˜์ด์ง€๊ฐ€ ๋ถˆ๋Ÿฌ์™€์ง€๋ฉด ์ด๋ฏธ ์œ ์ €๊ฐ€ ์„ ํƒํ•œ ํ˜น์€ ์„ ํƒํ•˜์ง€ ์•Š์€ ์˜ต์…˜ ๋ฆฌ์ŠคํŠธ ์˜์—ญ๋“ค์˜ ์ฐจ์ด๊ฐ€ ๋‚˜๋„๋ก ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ๋‹ค.

Untitled

DOM ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด getElementsByClassName()๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด ํ•ด๋‹น๋˜๋Š” ์˜์—ญ์„ ๋ถˆ๋Ÿฌ์™”์ง€๋งŒ, HTMLCollection์ด๋ผ๋Š” ์œ ์‚ฌ ๋ฐฐ์—ด์ธ ๊ฐ์ฒด๊ฐ€ ๋ฐ›์•„์™€์กŒ๋‹ค.

Untitled

  • HTMLCollection
    • ๊ฐ„๋‹จํžˆ ๋งํ•ด HTML์— ์žˆ๋Š” ์š”์†Œ๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ชจ์•„๋†“์€ ๊ฐ์ฒด์ด๋‹ค.
    • ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, typeof ์—ฐ์‚ฐ์ž์™€ Array.isArray() ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด ํ™•์ธํ•˜๋ฉด ๋ฐฐ์—ด์ด ์•„๋‹˜์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌ๋‹ค๋ณด๋‹ˆ, ๊ฐ ์š”์†Œ๋“ค๋งˆ๋‹ค ์œ ์ €๊ฐ€ ์ด๋ฏธ ์„ ํƒํ•œ ๊ฑด์ง€, ์•„๋‹Œ๊ฑด์ง€๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์กฐ๊ฑด์„ ์ฒดํฌํ•ด ํ‘œ์‹œ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด forEach() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๊ณ , ์ด๋ฅผ ์œ„ํ•ด ์œ ์‚ฌ ๋ฐฐ์—ด์ธ ๊ฐ์ฒด๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฐ›์•„์˜ฌ ํ•„์š”๊ฐ€ ์žˆ์—ˆ๋‹ค.

๋”ฐ๋ผ์„œ Array.from()์„ ํ†ตํ•ด ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด์ธ HTMLCollection์„ ๋ฐฐ์—ด๋กœ ๋ฐ›์•„์™€ ์•„๋ž˜์™€ ๊ฐ™์ด forEach() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜์—ญ๋ณ„ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

const checkboxGroup = document.getElementsByClassName("checkbox");
// checkbox class๊ฐ€ ๋“ค์–ด๊ฐ„ ์š”์†Œ๋“ค์„ ๋ฆฌ์ŠคํŠธํ™”

// Array.from์„ ํ†ตํ•ด ๋ฆฌ์ŠคํŠธํ™”๋œ ์š”์†Œ๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , forEach ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด
// ๊ฐ๊ฐ์˜ ์š”์†Œ๋ณ„๋กœ ์ƒํƒœ๋ฅผ ์ฒดํฌํ•˜์—ฌ ์ ์šฉํ•˜๋„๋ก ํ•จ.
**Array.from(checkboxGroup)**.forEach((element) => {
  if (selectState.period === "Yearly") {
    const costSpan = element.parentNode.childNodes[5];
    costSpan.innerText =
      element.id === "onlineService" ? "+$10/yr" : "+$20/yr";
  }

  if (selectState.addon.indexOf(element.id) !== -1) {
    element.parentNode.classList.add("border-purplish-blue", "bg-magnolia");
    element.classList.add("bg-purplish-blue", "border-purplish-blue");
  } else {
    element.parentNode.classList.remove(
      "border-purplish-blue",
      "bg-magnolia"
    );
    element.classList.remove("bg-purplish-blue", "border-purplish-blue");
  }
});

์œ„์˜ ๋ฐฉ์‹์„ ์ด์šฉํ•ด ๋ฐฐ์—ด ์† DOM ์š”์†Œ๋“ค์— ์œ ์ €๊ฐ€ ์„ ํƒํ•œ ์˜ต์…˜์ธ์ง€๋ฅผ ํ™•์ธํ•˜์—ฌ ์„ ํƒํ–ˆ๋‹ค๋ฉด ์„ ํƒํ•œ ์ƒํƒœ๋กœ, ์•„๋‹ˆ๋ผ๋ฉด ์„ ํƒํ•œ ์ƒํƒœ๋ฅผ ์ œ๊ฑฐํ–ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ Array.from()์„ ์ด์šฉํ•˜๋ฉด ์œ ์‚ฌ ๋ฐฐ์—ด์ธ ๊ฐ’์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•ด์ค„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋ฐฐ์—ด์ด ๋๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด์˜ ๋ฉ”์†Œ๋“œ๋“ค์„ ๋ฐ”๋กœ ํ™œ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

2๏ธโƒฃ JavaScript๋ฅผ ์ด์šฉํ•ด ๋ถ€๋ชจ, ์ž์‹, ํ˜•์ œ์˜ ๋…ธ๋“œ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋ฐฉ๋ฒ•

์—ฌ๊ธฐ ๋…ธํŠธ ํŠธ๋ฆฌ ๊ทธ๋ฆผ์„ ๋ณด์ž.

Untitled ์ถœ์ €: https://www.lambdatest.com/blog/testcafe-selectors/

div๋ผ๋Š” ์š”์†Œ๋ฅผ ๋ณด๋ฉด div ์•ˆ์—” img, h1, p, div๋ผ๋Š” ์š”์†Œ๊ฐ€ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  div์™€ ๋™์ผ ์„ ์ƒ์— script๋ผ๋Š” ์š”์†Œ๊ฐ€ ์กด์žฌํ•˜๋ฉฐ div์™€ script๋Š” ๋ชจ๋‘ body ์š”์†Œ์— ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

์ด๋ฅผ HTML๋กœ ํ‘œํ˜„ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๊ทธ๋ ค์ง„๋‹ค.

<body>
	<**div**>
		<h1></h1>
		<p></p>
		<img>
		<div></div>
	</**div**>
	<script></script>
</body>

๊ทธ๋ฆฌ๊ณ  ์ค‘์‹ฌ์ด ๋˜๋Š” div ์š”์†Œ์™€ ๋‹ค๋ฅธ ์š”์†Œ๋“ค๊ณผ์˜ ๊ด€๊ณ„๋ฅผ ์ •๋ฆฌํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋ถ€๋ชจ ๋…ธ๋“œ: body
  • ํ˜•์ œ ๋…ธ๋“œ: script
  • ์ž์‹ ๋…ธ๋“œ: h1, p, img, div

๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋ฉด์„œ ์š”์†Œ์™€ ๋…ธ๋“œ๊ฐ€ ๋ฒˆ๊ฐˆ์•„ ๋‚˜์˜ค๋Š” ๋ฐ์— ํ˜ผ๋ž€์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ž ์‹œ ์งš๊ณ  ๊ฐ€์ž.

Untitled

์ถœ์ €: https://dionysus2074.tistory.com/137

  • ๋…ธ๋“œ(Node)๋ž€, ์‰ฝ๊ฒŒ ๋งํ•ด HTML์˜ ๋ฌธ์„œ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋‹จ์œ„์ด๋‹ค. ์ด ๋…ธ๋“œ์—๋Š” ํ…์ŠคํŠธ, ์š”์†Œ, ์†์„ฑ, ์ฃผ์„ ๋“ฑ์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š”๋ฐ ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ๋งํ•˜๋Š” div์™€ img, h1 ๊ฐ™์€ ์š”์†Œ๋Š” ๋ฐ”๋กœ ์ด ์š”์†Œ ๋…ธ๋“œ(Element Node)๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
  • ๊ทธ ๋ฐ–์—๋„ ์š”์†Œ ๋…ธ๋“œ ์†์— ์ถœ๋ ฅ๋˜๋Š” ํ…์ŠคํŠธ ๋‚ด์šฉ์€ ํ…์ŠคํŠธ ๋…ธ๋“œ(Text Node), HTML ์•ˆ์— ์ž‘์—…์ž๋งŒ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ์ฃผ์„์„ ๋‹ฌ์•„๋†“๋Š” ๋‚ด์šฉ์€ ์ฃผ์„ ๋…ธ๋“œ(Comment Node), ์š”์†Œ ์†์— ์“ฐ์ด๋Š” onclick์ด๋‚˜ style, id์™€ ๊ฐ™์€ ์†์„ฑ๋“ค์€ ์†์„ฑ ๋…ธ๋“œ(Attribute Node)๋กœ ๋ถˆ๋ฆฌ๊ณ  ์žˆ๋‹ค.

์œ„ 1๏ธโƒฃ์—์„œ Array.from()์œผ๋กœ ๋ฐ›์•„์˜จ ๋ฐฐ์—ด์˜ ์š”์†Œ๋“ค๊ณผ ๊ด€๋ จํ•˜์—ฌ ์œ ์ €๊ฐ€ ์„ ํƒํ•œ ์˜ต์…˜์ธ์ง€ ์•„๋‹Œ์ง€์— ๋”ฐ๋ผ ์Šคํƒ€์ผ์— ๋ณ€ํ™”๋ฅผ ์ฃผ๊ณ  ์‹ถ์—ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ checkbox class๊ฐ€ ํฌํ•จ๋œ ์š”์†Œ๋Š” button ์š”์†Œ ์•ˆ์— ์žˆ๋Š” div์ด๋ฉฐ, ์œ ์ €์˜ ์„ ํƒ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์ฒดํฌ๋ฐ•์Šค ํ‘œ์‹œ์— ๋ณ€ํ™”์™€ ์ƒ๊ธฐ๋Š” ๊ฒƒ ์™ธ์—๋„ ์ฒดํฌ๋ฐ•์Šค๋ฅผ ํฌํ•จํ•œ ๋ฒ„ํŠผ์˜ ํ…Œ๋‘๋ฆฌ์˜ ์ƒ‰์ƒ์„ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ๋‹ค.

<button
  class="flex flex-row items-center border-light-gray border-2 rounded-md my-2 p-3 w-full xsm:w-110 xsm:my-4 xsm:p-4"
  onclick="selectAddOnOption(event)">
  <div
    id="largerStorage"
    class="**checkbox** flex justify-center items-center w-6 h-6 border-light-gray border-2 mr-3 rounded pointer-events-none xsm:mr-4">
    <img src="assets/images/icon-checkmark.svg" alt="" class="w-4 h-4" />
  </div>
  <div class="flex flex-col items-start pointer-events-none">
    <label
      class="block text-marine-blue text-sm font-medium pointer-events-none xsm:text-base "
      >Larger storage</label
    >
    <span class="block text-cool-gray text-xs pointer-events-none xsm:text-sm"
      >Extra 1TB of cloud save</span
    >
  </div>
  <span
    class="ml-auto text-sm text-purplish-blue font-medium pointer-events-none"
    >+$2/mo</span
  >
</button>

๋”ฐ๋ผ์„œ ์ฒดํฌ๋ฐ•์Šค๋ฅผ ๋‹ด๋‹นํ•˜๋Š”, checkbox class๊ฐ€ ํฌํ•จ๋œ div์˜ ๋ถ€๋ชจ์ธ button์„ ์ฐพ์•„ ๋‘ ์š”์†Œ์˜ class์— ๋ณ€ํ™”๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

const checkboxGroup = document.getElementsByClassName("checkbox");
// checkbox class๊ฐ€ ๋“ค์–ด๊ฐ„ ์š”์†Œ๋“ค์„ ๋ฆฌ์ŠคํŠธํ™”

// Array.from์„ ํ†ตํ•ด ๋ฆฌ์ŠคํŠธํ™”๋œ ์š”์†Œ๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , forEach ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด
// ๊ฐ๊ฐ์˜ ์š”์†Œ๋ณ„๋กœ ์ƒํƒœ๋ฅผ ์ฒดํฌํ•˜์—ฌ ์ ์šฉํ•˜๋„๋ก ํ•จ.
  Array.from(checkboxGroup).forEach((element) => {
    if (selectState.addon.indexOf(element.id) !== -1) {
      **element.parentNode**.classList.add("border-purplish-blue", "bg-magnolia");
			// ์š”์†Œ์˜ .parentNode ์†์„ฑ์„ ๋ถˆ๋Ÿฌ์˜ค๋ฉด ํ•ด๋‹น ์š”์†Œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
			// ์—ฌ๊ธฐ์„œ element๋Š” checkbox class๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” div์ด๋ฏ€๋กœ,
			// element.parentNode๊ฐ€ ๋ฐ›์•„์˜ค๋Š” ์š”์†Œ๋Š” div์˜ ๋ถ€๋ชจ์ธ button์ด๋‹ค.
      element.classList.add("bg-purplish-blue", "border-purplish-blue");
    } else {
      element.parentNode.classList.remove("border-purplish-blue", "bg-magnolia");
      element.classList.remove("bg-purplish-blue", "border-purplish-blue");
    }
  });

์ด์ฒ˜๋Ÿผ ์š”์†Œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ๋ฐ›์•„์˜ค๊ณ  ์‹ถ๋‹ค๋ฉด .parentNode ์†์„ฑ์„ ํ™œ์šฉํ•˜๋ฉด ๋œ๋‹ค.

ํ•œํŽธ, ์ด ๋‚ด์šฉ ์™ธ์—๋„ ์œ ์ €๊ฐ€ ์—ฐ ๊ตฌ๋…์ธ์ง€, ์›” ๊ตฌ๋…์ธ์ง€์— ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€์— ์žˆ๋Š” ๊ธˆ์•ก ํ‘œ์‹œ๊ฐ€ ์—ฐ ๋‹จ์œ„, ์›” ๋‹จ์œ„๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ๋‚ด์šฉ์„ ๊ตฌํ˜„ํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ๋‹ค.

๋™์ผ ์„ ์ƒ์— ์žˆ๋Š” ํ˜•์ œ ๋…ธ๋“œ๋ฅผ ๋ฐ›์•„์˜ค๊ณ  ์‹ถ์ง€๋งŒ, ํ˜•์ œ ๋…ธ๋“œ๋ฅผ ์ง€์›ํ•ด์ฃผ๋Š” ๊ฒƒ์€ ํ•ด๋‹น ์š”์†Œ์˜ ์ง์ „ ์•ž๊ณผ ์ง์ „ ๋’ค์ด๋ฏ€๋กœ ๊ฐ€๊ฒฉ ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋Š” ์š”์†Œ์ธ span์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์—†์–ด์„œ ๋ถ€๋ชจ ๋…ธ๋“œ์ธ button๋กœ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€ button์˜ ์ž์‹ ๋…ธ๋“œ ์ค‘ span์„ ๋ฐ›์•„์˜ค๋„๋ก ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

const checkboxGroup = document.getElementsByClassName("checkbox");
// checkbox class๊ฐ€ ๋“ค์–ด๊ฐ„ ์š”์†Œ๋“ค์„ ๋ฆฌ์ŠคํŠธํ™”

// Array.from์„ ํ†ตํ•ด ๋ฆฌ์ŠคํŠธํ™”๋œ ์š”์†Œ๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , forEach ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด
// ๊ฐ๊ฐ์˜ ์š”์†Œ๋ณ„๋กœ ์ƒํƒœ๋ฅผ ์ฒดํฌํ•˜์—ฌ ์ ์šฉํ•˜๋„๋ก ํ•จ.
  Array.from(checkboxGroup).forEach((element) => {
		if (selectState.period === "Yearly") {
			// ํ˜„์žฌ ์œ ์ €๊ฐ€ ๊ตฌ๋…ํ•œ๋‹ค๋Š” ์กฐ๊ฑด์ด '์—ฐ ๊ตฌ๋…'์ด๋ผ๋ฉด
      const costSpan = element.parentNode.childNodes[5];
			// button์˜ ์ž์‹ ์š”์†Œ์ธ span์„ ์ฐพ์•„์„œ ํ•ด๋‹น ๋…ธ๋“œ์— ์ถœ๋ ฅ๋˜๋Š” ๊ฐ€๊ฒฉ์ด ์กฐ๊ฑด์— ๋”ฐ๋ผ
			// ๋ฐ”๋€Œ๋„๋ก ์ ์šฉํ•จ.
      costSpan.innerText =
        element.id === "onlineService" ? "+$10/yr" : "+$20/yr";
    }

    if (selectState.addon.indexOf(element.id) !== -1) {
      **element.parentNode**.classList.add("border-purplish-blue", "bg-magnolia");
      element.classList.add("bg-purplish-blue", "border-purplish-blue");
    } else {
      element.parentNode.classList.remove("border-purplish-blue", "bg-magnolia");
      element.classList.remove("bg-purplish-blue", "border-purplish-blue");
    }
  });

์•ž์„œ element.parentNode๊ฐ€ ๋ฐ›์•„์˜ค๋Š” ๋…ธ๋“œ๋Š” div์˜ ๋ถ€๋ชจ์ธ button๋ผ๊ณ  ์„ค๋ช…ํ–ˆ๋‹ค.

์ด button์˜ ์ž์‹ ๋…ธ๋“œ ์ค‘ ๊ฐ€๊ฒฉ ์ •๋ณด๋ฅผ ๊ฐ€์ง„ span์˜ ๋‚ด์šฉ์„ ๋ฐ”๊พธ๊ณ  ์‹ถ์—ˆ์œผ๋ฏ€๋กœ ์ž์‹ ๋…ธ๋“œ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์†์„ฑ์ธ .childNodes๋ฅผ ํ™œ์šฉํ•ด ์ž์‹ ๋…ธ๋“œ๋ฅผ ๋ณ€์ˆ˜ costSpan์— ์ €์žฅํ–ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ๋ถ€๋ชจ ๋…ธ๋“œ์— .childNodes๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ˜์†”์ฐฝ์—์„œ ์ž์‹ ๋…ธ๋“œ๋“ค์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Untitled

์‚ฌ์ด์‚ฌ์ด์— ๋ณด์ด๋Š” ํ…์ŠคํŠธ ๋…ธ๋“œ๋Š” /n, ์ค„ ๋ฐ”๊ฟˆ ๊ฐ’์ด ์ ์šฉ๋˜์–ด์žˆ์–ด์„œ ๊ทธ๋ ‡๋‹ค.

Untitled

element.parentNode.childNodes[5]๋ผ๊ณ  ์ง€์ •ํ–ˆ๋˜ ์ด์œ ๋Š” ๋ฐ”๋กœ ์ž์‹ ๋…ธ๋“œ๋“ค ์ค‘์— span์ด 5๋ฒˆ ์ธ๋ฑ์Šค์— ํ•ด๋‹นํ•ด์„œ ๊ทธ๋ ‡๋‹ค.

์œ„์˜ ๋‚ด์šฉ์„ ํ† ๋Œ€๋กœ, ๊ทธ๋ฆฌ๊ณ  ์ข€ ๋” ๋ณด์ถฉํ•˜์—ฌ DOM ์š”์†Œ์—์„œ ๋ถ€๋ชจ, ์ž์‹, ํ˜•์ œ ์š”์†Œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์†์„ฑ๋“ค์„ ์ •๋ฆฌํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋ถ€๋ชจ ์š”์†Œ
    • parentNode: ๋ถ€๋ชจ๊ฐ€ ๋˜๋Š” ๋…ธ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
    • parentElement: ๋ถ€๋ชจ๊ฐ€ ๋˜๋Š” DOM ์š”์†Œ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
  • ์ž์‹ ์š”์†Œ
    • childNodes: ์ž์‹์ด ๋˜๋Š” ๋…ธ๋“œ๋“ค์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. ์ด ๋•Œ, ์ด ๋ฆฌ์ŠคํŠธ๋Š” โ€˜์œ ์‚ฌ ๋ฐฐ์—ดโ€™์ด๋‹ค.
    • firstChild: ์ž์‹์ด ๋˜๋Š” ๋…ธ๋“œ๋“ค ์ค‘์— ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
    • lastChild: ์ž์‹์ด ๋˜๋Š” ๋…ธ๋“œ๋“ค ์ค‘์— ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
  • ํ˜•์ œ ์š”์†Œ
    • previousSibling: ๋™์ผ ์„ ์ƒ์— ์žˆ๋Š” ๋…ธ๋“œ ์ค‘์— ๋ฐ”๋กœ ์•ž ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
    • previousElementSibling: ๋™์ผ ์„ ์ƒ์— ์žˆ๋Š” ๋…ธ๋“œ ์ค‘์— ๋ฐ”๋กœ ์•ž DOM ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
    • nextSibling: ๋™์ผ ์„ ์ƒ์— ์žˆ๋Š” ๋…ธ๋“œ ์ค‘์— ๋ฐ”๋กœ ๋’ค ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
    • nextElementSibling: ๋™์ผ ์„ ์ƒ์— ์žˆ๋Š” ๋…ธ๋“œ ์ค‘์— ๋ฐ”๋กœ ๋’ค DOM ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

๋ณธ์ธ์ด ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์€ ๋…ธ๋“œ๊ฐ€ ๋งŒ์•ฝ ์š”์†Œ๋ผ๋ฉด, parentElement, previousElementSibling, nextElementSibling์„ ์จ์„œ ํ™•์‹คํ•˜๊ฒŒ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

3๏ธโƒฃ Tailwind CSS ๋‚ด Important ์ ์šฉ

CSS์—์„œ๋Š” ํŠน์ • ์Šคํƒ€์ผ ๊ฐ’์— ์–ด๋– ํ•œ ๋ณ€ํ™”๋ฅผ ์ฃผ๋”๋ผ๋„ ๋ฐ˜๋“œ์‹œ ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฐ’์ด๋ผ๋ฉด !impotant๋ผ๋Š” ๊ฐ’์„ ๋’ค์— ๋ถ™์ž„์œผ๋กœ์„œ ๋ณ€ํ™”์— ๋”ฐ๋ผ์„œ๋„ ํŠน์ • ๊ฐ’์„ ์œ ์ง€์‹œ์ผœ์ค€๋‹ค.

Tailwind CSS๋Š” class๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— CSS๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋ฏ€๋กœ !impotant ๊ฐ’์„ ์ง์ ‘ ๋ถ™์ผ ์ˆ˜๋Š” ์—†์œผ๋‚˜, Tailwind CSS์—์„œ ์ง€์›ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์›ํ•˜๋Š” ์Šคํƒ€์ผ์— !important ๊ฐ’์„ ๋ถ™์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

๋น„๋ก ์ด๋ฒˆ ์ฑŒ๋ฆฐ์ง€์—์„œ ํ•ด๋‹น ๊ฐ’์„ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋Š” ์‚ฌ์šฉํ•˜๋ ค๋‹ค๊ฐ€ ํ•„์š”๊ฐ€ ์—†์–ด์ ธ ์‚ญ์ œํ–ˆ์œผ๋‚˜, ๋‚˜์ค‘์— ๋˜ ์ฐพ์•„๋ณผ ๊ธฐํšŒ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ด๋ ‡๊ฒŒ ๋ฐฐ์šด ๋‚ด์šฉ์— ๊ธฐ๋กํ•ด๋ณด์•˜๋‹ค.

๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

<script>
  tailwind.config = {
    important: true,
  };
</script>

์œ„์™€ ๊ฐ™์ด ๊ฐ’์„ tailwind.config์—์„œ important์˜ ๊ฐ’์„ true๋กœ ์„ค์ •ํ•˜๋ฉด Tailwind CSS๋กœ ์„ค์ •ํ•œ ๋ชจ๋“  class์˜ ์Šคํƒ€์ผ์€ !important๋ฅผ ํฌํ•จํ•˜๊ฒŒ ๋œ๋‹ค.

๋งŒ์•ฝ, ์ „์ฒด ๋‹ค ์ ์šฉ์ด ์•„๋‹Œ ํŠน์ • class๋‚˜ ํŠน์ • id์—๋งŒ ์ ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

<script>
  tailwind.config = {
    important: "#onlineService",
  };
</script>

์œ„์ฒ˜๋Ÿผ ์„ค์ •ํ•˜๋ฉด onlineService๋ผ๋Š” id ๊ฐ’์„ ๊ฐ€์ง„ ์š”์†Œ์—๋Š” Tailwind CSS๊ฐ€ ๋ฐฐ์น˜๋œ class๋“ค์ด ๋ชจ๋‘ !important๊ฐ’์„ ๊ฐ€์ง„ ์Šคํƒ€์ผ class๋กœ ๋ฐ”๋€๋‹ค.

ํ•˜์ง€๋งŒ, ๋ณดํ†ต !important ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ํ•˜๋‚˜์˜ ์Šคํƒ€์ผ ๊ฐ’์— ๋ณ€ํ™”๋ฅผ ์ฃผ๊ณ  ์‹ถ์ง€ ์•Š์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์„ ๊ฒƒ์ด๋‹ค.

์ด๋•Œ๋Š” ์š”์†Œ์— ๋ฐฐ์น˜๋œ Tailwind CSS class์— !๋ฅผ ๋ถ™์ž„์œผ๋กœ์„œ ํ•ด๋‹น ์Šคํƒ€์ผ์—๋งŒ !important ๊ฐ’์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ, ํ•„์š”ํ•  ๊ฒฝ์šฐ !๋ฅผ ์ ๊ทน ํ™œ์šฉํ•˜์ž.

<input
  id="phone"
  type="text"
  class="border-light-gray border-2 rounded w-full **!px-4 !py-2** outline-0 **focus:!border-purplish-blue** placeholder:text-sm placeholder:font-medium"
  placeholder="e.g. +1 234 567 890"
  onchange="inputValidationCheck(event)" />

4๏ธโƒฃ Tailwind CSS ๋‚ด @apply๋ฅผ ์ด์šฉํ•œ class ๋ณ‘ํ•ฉ

Tailwind CSS๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ class๋“ค์„ ์กฐํ•ฉํ•ด DOM ์š”์†Œ์˜ ์Šคํƒ€์ผ์„ ๊ตฌ์„ฑํ•˜๋„๋ก ๋„์™€์ฃผ๋Š” CSS ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค.

ํ•˜์ง€๋งŒ, ์ด๋Ÿฐ Tailwind CSS๋ฅผ ์ด์šฉํ•˜๋‹ค๋ณด๋ฉด ๋ฒ„ํŠผ UI ๋“ฑ๊ณผ ๊ฐ™์ด ์™„์ „ ๋˜‘๊ฐ™์€ ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜๊ฒŒ ๋˜๋Š” DOM ์š”์†Œ๋“ค์ด ๊ผญ ์žˆ๊ธฐ ๋งˆ๋ จ์ธ๋ฐ, ๊ทธ๋Ÿด ๊ฒฝ์šฐ ํ•˜๋‚˜์˜ ๋ฒ„ํŠผ UI์— ์ ์šฉํ•œ class๋ฅผ ์ „๋ถ€ ๋ณต์‚ฌํ•ด์„œ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธด๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ React ๊ฐ™์€ JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค ์ž…์žฅ์—์„œ๋Š”, ์ด๋ ‡๊ฒŒ ๋ฐ˜๋ณต์ ์ธ ์š”์†Œ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ๋ณด๋‹ค๋Š” ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ๋™์ผํ•œ ์š”์†Œ๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์ฃผ๊ณ  ์‹ถ์€ ์ถฉ๋™์ด ์ƒ๊ธธ ๊ฒƒ์ด๋‹ค.

Tailwind CSS์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๋™์ผํ•œ ์Šคํƒ€์ผ class๋“ค์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์ค„ ์ˆ˜ ์žˆ๋Š”, ์ •ํ˜•ํ™”๋œ ํŒจํ„ด๋“ค์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์ค„ ์ˆ˜ ์žˆ๋Š” @apply๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค.

๋‹จ, ์ด ๊ธฐ๋Šฅ์€ Tailwind CSS์—์„œ ์ถ”๊ตฌํ•˜๋Š” ์ด๋ฆ„์„ ๊ณ ๋ฏผํ•˜์ง€ ์•Š๊ณ  class๋งŒ์œผ๋กœ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉํ–ฅ์„ ๋ฒ—์–ด๋‚˜๋Š” ์‚ฌํ•ญ์ด๋ผ Tailwind CSS์—์„œ๋Š” ์‚ฌ์šฉ ๋ฐฉํ–ฅ์„ ๊ถŒ์žฅํ•˜๊ณ  ์žˆ์ง„ ์•Š๋‹ค. (๋‹จ์ˆœํžˆ ๊น”๋”ํ•˜๊ฒŒ ๋ณด์ด๊ฒŒ ํ•˜๋ ค๊ณ  ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ์ค„์ด๋Š” ๋ฐฉ์‹์„ Tailwind CSS์—์„œ๋Š” ์ข‹์•„ํ•˜์ง€ ์•Š๋Š”๋‹ค.)

Untitled

์ž‘์—… ๋‹น์‹œ์—๋Š” ์ด ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด๋ณด๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ Tailwind CSS๊ฐ€ ์ถ”๊ตฌํ•˜๋Š” ๋ฐฉํ–ฅ๊ณผ ๋‹ค๋ฅธ ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๊ณ , ๋˜ @apply๋ฅผ ์ด์šฉํ•ด class๋ฅผ ๋ฌถ๋Š” ๋ฐฉ์‹์ด ์‹ค์ œ๋กœ๋„ ์ž˜ ์“ฐ์ด๋Š”์ง€ ํŒ๋‹จ์ด ์„œ์ง€ ์•Š์•˜๋‹ค.

๊ทธ๋ž˜์„œ ์‹ค์ œ ์ ์šฉํ•ด๋ณด๊ณ  ๋™์ž‘์ด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์•Œ์•„๋ณธ ๋’ค์— ๋‹ค์‹œ ์›๋ž˜๋Œ€๋กœ class๋ฅผ ๋Œ๋ ค๋†จ์ง€๋งŒ, ๊ธฐ๋ก์„ ํ†ตํ•ด ์ด๋ ‡๊ฒŒ Tailwind CSS์˜ class๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋‚จ๊ฒจ๋‘๋ ค ํ•œ๋‹ค.

์šฐ์„ , CSS ํŒŒ์ผ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .form-input {
    @apply border-light-gray border-2 rounded w-full px-4 py-2 outline-0 focus:border-purplish-blue placeholder:text-sm placeholder:font-medium;
  }
}

@layer๋Š” Tailwind CSS ๋‚ด์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์ •ํ•œ ์Šคํƒ€์ผ ์‹œํŠธ๋ฅผ ๋ชจ์•„๋†“์€ ๋””๋ ‰ํ† ๋ฆฌ ํ˜น์€ ๋ฒ„ํ‚ท์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

์šฐ์„ , Tailwind CSS ๋‚ด์˜ ๋””๋ ‰ํ† ๋ฆฌ๋Š” ํฌ๊ฒŒ base์™€, components, ๊ทธ๋ฆฌ๊ณ  utilities๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

  • base: DOM ์š”์†Œ ๊ทธ ์ž์ฒด(h1, h2, pโ€ฆ)๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ ˆ์ด์–ด์ด๋‹ค.
  • components: ์ฃผ์š” ์Šคํƒ€์ผ๋“ค์„ Tailwind CSS์˜ class๋“ค๋กœ ๋ชจ์•„๋†“์€ ๋ ˆ์ด์–ด์ด๋‹ค.
  • utilities: CSS ์ค‘์— ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ์†์„ฑ๋“ค(focus, filter, hoverโ€ฆ)์„ Tailwind CSS์˜ class๋กœ ๋ชจ์•„๋†“์€ ๋ ˆ์ด์–ด์ด๋‹ค.

์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ์š”์†Œ๋Š” Tailwind CSS์˜ ํด๋ž˜์Šค๋“ค์„ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ, ์ •ํ˜•ํ™”๋œ ํŒจํ„ด์œผ๋กœ ๋ฌถ์–ด์ฃผ๊ธฐ ์œ„ํ•ด class๋กœ ๋ฌถ์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

components ๋ ˆ์ด์–ด์— ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” class์˜ ์ด๋ฆ„๊ณผ ํ•จ๊ป˜ @apply ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๋‹น class์— ๋ฌถ์–ด์ค„ class๋“ค์„ ๋‚˜์—ดํ•ด ๋ฌถ์–ด์ฃผ๋ฉด ํ•ด๋‹น class๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

<input
  id="email"
  type="email"
  class="**form-input**"
  placeholder="e.g. stephenking@lorem.com"
  onchange="inputValidationCheck(event)" />

์ด๋ ‡๊ฒŒ @apply๋ฅผ ์ด์šฉํ•ด ์†์‰ฝ๊ฒŒ Tailwind CSS์˜ class๋“ค์„ ์ •ํ˜•ํ™”๋œ ํ•˜๋‚˜์˜ class๋กœ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ, ์ด ๋ฐฉ์‹์—๋Š” ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋Š” ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Tailwind CSS์—์„œ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ class๋ฅผ ๋‚˜์—ดํ•˜๊ณ  JavaScript ๋“ฑ์„ ํ†ตํ•ด์„œ class๋ฅผ ์ถ”๊ฐ€, ๋ณ€๊ฒฝ, ์ œ๊ฑฐํ•จ์œผ๋กœ์„œ ์†์‰ฝ๊ฒŒ ๊ฐ„๋‹จํ•œ ๋ณ€ํ™”๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ์œ„์™€ ๊ฐ™์ด ํ•˜๋‚˜์˜ class๋กœ ๋ฌถ์–ด๋ฒ„๋ฆฌ๋ฉด ํ•˜๋‚˜๋กœ๋งŒ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ์›ํ•˜๋Š” ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€, ๋ณ€๊ฒฝ, ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ต๋‹ค. (JavaScript์—์„œ DOM ์š”์†Œ์˜ style์„ ํ†ตํ•ด์„œ ๋ณ€๊ฒฝํ•ด์ค˜์•ผ ํ•  ๊ฒƒ์ด๋‹ค.)

๋”ฐ๋ผ์„œ, Tailwind CSS์—์„œ๋Š” ์ •๋ง๋กœ ์ค‘์š”ํ•œ ๋ชฉ์ ์ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ํ•˜๋‚˜์˜ class๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•˜์ง€ ์•Š๊ณ  ์žˆ์œผ๋‹ˆ @apply๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์—๋Š” ์ด ์ ์„ ์ƒ๊ฐํ•˜๊ณ  ํŒ๋‹จํ•ด ์“ฐ๋„๋ก ํ•˜์ž.

5๏ธโƒฃ Tailwind CSS ๋‚ด ์ผํšŒ์„ฑ์ธ ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

Tailwind CSS๊ฐ€ ์ œ๊ณตํ•˜๋Š” class ์ค‘์—์„œ๋Š” ์œ ์ €๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” class๊ฐ€ ์—†๋‹ค๋ฉด tailwind.config์˜ extend ๋“ฑ์„ ํ™œ์šฉํ•˜์—ฌ ๋ฒ”์œ„๋‚˜ ์ƒ‰์ƒ ๋“ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•  class๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์ด๋Ÿฌํ•œ ์ถ”๊ฐ€๋Š” ๋น„ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•œ๋‹ค. ๊ฐ€๋ น 1ํšŒ์„ฑ์œผ๋กœ๋งŒ ์“ฐ์ด๋Š” ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์Šคํƒ€์ผ์„ ์ƒ๊ฐํ•œ๋‹ค๋ฉด, ๊ตณ์ด ํ™•์žฅํ•ด์„œ ์“ธ ํ•„์š”๋Š” ์—†์„ ํ…Œ๋‹ˆ๊นŒ.

Tailwind CSS์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ผํšŒ์„ฑ์œผ๋กœ๋งŒ ์“ฐ์ผ ์ˆ˜ ์žˆ๋Š” ์Šคํƒ€์ผ์„ tailwind.config ๋“ฑ์„ ํ†ตํ•ด ์„ค์ •ํ•˜์ง€ ์•Š๊ณ  class ๋‚ด์—์„œ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ๋Šฅ์„ ์ง€์›ํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จ, **์„ค์ •ํ•˜๊ณ ์ž ํ•˜๋Š” style ์š”์†Œ-[์ผํšŒ์„ฑ ๊ฐ’]**์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

์ฑŒ๋ฆฐ์ง€์—์„  ์ด ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ด ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ํ–ˆ๋‹ค.

<nav
  class="**bg-[url('./assets/images/bg-sidebar-mobile.svg')]** bg-no-repeat bg-cover flex flex-row justify-center gap-4 xsm:hidden w-full h-44 py-8 relative"></nav>

์ด๋ฏธ์ง€ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํฐํŠธ์˜ ํฌ๊ธฐ๋‚˜, border๋‚˜ padding, margin ๊ฐ’ ๋“ฑ ๋‹ค์–‘ํ•œ ์Šคํƒ€์ผ ์š”์†Œ๋“ค์—๋„ ์ผํšŒ์„ฑ์œผ๋กœ ์“ฐ์ด๋Š” ๊ฐ’๋“ค์ด๋ผ๋ฉด ์œ„์˜ ๋ฐฉ์‹์œผ๋กœ ํ‘œํ˜„ํ•ด ์“ธ ์ˆ˜ ์žˆ๋‹ค.

<div class="rounded-[12px]"></div>
<!-- border-radius: 12px -->

<p class="text-[14px]"></p>
<!-- font-size: 12px -->

์ถ”๊ฐ€ ๊ฐœ๋ฐœ ํฌ๋ง ์‚ฌํ•ญ

์ฐธ๊ณ  ์ž๋ฃŒ ๋งํฌ

์ œ์ž‘์ž

ํ›„๊ธฐ