2차원 레이아웃 시스템으로, 행과 열을 동시에 제어하여 복잡한 레이아웃을 간단하게 구현한다.
웹 사이트의 전체 구조 설계에 최적화되어 있다.
2행 이상이 되면 flexbox는 다음 열 컨텐트가 화면에 꽉 차게 되는데, 이를 방지하기 위해 2행 이상이면 grid를 사용하는 것이 좋다.
content box는 정확한 너비 계산이 어려우므로 border box를 사용한다.
사용 예) 전체 페이지 레이아웃, 갤러리, 대시보드
/* Grid 예제 2 : 복잡도가 있는 그리드 레이아웃 연습 (헤더, 사이드바, 메인, 푸터) */
.grid-layout {
display: grid;
grid-template-columns: 200px 1fr; /* 200px 1fr => 사이드바 고정폭, 메인 유동폭 */
/* 사이드바 크기는 고정이고, 메인은 1fr이므로 사이드바가 아닌 곳의 크기를 모두 차지한다. */
grid-template-rows: 60px 1fr 50px; /* 60px 1fr 50px => 헤더 60px 메인 유동폭 푸터 50px */
grid-template-areas: "header header" "sidebar main" "footer footer";
height: 400px;
gap: 10px;
padding: 10px;
background-color: #fce4ec;
}
3-4. 반응형 웹
웹사이트가 데스크탑, 태블릿, 모바일, 폰 등 다양한 화면 크기와 기기에 맞춰 자동으로 최적화된 레이아웃과 디자인을 제공하도록 만드는 웹 디자인 기법
뷰 포트 메타 태그 <meta name="viewport" content="width=device-width, initial-scale=1.0"> : 모바일 기기에서 화면 크기에 맞게 레이아웃이 조정될 수 있도록 하는 필수 설정
미디어 쿼리 @media (max-width: 768px) { ... } : 화면 크기에 따라 CSS 스타일을 다르게 적용해 다양한 기기에서 최적의 레이아웃을 만든다.
유동적 단위 사용 : px 대신 %, em, rem, vw, vh, fr 등 상대 단위를 사용해 요소가 화면 크기에 따라 자연스럽게 변하도록 한다.
max-width:100%; height:auto; : 이미지와 미디어의 반응형 처리로 이미지가 부모 영역을 넘지 않도록 하고, 필요하면 srcset 로 해상도별 이미지를 제공한다.
/* 해상도별 미디어 쿼리 목록 */
@media (max-width: 480px) { /* 작은 스마트폰 */ }
@media (max-width: 600px) { /* 일반 스마트폰 */ }
@media (max-width: 768px) { /* 태블릿 이하 */ }
@media (min-width: 769px) and (max-width: 1200px) { /* 데스크톱 */ }
@media (min-width: 1201px) { /* 큰 데스크톱 */ }
@media (min-resolution: 2dppx) { /* 레티나 디스플레이 */ }
4. JavaScript
4-1. JavaScript 기초
웹 문서의 동적 행위를 담당하는 ECMAScript 표준 스크립트 언어이다.
HTML + CSS + JavaScript 가 웹의 3요소이다.
4-2. ECMAScript
ECMA 인터내셔널이 제정한 JavaScript 표준 명세로 이 표준을 준수하는 스크립트 언어가 JavaScript 이다.
ECMA 인터내셔널 : 정보 통신 표준을 제정하는 표준화 기구
ES5(ECMA5, 2009) : 변수 선언 var -> function level scope 등
ES6(ECMA6, 2015) : 변수 선언 let, const -> Block level (자바의 지역 변수와 scope가 유사), arrow function(화살표 함수), 구조 분해 할당, Template Literal, asyn await 등이 있다.
4-3. 변수와 스코프
var (ES5) : 중복 선언 가능, function level scope 로 호이스팅(hoisting) 시 undefined로 초기화된다.
let (ES6) : 중복 선언 불가능, block level scope 로 재할당이 가능하다. 호이스팅 시 초기화가 이루어지지 않으므로 초기화 없이 사용할 경우 Reference Error 가 발생한다.
JavaScript는 따로 변수의 타입을 정의하지 않는다. 전부 var 또는 let, 상수는 const 로 정의한다.
==와 === : ==는 강제 형변환이 일어난 후 비교한다. ===는 엄격한 비교 시에 사용하며, 타입까지 비교한다.
const (ES6) ; 중복 선언 불가능, block level scope 로 재할당이 불가능하다. 호이스팅 시 초기화가 이루어지지 않으므로 초기화 없이 사용할 경우 Reference Error 가 발생한다.
scope : 변수에 접근할 수 있는 유효한 범위
Global scope : 전역에서 접근이 가능하다.
Function scope : 함수 내부에서만 접근이 가능하다.
Block scope : 블럭 ({}) 내부에서만 접근이 가능하다.
4-4. 호이스팅(Hoisting)
호이스팅 (Hoisting) : 변수와 함수 선언이 코드 실행 전에 맨 위로 끌어 올려진 것처럼 동작하는 현상이다. var 과 function 선언문에서 발생한다.
var : 자신의 scope 맨 위로 선언이 호이스팅되고 초기화는 undefined로 된다.
기존의 var 변수 형식은 코드 예측 가능성을 떨어뜨리고 잠재적인 버그를 유발했다.
let, const : 초기화 없이 선언만 호이스팅하며, TDZ(Temporal Dead Zone : 일시적 사각지대)를 만들어 이 기간 동안 해당 변수에 접근하려고 하면 Reference Error 가 발생한다.
function varTest(num) {
// 선언 하기 전에 사용 가능
alert(a); // 호이스팅에 의해 undefined 으로 초기화 되었기 때문에 undefined 로 출력
if (num > 1) {
var a = 999; // var 로 변수를 선언 function level scope
}
alert(a); // ok : var 변수는 사용 가능 function level scope => why? hoisting 특성 때문
}
// alert(a); //var => function level scope
function letTest(num) {
// alert(b); // var 와 다르게 error
if (num > 0) {
let b = 1;
}
// alert(b); //error let 은 block level scope
console.log(b);
// 선언된 자신의 block 내에서만 사용 가능
}
4-5. DOM (Document Object Model)
문서 객체 모델로, JavaScript에서 HTML Web Document (웹 문서)의 요소를 제어하기 위한 프로그래밍 인터페이스이다.
트리 구조로 문서를 표현하며, 동적 제어가 가능하다.
document.getElementById("id") : id로 html 요소 가져오기
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DOM Event Study</title>
</head>
<body>
<form>
<!-- javascript key event 를 이용해 enter key 눌렀다가 뗄 때 텍스트를 이동시키게 한다 -->
<input type="text" id="orgTxt" onkeyup="enterKeyMoveTxt()" />
<button type="button" onclick="moveTxt()">이동</button>
<input type="text" id="destTxt" />
</form>
<script>
// 버튼 클릭했을 때 실행하는 함수
function moveTxt() {
let orgTxtElement = document.getElementById("orgTxt");
let destTxtElement = document.getElementById("destTxt");
destTxtElement.value = orgTxtElement.value;
orgTxtElement.value = "";
orgTxtElement.focus();
}
// enter key 눌렀다가 뗄 때 실행되는 함수
function enterKeyMoveTxt() {
// alert(event.keyCode); // enter key 의 keyCode 는 13번
if (event.keyCode === 13) {
moveTxt();
}
}
</script>
</body>
</html>
document.querySelector("#id") : 요소의 객체를 리턴받을 수 있다.
4-6. BOM (Browser Object Model)
브라우저 객체 모델로, JavaScript가 브라우저와 소통하기 위해 만들어진 객체 모델이다.
Web Document 가 element를 제외한 웹 브라우저 창에 포함된 객체 요소를 의미한다.
4-7. 화살표 함수와 익명 함수
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>javascript 다양한 함수 표현식</title>
</head>
<body>
<h1>javascript 다양한 함수 표현식(Function Expression)</h1>
<script>
//1. 기본 함수 선언문 function declaration
function test1() {
return "불금";
}
console.log(test1());
// const add 에 익명 함수 객체를 할당
//2. 함수 표현식 function expression : 변수(or 상수)에 할당되는 익명함수
let add = function (a, b) {
// 익명 함수
return a + b;
};
console.log(add(4, 3));
// 함수 표현식
const multiply = function (a, b) {
return a * b;
};
console.log(multiply(3, 7));
//3. 화살표 함수 arrow function
const add2 = (a, b) => {
return a + b;
};
console.log(add2(3, 4));
const add3 = (a, b) => a + b;
console.log(add3(7, 4));
</script>
</body>
</html>
4-7. Inner Html vs TextContent
addEventListener()
querySelector()을 사용하여 이벤트 자원(소스) 객체를 const에 할당한다.
이벤트 발생 시 실행될 행위를 정의하는 이벤트 핸들러를 정의한다.
addEventListener()로 이벤트 바인딩을 한다. 이벤트 소스(자원: button, div, span ... ) 에 특정 이벤트(click)가 발생할 때 실행될 함수(이벤트 핸들러를 등록한다.)
InnerHTML 과 달리 textContainer은 내용이 html 이 아닌 일반 텍스트로 인식된다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>javascript event study</title>
<style>
div {
background-color: antiquewhite;
}
span {
background-color: aquamarine;
}
</style>
</head>
<body>
<h1>javascript event addEventListener 함수</h1>
<div id="divTest">div 영역입니다</div>
<!-- block 속성 : width 100% 꽉 채우는 속성 -->
<br /><br />
<!--
<button type="button" onclick="test()">div 테스트</button>
위의 방식을 아래의 이벤트 처리 방식으로 변경 (querySelector()와 addEventListener())
-->
<button type="button" id="divTestBtn">div 테스트</button>
<br /><br />
<span id="spanTest"> span 영역입니다</span>
<button type="button" id="spanTestBtn">span 테스트</button>
<!--
const spanTestElement = ... ;
const spanTestButton = ... ;
// 화살표 함수 arrow function
const changeSpanContent = 화살표 함수 평화로운 화요일입니다
// 이벤트 등록
// addEventListener
-->
<hr />
<h3>innerHTML vs textContent 비교</h3>
<div id="htmlTest">HTML 테스트 영역</div>
<div id="textTest">Text 테스트 영역</div>
<button type="button" id="compareBtn">
innerHTML 과 textContent 차이 보기
</button>
<!-- 인라인 속성 : 컨텐트 사이즈만큼 영역 차지 -->
<script>
// querySelector 함수를 아용해 요소 객체를 리턴받는다
// 구조와 행위를 분리 -> 응집도 증가
/*
기존 방식 : document.getElementById("divTest");
다른 새로운 방식 : document.querySelector("#divTest"); // # 는 아이디를 의미
*/
// DOM 요소 선택
const divTestElement = document.querySelector("#divTest");
const divTestButton = document.querySelector("#divTestBtn");
// div 제어 - arrow function (화살표 함수)
const changeDivContent = () => {
console.log("현재 div 내용:", divTestElement.innerHTML); // 참고 : form 요소는 value
// 기존 div 내용을 변경
divTestElement.innerHTML = "<strong>즐거운 화요일입니다<strong>";
};
// 이벤트 등록 : addEventListener 로 이벤트 등록
// <button onclick="함수 호출"> 의 역할을 아래에서 한다
divTestButton.addEventListener("click", changeDivContent);
/****************span 영역 이벤트 처리***************/
// 이벤트 소스(자원) 선택
const spanTestElement = document.querySelector("#spanTest");
const spanTestButton = document.querySelector("#spanTestBtn");
//이벤트 발생 시 실행될 함수를 정의 (익명 함수 스타일로)
const changeSpanContent = () => {
//console.log("현재 span 내용:", spanTestElement.innerHTML);
spanTestElement.innerHTML = "평화로운 화요일입니다";
};
//이벤트 등록
spanTestButton.addEventListener("click", changeSpanContent);
/****************innerHTML 과 textContent 비교*****************/
/*
1. 이벤트 자원(소스) 객체를 const 에 할당 : querySelector()
2. 이벤트 핸들러 정의 (이벤트 발생 시 실행될 함수(행위)를 정의)
3. 이벤트 바인딩 (이벤트 발생 시 실행될 함수를 요소 객체에 등록) : addEventListener()
*/
// 1. 이벤트 자원(소스) 객체를 const 에 할당 : querySelector()
const htmlTestElement = document.querySelector("#htmlTest");
const textTestElement = document.querySelector("#textTest");
const compareButton = document.querySelector("#compareBtn");
// 2. 이벤트 핸들러(처리 담당자) 정의 (이벤트 발생 시 실행될 함수(행위)를 정의)
// innerHTML 과 textContext 속성(property)을 비교
const compareHTMLvsText = () => {
// 같은 HTML 태그가 포함된 내용을 설정
const content = "<h4>제목</h4><p>내용:<strong>중요 정보</strong></p>";
// 두 요소에 content 를 할당해본다
htmlTestElement.innerHTML = content;
textTestElement.textContent = content; // 차이를 비교해본다 => textContent 는 content 내용이 그냥 텍스트로 인식된다.
};
// 3. event binding 이벤트 소스(자원: 버튼, div, span ...)에 특정 이벤트(click)가 발생할 때 실행될 함수(이벤트 핸들러)를 등록
// 이벤트 : compareButton 버튼을 눌렀을 때 (click event) compareHTMLvsText 이벤트 핸들러가 동작해야 한다
compareButton.addEventListener("click", compareHTMLvsText);
</script>
</body>
</html>
form event selector
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>form event querySelector</title>
</head>
<body>
<h3>form event querySelector</h3>
<div>
<label>이름:</label>
<input type="text" id="userName" placeholder="이름을 입력하세요" />
<span id="nameResult"> </span>
</div>
<div>
<button class="colorBtn">빨강</button>
<button class="colorBtn">초록</button>
<button class="colorBtn">파랑</button>
<div class="colorDisplay">색상이 여기에 표시돼요</div>
</div>
<div>
<!--
attribute selector(속성 선택자) 예제
button 의 type submit 인 버튼을 선택
-->
<br /><br />
<form id="testForm" action="register.jsp">
<button type="button">button 일반버튼</button>
<br /><br />
<input type="text" placeholder="사용자명" />
<button type="submit">submit 전송버튼</button>
</form>
</div>
<script>
// 이벤트 자원(소스)을 자바스크립트 객체로 const 에 저장
const userNameInput = document.querySelector("#userName");
const nameResultElement = document.querySelector("#nameResult");
// 이벤트 자원에 특정 이벤트 발생시 동작할 이벤트 핸들러를 바인딩 (등록)
// 익명 함수 방식
// input event : 입력할 때마다 이벤트 발생
// userName 을 입력할 때마다 실시간으로 nameResult span 영역에 정보를 출력
userNameInput.addEventListener("input", function (event) {
// event.target : 이벤트가 발생한 DOM 요소
const inputValue = event.target.value;
nameResultElement.textContent = inputValue;
});
/***************css selector**************/
// querySelectorAll() : 같은 클래스를 가진 모든 요소를 선택
const colorButtons = document.querySelectorAll(".colorBtn");
console.log(colorButtons.length);
const colorDisplay = document.querySelector(".colorDisplay");
// forEach 를 사용하여 각 버튼에 이벤트 리스너를 등록
// forEach 은 colorButtons 배열 요소의 수만큼 반복하면서 callback function 을 실행한다 (callback function의 의미는 정의 후 실행)
colorButtons.forEach(function (button, index) {
//버튼에 각각 이벤트 핸들러를 등록한다. 아래는 각 버튼에서 click 이벤트 발생하면
//두번째 매개변수인 익명 함수가 클릭 시 실행된다.
button.addEventListener("click", function (event) {
const colorName = event.target.textContent;
//console.log(colorName);
let backgroundColor = "";
switch (colorName) {
case "빨강":
backgroundColor = "#ffebee";
break;
case "파랑":
backgroundColor = "#e3f2fd";
break;
case "초록":
backgroundColor = "#e8f5e8";
break;
} //switch
colorDisplay.textContent = "선택된 색상:" + colorName;
colorDisplay.style.backgroundColor = backgroundColor;
});
});
/******************attribute selector([attribute])****************/
// attribute 로 selector : 특정 속성값을 가진 요소를 선택
// 즉 button 중에서 type이 submit 인 버튼만 alert 가 나오도록 할 수 있다.
const submitButton = document.querySelector("button[type='submit']");
submitButton.addEventListener("click", function (event) {
// 기본 동작(폼 제출)을 막음
// 특정 조건이 충족되지 않을 때 submit 버튼의 전송 동작을 막는다.
event.preventDefault();
// 폼 내의 input 요소를 선택, #testForm 아이디 하위의 input type text 요소를 선택
// testForm 하위의 input 중 type이 text 인 것을 고르기
const textInput = document.querySelector(
"#testForm input[type='text']"
);
alert(textInput.value);
});
</script>
</body>
</html>
4-8. forEach 문
// 기존 for 문
for (let i = 0; i < foods.length; i++) {
console.log(`${i + 1}번째 음식: ${foods[i]}`);
}
// forEach 문
foods.forEach(function (food, index) {
console.log(`${index + 1}번째 과일: ${food}`);
});