첫 웹 페이지 만들기
HTML 구조와 CSS 스타일, JavaScript 클릭 이벤트를 연결해 자기소개가 담긴 첫 웹 페이지를 완성합니다.
앞선 절에서 웹의 기본 원리와 핵심 언어, 그리고 개발 환경 설정까지 마쳤습니다.
이제 이 모든 지식과 도구를 활용하여 여러분의 첫 번째 웹 페이지를 직접 만들어 볼 시간입니다.
우리가 방금 설정한 개발 환경에서 HTML, CSS, 그리고 자바스크립트 코드를 직접 작성하고, 그 결과물을 웹 브라우저에서 바로 확인하게 됩니다.
이 실습에서는 HTML, CSS, JavaScript 파일을 연결해 브라우저에 표시되는 첫 페이지를 만듭니다.
이번 장에서는 여러분의 이름과 간단한 소개가 담긴 개인 웹 페이지를 만들어 볼 것입니다.
이를 통해 HTML로 구조를 만들고, CSS로 스타일을 적용하며, 자바스크립트로 간단한 상호작용을 추가하는 과정을 실제 예시로 경험하게 됩니다.
첫 페이지 파일 연결과 브라우저 실행 순서 — 상태 추적
HTML 파서·서버·일반 script의 실제 메시지 순서와 버튼 handler 준비 여부가 중요하다. 본문 contactButton 예제에 맞춰 파일 요청→스크립트 등록→DOMContentLoaded를 분리할 가치가 있다.
FIRST PAGE INTEGRATION
본문 끝 스크립트가 앞의 버튼에 동작을 연결합니다
HTML 파싱 중 CSS·JS를 요청하고, 교재의 일반 script가 실행된 뒤 파싱 완료와 DOMContentLoaded에 도달합니다.
본문 끝 script · 대상 요소를 먼저 구성
<button id="contactButton">
문의하기
</button>
<script
src="profile_script.js">
</script>그림은 교재의 async·defer 없는 일반 script를 기준으로 합니다. 클릭 핸들러는 문의 기능 대신 alert를 보여줍니다.
* 응답 수신과 실행은 구분
일반 script는 먼저 발견된 blocking stylesheet를 기다릴 수 있습니다. CSS 응답은 그림에서 생략했습니다. 모바일의 HTML·CSS·JS는 각각 my_profile.html·profile_style.css·profile_script.js를 가리킵니다. 요청 간격·수명선 길이는 실제 소요 시간이 아닙니다.
DOMContentLoaded는 문서 파싱과 관련 스크립트 실행 완료를 알리는 시점입니다. 이미지 등 모든 자원 로드와는 구분합니다. Network에서 실제 세 파일 요청, Console에서 오류·load 메시지, 버튼 조작에서 alert를 확인합니다.
이 예의 조건
- 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
- 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
관계도의 보충 설명
| 구분 | 내용 |
|---|---|
| 원도표 설명 | 그림은 교재의 async·defer 없는 일반 script를 기준으로 합니다. 클릭 핸들러는 문의 기능 대신 alert를 보여 줍니다. |
| 장면 | 현재 관찰값 | 설명 | 변화 이유 |
|---|---|---|---|
| HTML 파싱 중 | 문서: 아직 파싱 중 / 버튼: 핸들러 등록 전 | 파서가 첫 문서를 읽으며 필요한 파일을 요청한다 | 문서와 script는 별도 입력이다 |
| 스크립트 실행 | 스크립트: 현재 실행 / 버튼: 이벤트 handler 등록 | 해당 스크립트가 DOM 대상을 찾아 handler를 연결한다 | 실제 DOM에 handler가 연결되어 후속 클릭을 받을 수 있다 |
| 파싱 완료를 알린다 | 문서: 파싱 완료 / 이미지: 모두 완료라는 뜻은 아님 | DOMContentLoaded는 문서 파싱 및 해당 대기 스크립트 뒤의 사건이다 | DOMContentLoaded와 전체 자원 load는 서로 다른 완료 조건이다 |
첫 페이지 파일 연결과 브라우저 실행 순서 — 상태 추적
HTML 파서·서버·일반 script의 실제 메시지 순서와 버튼 handler 준비 여부가 중요하다. 본문 contactButton 예제에 맞춰 파일 요청→스크립트 등록→DOMContentLoaded를 분리할 가치가 있다.
FIRST PAGE INTEGRATION
본문 끝 스크립트가 앞의 버튼에 동작을 연결합니다
HTML 파싱 중 CSS·JS를 요청하고, 교재의 일반 script가 실행된 뒤 파싱 완료와 DOMContentLoaded에 도달합니다.
본문 끝 script · 대상 요소를 먼저 구성
<button id="contactButton">
문의하기
</button>
<script
src="profile_script.js">
</script>그림은 교재의 async·defer 없는 일반 script를 기준으로 합니다. 클릭 핸들러는 문의 기능 대신 alert를 보여줍니다.
* 응답 수신과 실행은 구분
일반 script는 먼저 발견된 blocking stylesheet를 기다릴 수 있습니다. CSS 응답은 그림에서 생략했습니다. 모바일의 HTML·CSS·JS는 각각 my_profile.html·profile_style.css·profile_script.js를 가리킵니다. 요청 간격·수명선 길이는 실제 소요 시간이 아닙니다.
DOMContentLoaded는 문서 파싱과 관련 스크립트 실행 완료를 알리는 시점입니다. 이미지 등 모든 자원 로드와는 구분합니다. Network에서 실제 세 파일 요청, Console에서 오류·load 메시지, 버튼 조작에서 alert를 확인합니다.
이 예의 조건
- 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
- 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
관계도의 보충 설명
| 구분 | 내용 |
|---|---|
| 원도표 설명 | 그림은 교재의 async·defer 없는 일반 script를 기준으로 합니다. 클릭 핸들러는 문의 기능 대신 alert를 보여 줍니다. |
| 장면 | 현재 관찰값 | 설명 | 변화 이유 |
|---|---|---|---|
| HTML 파싱 중 | 문서: 아직 파싱 중 / 버튼: 핸들러 등록 전 | 파서가 첫 문서를 읽으며 필요한 파일을 요청한다 | 문서와 script는 별도 입력이다 |
| 스크립트 실행 | 스크립트: 현재 실행 / 버튼: 이벤트 handler 등록 | 해당 스크립트가 DOM 대상을 찾아 handler를 연결한다 | 실제 DOM에 handler가 연결되어 후속 클릭을 받을 수 있다 |
| 파싱 완료를 알린다 | 문서: 파싱 완료 / 이미지: 모두 완료라는 뜻은 아님 | DOMContentLoaded는 문서 파싱 및 해당 대기 스크립트 뒤의 사건이다 | DOMContentLoaded와 전체 자원 load는 서로 다른 완료 조건이다 |
HTML: 웹 페이지의 뼈대 세우기
가장 먼저 HTML을 사용하여 웹 페이지의 기본 구조를 만듭니다.
나의 소개라는 제목과 함께 여러분의 이름, 간단한 자기소개 문구, 그리고 몇 가지 정보를 담을 공간을 마련할 것입니다.
- 개발 환경 설정 절에서 만든
web-dev-practice폴더를 VS Code에서 엽니다. - 폴더 안에 새로운 파일
my_profile.html을 생성합니다. (기존index.html은 그대로 두고, 이번 실습을 위한 새 파일을 만듭니다.)
my_profile.html파일에 다음 코드를 입력합니다. (VS Code에서html:5를 입력한 후Tab키를 누르면 기본 구조가 자동 완성됩니다.)[여러분의 이름]은 예제의 자리 표시자입니다.title·h1·푸터에서 자신의 이름으로 바꾸세요.title은 브라우저 탭에,h1은 페이지 안에 보이므로 두 위치를 각각 확인합니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>나의 첫 프로필 페이지 - [여러분의 이름]</title>
</head>
<body>
<header>
<h1>안녕하세요, [여러분의 이름]입니다!</h1>
<p>웹 개발을 시작하는 초보 개발자입니다.</p>
</header>
<section>
<h2>저를 소개합니다</h2>
<p>
저는 새로운 기술을 배우는 것을 즐기며, 특히 웹 개발에 깊은 흥미를 느끼고 있습니다.
이 책과 함께 여러분과 함께 성장하고 싶습니다.
</p>
<ul>
<li><strong>취미:</strong> 독서, 산책</li>
<li><strong>좋아하는 것:</strong> 맛있는 커피, 새로운 지식</li>
<li><strong>목표:</strong> 나만의 멋진 웹 서비스 만들기</li>
</ul>
</section>
<footer>
<p>© 2025 [여러분의 이름]. All rights reserved.</p>
<button id="contactButton">문의하기</button>
</footer>
</body>
</html><!DOCTYPE html>: 이 문서가 HTML5 표준을 따른다는 것을 웹 브라우저에 알려줍니다.<html lang="ko">: 문서의 시작을 알리며, 문서의 기본 언어가 한국어임을 명시합니다. 이는 검색 엔진이나 스크린 리더 등에 유용합니다.<head>: 웹 페이지 자체에 대한 정보(메타데이터)를 담는 부분입니다. 사용자에게 직접 보이지는 않지만, 웹 페이지의 설정과 관련된 중요한 내용이 들어갑니다.<meta charset="UTF-8">: 문서의 문자 인코딩을 UTF-8로 설정합니다. 한글이 깨지지 않도록 하는 매우 중요한 설정입니다.<meta name="viewport" ...>: 웹 페이지가 다양한 기기(모바일, 태블릿 등)에서 올바르게 표시되도록 뷰포트 설정을 정의합니다. 반응형 웹을 위한 필수 설정입니다.<title>: 웹 브라우저 탭에 표시될 웹 페이지의 제목을 설정합니다.
<body>: 웹 브라우저 화면에 실제로 표시될 모든 콘텐츠가 들어가는 부분입니다.<header>: 페이지의 머리글 영역을 나타냅니다. 주로 제목이나 로고, 내비게이션 바 등이 들어갑니다.<h1>,<p>: 제목과 단락을 나타내는 태그입니다.<section>: 문서의 독립적인 섹션을 나타냅니다.<h2>: 두 번째 수준의 제목을 나타냅니다.<ul>,<li>: 순서 없는 목록(Unordered List)과 목록의 각 항목(List Item)을 나타냅니다.<strong>: 텍스트를 강조하는 태그입니다.<footer>: 페이지의 바닥글 영역을 나타냅니다. 주로 저작권 정보나 연락처 등이 들어갑니다.<button>: 클릭할 수 있는 버튼을 만듭니다.id="contactButton"은 나중에 자바스크립트에서 이 버튼을 쉽게 찾기 위한 고유한 이름입니다.
my_profile.html파일을 저장합니다.- Live Server를 설치했다면
my_profile.html을 우클릭해 Open with Live Server로 여세요.Go Live가 다른 시작 파일을 열면 주소 끝이my_profile.html인지 확인합니다. 확장 프로그램 없이 따라갈 때는 이 파일을 더블 클릭해 열고, 수정·저장 뒤 직접 새로고침해도 됩니다. - 웹 브라우저에 여러분이 작성한 HTML 내용이 표시될 것입니다. 아직 스타일이 적용되지 않아 다소 밋밋하게 보일 수 있습니다. 마치 건물의 뼈대만 완성된 상태입니다.
CSS: 웹 페이지에 스타일 입히기
이제 HTML로 만든 뼈대에 CSS를 사용하여 옷을 입히고 아름답게 꾸며줄 차례입니다.
색상, 글꼴, 여백 등을 조절하여 웹 페이지를 시각적으로 매력 있게 만들어 봅시다.
web-dev-practice폴더 안에 새로운 파일profile_style.css를 생성합니다. (개발 환경 설정 절에서 만든style.css는 그대로 두고 새 파일을 만듭니다.)
my_profile.html파일로 돌아와</head>태그 바로 앞에 다음 코드를 추가합니다.
<link rel="stylesheet" href="profile_style.css">- 이 코드는
my_profile.html파일이profile_style.css파일의 스타일 규칙을 적용받도록 연결해 줍니다.
profile_style.css파일에 다음 CSS 코드를 작성합니다.
/* 전체 페이지에 적용될 기본 스타일 */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f0f2f5; /* 연한 회색 배경 */
color: #333;
line-height: 1.6;
margin: 0;
padding: 0;
display: flex; /* Flexbox를 사용하여 콘텐츠를 중앙에 배치 */
flex-direction: column;
align-items: center;
min-height: 100vh; /* 최소 화면 높이 */
}
/* 헤더 스타일 */
header {
background-color: #007bff; /* 파란색 배경 */
color: white;
padding: 40px 20px;
width: 100%;
box-sizing: border-box; /* padding을 지정한 너비 안에 포함 */
text-align: center;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
header h1 {
margin-bottom: 10px;
font-size: 2.8em;
}
header p {
font-size: 1.2em;
opacity: 0.9;
}
/* 섹션 스타일 */
section {
background-color: white;
margin: 30px 20px;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
max-width: 800px;
width: calc(100% - 40px); /* 좌우 margin 20px씩 제외 */
box-sizing: border-box; /* padding을 지정한 너비 안에 포함 */
text-align: left;
}
section h2 {
color: #0056b3;
margin-bottom: 20px;
font-size: 2em;
border-bottom: 2px solid #eee;
padding-bottom: 10px;
}
section ul {
list-style: none; /* 목록 마커 제거 */
padding: 0;
margin-top: 20px;
}
section ul li {
background-color: #e9f7fe; /* 연한 하늘색 배경 */
margin-bottom: 10px;
padding: 12px 15px;
border-left: 5px solid #007bff;
border-radius: 5px;
font-size: 1.1em;
}
section ul li strong {
color: #004d66;
}
/* 푸터 스타일 */
footer {
background-color: #333;
color: white;
text-align: center;
padding: 20px;
width: 100%;
box-sizing: border-box; /* padding을 지정한 너비 안에 포함 */
margin-top: auto; /* 하단에 고정 */
}
footer p {
margin-bottom: 15px;
font-size: 0.9em;
opacity: 0.8;
}
/* 버튼 스타일 */
#contactButton { /* ID 선택자 사용 */
background-color: #28a745; /* 녹색 버튼 */
color: white;
padding: 12px 25px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1.1em;
transition: background-color 0.3s ease, transform 0.2s ease; /* 호버 애니메이션 */
}
#contactButton:hover {
background-color: #218838; /* 진한 녹색 */
transform: translateY(-2px); /* 살짝 위로 */
}profile_style.css와my_profile.html파일을 저장합니다. (Live Server를 사용 중이라면 자동으로 새로고침됩니다.)- 웹 브라우저에서 여러분의 프로필 페이지가 확연히 달라진 것을 확인할 수 있을 것입니다. 배경색이 바뀌고, 글꼴이 정돈되며, 각 영역이 깔끔하게 구분되어 보일 것입니다. 브라우저에서 배경색, 글꼴, 영역 구분이 적용되었는지 확인합니다.
- 스타일이 적용되지 않으면
href의 파일 이름과profile_style.css가 같은 폴더에 있는지 확인합니다.
JavaScript: 웹 페이지에 상호작용 추가하기
마지막으로 자바스크립트를 사용하여 웹 페이지에 동적인 기능을 추가해 봅시다.
문의하기 버튼을 클릭하면 경고창이 나타나도록 만들어 보겠습니다.
web-dev-practice폴더 안에 새로운 파일profile_script.js를 생성합니다. (개발 환경 설정 절에서 만든script.js는 그대로 두고 새 파일을 만듭니다.)
my_profile.html파일로 돌아와</body>태그 바로 앞(푸터 아래)에 다음 코드를 추가합니다.
<script src="profile_script.js"></script>- 브라우저는 HTML을 읽으며 요소 구조인 DOM을 만듭니다. 이 예제는
script를 버튼 뒤,</body>바로 앞에 두므로 스크립트가 실행될 때contactButton요소를 이미 찾을 수 있습니다. 스크립트를 버튼보다 앞에 옮기면 아직 없는 요소를 찾다가null을 얻을 수 있으므로 지금은 이 위치를 유지하세요. - 그림의
DOMContentLoaded는 문서 파싱이 끝난 시점을 가리킵니다. 예제의window.onload는 이미지 같은 추가 자원의 로드까지 기다리는 별도 시점입니다. 앞서 발견한 스타일시트가 일반 스크립트의 실행을 기다리게 할 수 있다는 세부 조건은 MDN의 DOMContentLoaded 설명에서 확인할 수 있습니다.
profile_script.js파일에 다음 자바스크립트 코드를 작성합니다.
// '문의하기' 버튼 요소를 ID로 선택합니다.
const contactButton = document.getElementById('contactButton');
// 버튼에 클릭 이벤트 리스너를 추가합니다.
contactButton.addEventListener('click', function() {
// 버튼이 클릭될 때 경고창(alert)을 띄웁니다.
alert('아직 문의 기능은 개발 중입니다. 잠시만 기다려주세요! 😊');
});
// 페이지가 로드되면 실행되는 메시지 (선택 사항)
window.onload = function() {
console.log('프로필 페이지가 성공적으로 로드되었습니다!');
// 개발자 도구의 콘솔 탭에서 이 메시지를 확인할 수 있습니다.
};profile_script.js와my_profile.html파일을 저장합니다.- 웹 브라우저에서 여러분의 프로필 페이지를 확인합니다.
- 하단의 문의하기 버튼을 클릭해 보세요. 아직 문의 기능은 개발 중입니다...라는 경고창이 나타날 것입니다.
- 경고창이 나타나지 않으면
src의 파일 이름과profile_script.js의 저장 여부를 먼저 확인합니다.
이 예시는 자바스크립트가 사용자 입력에 반응해 화면을 바꾸는 기본 흐름을 보여줍니다.
정리 및 다음 단계 안내
이번 실습에서는 첫 웹 페이지를 만들며 다음 흐름을 확인했습니다.
- HTML: 웹 페이지의 뼈대와 내용을 구조화하는 방법
- CSS: 구조화된 내용에 시각적인 스타일을 적용하는 방법
- 자바스크립트: 사용자와 상호작용하는 동적인 기능을 추가하는 방법
- 개발 환경: VS Code와 Live Server를 활용하여 코드를 작성하고 실시간으로 확인하는 방법
지금 만든 페이지는 기초적인 수준이지만, HTML 구조, CSS 스타일, JavaScript 동작을 한 파일 흐름 안에서 확인했다는 점이 중요합니다.
다음 장부터는 이 세 요소를 더 세분화해 다룹니다.
자기소개 페이지를 스스로 한 번 바꿔 보기
예제 파일을 보관한 상태에서 취미 목록에 항목을 하나 추가하고, 헤더 배경을 자신이 고른 색으로 바꾸고, 문의 안내창의 문구를 바꿔 보세요. 수정 전에 세 변경을 각각 어느 파일에서 할지 적습니다. 저장·새로고침 뒤에는 목록 항목 수, 헤더 색, 버튼 클릭 시 안내 문구를 하나씩 확인하세요.
확인 기준과 연결 실패 구분
목록 항목은 my_profile.html의 ul 안 li, 헤더 배경은 profile_style.css의 header 규칙, 안내 문구는 profile_script.js의 클릭 함수 안 alert에서 바꿉니다. 취미만 추가되면 HTML은 반영되었지만 CSS·JS 저장이나 연결은 각각 더 확인해야 합니다. 문의 버튼은 Tab으로 이동해 Enter 또는 Space로도 눌러 보고 같은 안내창이 뜨는지 확인합니다. 이 예제는 안내창만 보여 주며 서버에 문의를 보내지는 않습니다.