작업일2026. 07

웹페이지는 HTML, CSS, JavaScript가 함께 구성합니다. HTML은 문서 구조를 만들고, CSS는 화면 표현을 정의하며, JavaScript는 사용자 입력과 상태 변화에 대응합니다. 프론트엔드의 기본 구성을 정리했습니다.
웹 개발을 시작하면 이 셋을 거의 동시에 배우게 됩니다. 그래서 각 기술의 역할 범위가 헷갈리기 쉽습니다. 역할을 구분해두면 React 같은 프레임워크를 배울 때도 도움이 됩니다.
HTML: 문서의 구조
HTML(HyperText Markup Language)은 태그로 문서의 구조를 정의하는 마크업 언어입니다. 프로그래밍 언어가 아니라 "이건 제목이고 저건 문단이다"라고 표시(markup)해주는 언어입니다. 브라우저는 이 표시를 읽어 화면을 그립니다.
요소와 속성
HTML의 기본 단위는 요소(Element)입니다. 시작 태그, 내용, 끝 태그로 이루어집니다.
<h1>가장 큰 제목</h1>
<p>평범한 문단입니다.</p>
<br> <!-- 내용이 없는 요소는 끝 태그도 없습니다 -->
요소 안에 요소를 중첩할 수 있고, 속성(Attribute)으로 추가 정보를 줍니다. 속성은 항상 시작 태그 안에 들어갑니다.
<a href="https://example.com">링크</a>
<img src="cat.jpg" alt="고양이 사진">
alt는 이미지를 표시할 수 없을 때 대체로 제공할 텍스트입니다. 스크린 리더도 이 값을 읽으므로 접근성과 SEO에 영향을 줍니다. 의미 있는 이미지는 작성하는 것이 좋습니다.
id와 class
| 속성 | 의미 | 개수 | 주 용도 |
|---|---|---|---|
id |
고유 식별자 | 문서에 하나만 | 특정 요소를 콕 집을 때 |
class |
공유 가능한 이름 | 여러 개 가능 | 같은 스타일을 묶을 때 |
문서의 기본 뼈대
<!DOCTYPE html> <!-- HTML5 문서라는 선언 -->
<html lang="ko">
<head> <!-- 화면에 안 보이는 문서 정보 -->
<meta charset="UTF-8">
<title>페이지 제목</title> <!-- 브라우저 탭에 뜨는 이름 -->
</head>
<body> <!-- 실제로 화면에 보이는 내용 -->
<h1>안녕하세요</h1>
</body>
</html>
역할별 태그
| 분류 | 대표 태그 | 쓰임 |
|---|---|---|
| 텍스트 | h1~h6, p, span, strong, a |
제목·문단·강조·링크 |
| 목록 | ul, ol, li |
순서 없는/있는 목록 |
| 표 | table, thead, tbody, tr, th, td |
행과 열 데이터 |
| 폼 | form, input, label, button |
사용자 입력받기 |
| 미디어 | img, video, audio |
이미지·영상·소리 |
| 시맨틱 | header, nav, main, section, footer |
의미를 가진 구획 |
<div>만으로도 화면은 구성할 수 있습니다. 다만 <header>, <nav>를 사용하면 검색엔진과 스크린 리더가 콘텐츠의 역할을 더 정확히 해석할 수 있습니다. 화면은 같아도 문서의 의미 정보가 달라집니다.Block과 Inline
요소마다 기본 배치 방식이 있습니다. 이를 알아야 width와 height의 적용 결과를 예측할 수 있습니다.
| 구분 | Block 요소 | Inline 요소 |
|---|---|---|
| 배치 | 혼자 한 줄 차지 (세로로 쌓임) | 다른 요소와 한 줄에 나란히 |
| 크기 | 가로 폭을 최대로 | 내용 크기만큼만 |
| width / height | 적용됨 | 무시됨 |
| 예 | div, p, h1, ul |
span, a, strong, img |
<span> 같은 inline 요소에는 width: 200px이 적용되지 않습니다. 크기를 지정하려면 display: block 또는 inline-block으로 변경해야 합니다.CSS: 보이는 모습
CSS(Cascading Style Sheets)는 HTML 요소를 화면에 어떻게 보여줄지 정의하는 스타일시트 언어입니다. 색, 글꼴, 간격, 위치, 레이아웃이 전부 CSS의 영역입니다.
문법과 적용 방법
p { /* 선택자: 누구에게 */
color: red; /* 속성: 값 */
text-align: center;
}
적용 방법은 세 가지입니다. 일반적으로는 스타일과 구조를 분리하기 위해 외부 파일(External) 방식을 사용합니다.
<link rel="stylesheet" href="style.css"> <!-- 권장 -->
<style> p { color: red; } </style> <!-- 문서 안에 -->
<p style="color:red;">…</p> <!-- 태그에 직접, 지양 -->
선택자: 누구에게 스타일을 줄까
| 선택자 | 예시 | 의미 |
|---|---|---|
| 요소 | p { } |
모든 p 태그 |
| id | #header { } |
id가 header인 요소 |
| class | .menu { } |
class가 menu인 요소 |
| 자식 | div > p { } |
div의 바로 아래 p |
| 후손 | div p { } |
div 안의 모든 p |
| 의사 클래스 | a:hover { } |
마우스를 올린 상태 |
우선순위: 스타일이 안 먹을 때
여러 규칙이 같은 요소를 가리키면 충돌합니다. 이때 명시도(Specificity)가 높은 쪽이 이깁니다.
인라인 스타일 > id > class · 속성 · 의사클래스 > 요소
- 명시도가 높은 규칙이 우선합니다. class 선택자 하나는 요소 선택자 여러 개보다 우선합니다.
- 명시도가 같으면 나중에 작성한 규칙이 적용됩니다. 이것이 "Cascading"의 의미입니다.
!important는 예외적으로만 사용합니다. 우선순위 문제를 임시로 덮을 수 있어 유지보수가 어려워집니다. 먼저 선택자와 적용 순서를 확인하는 편이 좋습니다.박스 모델
CSS 레이아웃의 기본 개념입니다. 모든 HTML 요소는 네 영역으로 구성됩니다.
width 는 맨 안쪽 content 의 너비만 가리킵니다width는 content 영역만의 너비입니다. width: 300px; padding: 25px;이면 실제 차지하는 너비는 300 + 25×2 = 350px가 됩니다. 보통은
box-sizing: border-box;를 사용합니다. padding과 border를 width에 포함하므로 지정한 값으로 전체 너비를 관리할 수 있습니다.position: 위치 잡기
| 값 | 동작 | 자주 쓰는 곳 |
|---|---|---|
static |
기본값. 문서 흐름 그대로 | 거의 지정하지 않음 |
relative |
원래 위치 기준으로 살짝 이동 (자리는 유지) | 미세 조정, absolute의 기준점 |
absolute |
가장 가까운 위치 지정 조상 기준 (문서 흐름에서 빠짐) | 배지, 툴팁, 닫기 버튼 |
fixed |
화면 기준 고정 (스크롤해도 안 움직임) | 플로팅 버튼 |
sticky |
스크롤하다 특정 지점에서 고정 | 상단 헤더, 목차 |
Flexbox와 Grid
과거에는 float로 레이아웃을 구성했지만, 현재는 Flexbox와 Grid를 주로 사용합니다.
| 구분 | Flexbox | Grid |
|---|---|---|
| 차원 | 1차원 (가로 또는 세로) | 2차원 (행 과 열) |
| 잘하는 것 | 한 줄 안에서 정렬·간격 배분 | 페이지 전체를 격자로 나누기 |
| 쓰는 곳 | 내비게이션 바, 카드 안 요소 정렬 | 전체 레이아웃, 갤러리, 대시보드 |
/* Flexbox: 가운데 정렬 */
.container {
display: flex;
justify-content: center; /* 메인 축(가로) 정렬 */
align-items: center; /* 교차 축(세로) 정렬 */
}
/* Grid: 2열 레이아웃 */
.layout {
display: grid;
grid-template-columns: 1fr 2fr; /* 1:2 비율로 두 열 */
gap: 20px;
}
둘은 함께 사용할 수 있습니다. 예를 들어 페이지 레이아웃에는 Grid, 내부 요소 정렬에는 Flexbox를 사용할 수 있습니다.
JavaScript: 페이지의 동작
JavaScript는 웹페이지의 동작과 로직을 구현하는 프로그래밍 언어입니다. HTML 콘텐츠와 CSS 스타일을 변경하고, 사용자 입력에 반응할 수 있습니다.
먼저 세 가지 성격을 알아두면 쉽게 이해할 수 있습니다.
- 인터프리터: 컴파일 없이 브라우저가 한 줄씩 읽으며 바로 실행합니다.
- 동적 타입: 변수를 만들 때 타입을 정하지 않습니다. 값이 들어가는 순간 결정됩니다.
- 싱글 스레드: 한 번에 하나씩만 처리합니다. 그래서 비동기가 중요해집니다.
변수: var, let, const
| 키워드 | 스코프 | 재선언 | 재할당 | 지금 쓰나? |
|---|---|---|---|---|
var |
함수 | 가능 | 가능 | ❌ 쓰지 않습니다 |
let |
블록 { } |
불가 | 가능 | ⭕ 값이 바뀔 때 |
const |
블록 { } |
불가 | 불가 | ⭕ 기본값 |
const를 사용하고, 재할당이 필요할 때만 let을 사용합니다. 새 코드에서는 var를 피하는 편이 좋습니다.호이스팅(Hoisting)은 JS가 변수 선언을 스코프 맨 위로 끌어올리는 동작입니다. var는 값이 없는 채로 올라가서 선언 전에 접근해도 에러 대신 undefined가 나옵니다. 이게 조용한 버그의 원인이 되며, let·const가 권장되는 이유 중 하나입니다.
데이터 타입
| 구분 | 원시형 (Primitive) | 객체형 (Object) |
|---|---|---|
| 종류 | number, string, boolean, null, undefined | object, array, function |
| 저장 방식 | 값 자체를 저장 | 값이 있는 주소를 저장 |
| 변경 | 불변 | 가변 |
객체를 복사한 뒤 원본 변경이 함께 반영되는 문제가 생길 수 있습니다. 객체 변수는 값 자체가 아니라 참조를 복사하기 때문입니다.
DOM: HTML을 객체로 다루기
DOM(Document Object Model)은 브라우저가 HTML 문서를 트리 구조의 객체로 표현한 것입니다. JavaScript는 DOM을 통해 페이지 콘텐츠와 상태를 변경합니다. 즉 JavaScript는 HTML 소스 자체가 아니라 브라우저가 구성한 DOM을 조작합니다.
// ① 요소를 찾고
const el = document.getElementById("demo");
// ② 내용을 바꾸고
el.innerHTML = "안녕하세요";
// ③ 스타일도 바꿉니다
el.style.color = "red";
요소를 찾는 방법은 여러 가지입니다. CSS 선택자를 사용할 수 있는 querySelector()가 자주 쓰입니다.
document.getElementById("demo"); // id로
document.querySelector(".menu"); // CSS 선택자로 (첫 번째 하나)
document.querySelectorAll(".menu"); // CSS 선택자로 (전부)
이벤트
클릭, 입력, 스크롤처럼 페이지에서 발생하는 일이 이벤트입니다. 이벤트 등록에는 여러 방법이 있지만, 일반적으로 addEventListener를 사용합니다.
<!-- 비권장: HTML에 JS를 섞으면 관리가 안 됩니다 -->
<button onclick="doSomething()">클릭</button>
// 권장: 핸들러를 여러 개 달 수 있고, HTML과 완전히 분리됩니다
const btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
document.getElementById("demo").innerHTML = "눌렸습니다!";
});
이벤트 전파: <div> 안의 <button>을 클릭하면 이벤트는 요소 계층을 따라 전달됩니다. 전달 방향에는 두 가지가 있습니다.
| 구분 | 버블링 (Bubbling) | 캡처링 (Capturing) |
|---|---|---|
| 방향 | 자식 → 부모 (안에서 밖으로) | 부모 → 자식 (밖에서 안으로) |
| 설정 | 기본값 | addEventListener(t, fn, true) |
| 활용도 | 높음 (이벤트 위임의 원리) | 낮음 |
자주 쓰는 제어 두 가지도 알아두면 좋습니다.
event.preventDefault(): 태그의 기본 동작을 막습니다. 폼 제출 시 새로고침되는 걸 막을 때 거의 항상 씁니다.event.stopPropagation(): 부모로 전파되는 걸 중단합니다.
비동기
JavaScript는 싱글 스레드로 실행됩니다. 네트워크 요청처럼 시간이 걸리는 작업을 동기적으로 처리하면 UI 응답이 지연될 수 있습니다. 이런 작업을 기다리는 동안 다른 코드를 실행하도록 처리하는 방식이 비동기입니다.
비동기 처리 방식은 다음과 같이 발전해 왔습니다.
| 세대 | 방식 | 특징 |
|---|---|---|
| 1세대 | Callback | 중첩이 깊어지면 코드 흐름을 파악하기 어려움 |
| 2세대 (ES6) | Promise | 상태를 객체로 만들어 .then() / .catch()로 연결 |
| 3세대 (ES8) | async / await | 비동기 코드를 동기 코드처럼 읽을 수 있음. 현재 널리 사용 |
Promise는 비동기 작업의 완료 또는 실패 결과를 나타내는 객체입니다. 세 가지 상태를 가집니다.
- Pending: 아직 진행 중
- Fulfilled: 성공, 결과값이 있음
- Rejected: 실패, 에러가 있음
// async/await: Promise를 훨씬 읽기 쉽게 쓴 것
async function getData() {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
console.log(data);
}
셋이 함께 일하는 모습
버튼을 클릭하면 문구가 바뀌는 예제입니다. HTML, CSS, JavaScript가 각각 무엇을 처리하는지 확인할 수 있습니다.
<!-- HTML : 무엇이 있는가 -->
<button id="btn">클릭</button>
<p id="msg" class="greeting">안녕하세요</p>
<!-- CSS : 어떻게 보이는가 -->
<style>
.greeting { color: navy; font-size: 20px; }
</style>
<!-- JavaScript : 어떻게 움직이는가 -->
<script>
document.getElementById("btn").addEventListener("click", () => {
document.getElementById("msg").innerHTML = "반갑습니다!";
});
</script>
HTML이 버튼과 문단을 만들고, CSS가 색과 크기를 정의하며, JavaScript가 클릭 이벤트에 따라 내용을 변경합니다. 세 파일로 분리해도 동일하게 동작합니다. 역할을 분리하면 코드 관리가 쉬워집니다.
정리하면
처음부터 모든 태그와 속성을 외울 필요는 없습니다. 문법은 필요할 때 문서를 참고하면 됩니다. 대신 block과 inline의 차이, 박스 모델의 계산 방식, DOM의 개념은 반드시 이해해두는 것이 좋습니다. 이 세 가지를 기준으로 나머지 개념을 확장해 나갈 수 있습니다.
참고
- MDN Web Docs: HTML · CSS · JavaScript
- W3Schools: 예제를 바로 돌려볼 수 있어 처음 배울 때 좋습니다
- roadmap.sh: Frontend
앞 글에서는 이 파일들이 서버에서 브라우저까지 어떻게 도착하는지(HTTP·DNS·TCP/IP) 정리했습니다.
'소프트웨어 개발 > 웹' 카테고리의 다른 글
| 묵시적 커밋과 AUTO COMMIT | TRUNCATE와 DELETE 차이, 롤백 안 되는 자리 (0) | 2026.08.07 |
|---|---|
| JavaScript 비동기 처리| 이벤트 루프, Promise, async/await, Fetch (0) | 2026.07.26 |
| 웹 개발을 위한 네트워크 기초 (0) | 2026.07.26 |