Frontend 06
CSS 기초: 역할, 문법, 선택자, 연결 방식 완벽 이해하기
CSS 파일을 만들었는데 어떤 HTML 요소에 왜 적용되는지, 선택자와 연결 방식이 한꺼번에 섞여 보인다.
근거 · 교안 p19-p23
1장: CSS, HTML에 스타일을 입히는 ‘언어’의 기본 구조
솔라의 손가락이 노트북 트랙패드 위에서 멈췄다. 화면에는 방금 막 완성한 짧은 HTML 문서가 떠 있었다. 제목, 몇 개의 문단, 목록까지 구조는 그럴듯했지만, 내용은 온통 검은색 텍스트뿐이었다. 밋밋한 흰 배경 위에 자리 잡은 글자들은 마치 아직 잠에서 깨지 않은 것처럼 보였다.
“분명 ‘CSS는 HTML에 시각적 표현을 입히는 언어’라고 했는데…”
솔라는 혼잣말로 중얼거렸다. 며칠 전 수업에서 들었던 문장이었다. 머릿속에서는 그럴싸하게 들렸지만, 막상 자신의 화면을 보니 막막했다. 그 문장은 ‘소금은 음식의 간을 맞춘다’는 말처럼 들렸다. 맞는 말이지만, 소금이 하얀 가루인지, 네모난 덩어리인지, 어떻게 음식에 넣어야 하는지 알려주지 않는 것과 같았다.
그때 방으로 들어오던 언니 루나가 솔라의 노트북 화면을 흘긋 보았다.
“거의 다 됐네. 이제 꾸밀 차례인가?”
“언니, 바로 그거야. ‘꾸민다’는 게 대체 뭐야? 이 제목(<h1>) 글자색을 빨간색으로 바꾸고 싶은데, 방법을 모르겠어. CSS가 스타일을 입히는 거라는데, HTML 파일이랑 CSS는 대체 어떻게 말을 주고받는 거지? 그냥 ‘이거 빨갛게 해줘!’ 하고 소리칠 수도 없고.”
솔라의 목소리에는 짜증이 섞여 있었다. 아는 단어들이 눈앞의 문제를 해결하는 데 아무런 도움이 되지 않는다는 사실이 답답했다.
루나는 의자를 끌어와 솔라의 옆에 앉았다. 화면 속 HTML 코드를 잠시 들여다보더니, <h1> 태그가 있는 줄을 손가락으로 가리켰다.
<h1>나의 첫 번째 블로그</h1>
“전체 구조를 한 번에 바꾸려고 하면 복잡하게 느껴져. 딱 하나, 이 제목부터 바꿔보자. HTML은 각자 이름표를 가진 배우들이라고 생각해 봐. 우리는 지금 ‘h1’이라는 배우에게만 특별한 지시를 내릴 거야.”
루나는 솔라에게 <h1> 태그 안쪽에 코드를 직접 입력해보라고 했다.
“<h1” 바로 뒤에 한 칸 띄고 style="color: red;" 라고 써봐.”
솔라는 미심쩍은 표정으로 키보드를 두드렸다. 태그 안에 무언가 쓰는 방식은 낯설었다.
<h1 style="color: red;">나의 첫 번째 블로그</h1>
솔라는 파일을 저장하고 브라우저를 새로고침했다. 화면의 제목이 선명한 빨간색으로 바뀌었다.
“오! 되네?”
짧은 감탄과 함께 새로운 의문이 떠올랐다. “근데 이건 그냥 언니가 시키는 대로 따라 친 거잖아. 주문을 외운 것 같아. 왜 이렇게 되는 건데?”
루나는 기다렸다는 듯, 책상 위 메모지를 가져와 펜으로 무언가를 적었다.
color: red;
“마법 주문의 핵심은 이 부분이야. style="" 안에 들어간 내용 말이야. 이게 바로 CSS라는 ‘언어’의 가장 작은 문장 단위야.”
루나는 펜 끝으로 color를 콕 찍었다.
“이건 **속성(property)**이라고 불러. ‘무엇을’ 바꾸고 싶은지에 대한 거지. 글자 색, 글자 크기, 배경색 같은 것들이 여기 해당돼.”
이어서 루나의 펜이 콜론(:)을 지나 red로 옮겨갔다.
“그리고 이건 값(value). 속성을 ‘어떻게’ 바꿀지에 대한 대답이야. ‘빨간색’으로, ‘16픽셀’ 크기로, 같은 구체적인 지시지.”
마지막으로 루나는 문장 끝의 세미콜론(;)에 동그라미를 쳤다.
“세미콜론은 문장의 마침표 같은 거야. ‘여기까지가 하나의 지시다’라고 알려주는 거지.”
솔라는 루나가 적은 메모와 자신의 HTML 코드 속 style="color: red;"를 번갈아 보았다. 따로따로 흩어져 있던 기호들이 하나의 문법으로 보이기 시작했다. ‘그냥 꾸민다’는 막연한 생각에서 벗어나, ‘어떤 속성을 어떤 값으로 바꾼다’는 명확한 명령의 구조가 눈에 들어왔다.
“아… 그러니까 그냥 ‘빨갛게 해’가 아니라, ‘color라는 속성의 값을 red로 지정한다’는 완전한 문장이었구나. 정말 언어네.”
솔라는 고개를 끄덕였다. 이제야 ‘CSS는 HTML 구조에 시각적 표현을 입히는 언어다’라는 문장이 다르게 읽혔다. 그것은 추상적인 비유가 아니라, 지금 눈앞에 있는 속성: 값; 이라는 구체적인 문법을 가리키는 말이었다.
생각이 정리되자, 곧바로 다음 질문이 튀어나왔다. 풀리지 않은 매듭의 다른 쪽 끝이 모습을 드러낸 것이다.
“알겠어. color: red;가 지시 내용인 건 이해했어. 그런데 이번에는 우리가 h1 태그 바로 안쪽에 이 지시를 써넣었으니까 브라우저가 알아들은 거잖아. 만약 CSS 코드를 완전히 다른 파일에 잔뜩 써놓는다면, 컴퓨터가 어떻게 이 많은 지시들이 수많은 HTML 태그 중에 정확히 누구를 위한 건지 알 수 있는 거지? 멀리서 배우의 이름표를 불러줘야 할 텐데.”
2장: HTML 요소를 ‘선택’하는 CSS 선택자의 규칙
솔라가 잠시 자리를 비운 사이, 루나는 노트북 화면을 조용히 바꾸어 놓았다. 솔라가 돌아왔을 때, 그녀를 맞이한 것은 이전과 미묘하게 달라진 코드였다. 분명 빨간색이었던 <h1> 제목은 다시 검은색으로 돌아와 있었다.
“어? 다시 원래대로 돌아왔네?”
하지만 코드 편집기를 보자 고개가 갸우뚱해졌다. <h1> 태그 안은 깨끗했다. 지난번에 직접 입력했던 style="color: red;" 구문이 감쪽같이 사라져 있었다. 대신, 문서의 상단, <head> 태그 안쪽에 처음 보는 코드 블록이 생겨나 있었다.
<head>
<style>
h1 {
color: blue;
}
</style>
</head>
솔라는 눈을 가늘게 뜨고 코드를 뜯어보았다. color는 이제 blue가 되어 있었고, 그 익숙한 속성: 값 쌍이 중괄호 {} 안에 감싸여 있었다. 그리고 그 앞에는 h1이라는, 너무나 익숙한 태그 이름이 덩그러니 놓여 있었다.
“언니, 이게 뭐야? style 속성은 어디 가고… 어?”
솔라는 말을 잇다 말고 무언가 깨달은 듯 화면을 다시 봤다. 그리고 파일을 저장하고 브라우저를 새로고침했다. 제목 나의 첫 번째 블로그가 파란색으로 바뀌었다.
“아! 잠깐만. 내가 아까 말했던 거랑 비슷해. ‘멀리서 배우의 이름표를 불러줘야 할 텐데’라고 했던 거. 그럼 저 h1 이게 바로 그 ‘이름표’ 역할을 하는 거야?”
“맞아.” 루나가 짧게 답했다. “우리가 <h1> 태그 안에서 직접 속삭이는 대신, 이제 무대 밖 감독석에서 ‘h1 배우 나와서, 조명 파랗게 받아!’ 하고 외친 거야. CSS에서는 저 이름표를 **선택자(selector)**라고 불러.”
솔라는 h1 { color: blue; }라는 구문을 손가락으로 짚었다. 이제야 속성: 값이라는 지시 내용과, 그 지시가 누구를 향한 것인지를 알려주는 ‘선택자’가 하나의 완전한 문장 구조를 이룬다는 사실이 보였다.
“그럼 선택자는 항상 저렇게 태그 이름을 쓰는 거야? 만약에 페이지에 <p> 태그가 여러 개 있으면 어떡해? 그중 몇 개만 다르게 꾸미고 싶을 수도 있잖아. ‘거기 배우들!’ 하고 부르면 다 같이 쳐다볼 텐데.”
“좋은 질문이야. 바로 그걸 실험해보자.”
루나는 솔라의 HTML 문서에 문단 몇 개와 목록을 추가하도록 했다. 화면은 금세 좀 더 현실적인 블로그 글의 모습이 되었다.
<h1>나의 첫 번째 블로그</h1>
<p>첫 번째 문단입니다. 블로그에 오신 것을 환영합니다.</p>
<p>두 번째 문단입니다. CSS는 정말 재미있어요!</p>
<ul>
<li>항목 1</li>
<li>항목 2: 이 항목은 중요해요.</li>
</ul>
“자, 이제 감독이 되어 지시를 내려봐. 모든 문단(p 태그)을 기울임꼴로 만들어볼까?”
솔라는 <style> 태그 안에 새로운 규칙을 추가했다. h1 규칙 바로 아래였다.
p {
font-style: italic;
}
새로고침하자, 두 개의 문단이 모두 기울어졌다. 솔라의 예상대로였다. 이것이 ‘태그 선택자’였다. 특정 종류의 배역을 맡은 배우를 모두 부르는 것과 같았다.
“좋아. 그럼 이제 두 번째 문단만 배경색을 노란색으로 칠해서 강조하고 싶어. 어떻게 ‘두 번째 p’만 콕 집어 부를 수 있을까?”
루나는 p 태그 중 두 번째 것에 class="highlight"라는 속성을 추가해보라고 했다. ‘highlight’라는 별명을 붙여주는 것과 같았다.
<p>첫 번째 문단입니다. 블로그에 오신 것을 환영합니다.</p>
<p class="highlight">두 번째 문단입니다. CSS는 정말 재미있어요!</p>
“이제 그냥 p라고 부르면 안 되겠지. 별명을 가진 배우를 불러야 하니까.”
루나는 <style> 태그 안에 새로운 규칙을 쓸 때, highlight 이름 앞에 마침표(.)를 찍어보라고 힌트를 주었다.
.highlight {
background-color: yellow;
}
솔라가 코드를 입력하고 브라우저를 확인했다. 정확히 두 번째 문단에만 노란색 배경이 칠해졌다.
“와! 마침표가 별명을 부르는 기호구나! 그럼 여러 명한테 같은 별명을 붙여줄 수도 있어?”
솔라는 곧장 첫 번째 문단에도 class="highlight"를 추가했다. 그러자 첫 번째 문단에도 즉시 노란 배경이 적용되었다.
“알겠다! 클래스(class) 선택자는 같은 역할을 하는 배우들을 ‘A팀’, ‘B팀’으로 묶어서 한 번에 부르는 거네.”
마지막으로 루나가 h1 태그를 가리켰다. “페이지에서 제목은 보통 딱 하나만 있잖아. 이렇게 문서 전체에서 유일무이한 배우에게는 아주 특별한 이름표를 줄 수 있어. 주민등록번호처럼 말이야.”
루나는 h1 태그에 id="main-title" 속성을 추가하라고 했다. 그리고 CSS 규칙을 작성할 때는 이름 앞에 샵(#) 기호를 붙이라고 알려주었다.
<h1 id="main-title">나의 첫 번째 블로그</h1>
#main-title {
border-bottom: 2px solid black;
}
솔라가 코드를 완성하자, 파란색이었던 제목 아래에 검은색 밑줄이 그어졌다.
솔라는 잠시 키보드에서 손을 떼고 자신이 작성한 <style> 블록을 찬찬히 훑어보았다. 이전에는 그저 뒤죽박죽으로 보였던 선택자들이 이제는 명확한 규칙을 가진 도구로 보였다.
p: ‘p’라는 배역을 맡은 모두에게. (태그 선택자).highlight: ‘highlight’라는 팀 소속인 모두에게. (클래스 선택자)#main-title: ‘main-title’이라는 고유 번호를 가진 단 한 명에게. (ID 선택자)
“이제야 알겠어. ‘선택자’라는 게 그냥 이름표가 아니라, 대상을 얼마나 넓게 또는 좁게 지정할지 정하는 ‘호출 방식’ 그 자체였구나.”
솔라는 고개를 끄덕였다. 선택자 { 속성: 값; } 이라는 문법이 비로소 완전한 의미로 다가왔다. ‘[누구]에게 [무엇]을 [어떻게] 하라’는 완벽한 명령문이었다.
그런데 모든 규칙이 담겨있는 <style> 태그를 보던 솔라의 눈에 새로운 질문이 떠올랐다.
“언니, 지금은 HTML 파일 안에 이 규칙들을 전부 썼잖아. 그런데 실무에서는 CSS 파일을 아예 따로 만든다고 들었어. 지금처럼 <style> 태그를 쓰는 거랑, 그 파일을 따로 만드는 건 뭐가 다른 거지? 굳이 왜 파일을 분리해서 연결하는 거야?“
3장: CSS 코드를 HTML에 ‘결합’하는 최적의 방법
솔라의 질문이 끝나기 무섭게, 루나는 조용히 키보드를 가져갔다. 솔라가 막 완성한 코드, <head> 태그 안에 자리 잡았던 <style> 블록 전체를 드래그해 선택했다. 파랗게 반전된 코드가 화면 위에서 빛났다.
루나는 망설임 없이 Ctrl+X 키를 눌렀다. 방금 전까지 여러 줄을 차지하던 CSS 규칙들이 순식간에 사라졌다. 솔라가 브라우저를 새로고침하자, 마법이 풀린 것처럼 모든 것이 원래대로 돌아왔다. 파란색이었던 제목은 검게, 기울어졌던 문단은 똑바로, 노란색 배경은 흰색으로. 애써 꾸며놓았던 배우들이 모두 무대 의상을 벗고 평상복으로 돌아온 듯했다.
루나는 텅 빈 새 파일을 열고 style.css라는 이름을 붙였다. 그리고 방금 잘라냈던 코드 덩어리를 그대로 붙여넣었다. 이제 솔라의 노트북 화면에는 두 개의 파일이 나란히 열려 있었다. 하나는 배우들의 대본과 동선만 남은 index.html, 다른 하나는 잘 짜인 조명과 의상 지시서가 담긴 style.css. 하지만 둘 사이에는 아무런 연결 고리가 없었다.
“언니, 지금 뭐 하는 거야? 스타일 다 사라졌잖아!”
당황한 솔라의 목소리에 루나는 대답 대신, 텅 비어버린 index.html의 <head> 안쪽을 가리켰다.
“네 질문에 대한 답을 찾는 중이야. ‘왜 굳이 파일을 분리해서 연결하는지’ 알려면, 일단 완벽하게 분리된 상태에서 시작해야지.”
루나는 메모지에 한 줄의 코드를 적어 솔라에게 건넸다.
<link rel="stylesheet" href="style.css">
“이 한 줄을 아까 그 <style> 태그가 있던 자리에 넣어봐. 이건 HTML 문서에게 ‘우리의 스타일리스트는 저기 있는 style.css 파일이야’라고 알려주는 소개장 같은 거야.”
솔라는 반신반의하며 코드를 입력했다. 파일을 저장하고 브라우저를 새로고침하는 순간, 사라졌던 모든 스타일이 거짓말처럼 제자리로 돌아왔다. 파란 제목, 기울어진 문단, 노란 배경까지.
“와…! 돌아왔다. 그런데… 결국 똑같네. 아까처럼 HTML 파일 안에 규칙을 쓸 때랑, 지금처럼 다른 파일에 써서 연결할 때랑, 결과는 완전히 똑같잖아. 그냥 방법만 다른 거 아니야? 취향 차이인가?”
솔라의 눈에는 여전히 세 가지 방식—태그 안에 직접 쓰는 것, <style> 태그에 모아 쓰는 것, 외부 파일로 연결하는 것—이 다 비슷해 보였다.
“결과가 같다고 과정까지 같은 건 아니지.”
루나는 새로운 시나리오를 제시했다.
“만약 우리 블로그에 ‘소개’, ‘글 목록’ 페이지가 더 생긴다면 어떨까? 두 페이지도 지금 이 페이지처럼 똑같은 스타일을 적용하고 싶어. 제목은 파랗게, 중요한 문단은 노랗게.”
루나는 about.html과 posts.html이라는 이름의 파일 두 개를 더 만들었다. 내용은 달랐지만, 구조는 비슷했다.
“자, 첫 번째 방법부터 생각해 보자. 우리가 맨 처음 했던 것처럼 모든 스타일을 태그 안에 style="..."로 직접 써넣는다면? about.html에 있는 제목에도 style="color: blue;"를, posts.html에 있는 제목에도 똑같이 써줘야겠지. 만약 나중에 제목 색을 보라색으로 바꾸고 싶으면? 세 개의 파일을 전부 열어서 모든 제목 태그를 일일이 찾아 고쳐야 해.”
솔라는 상상만 해도 질린다는 표정을 지었다. 수십, 수백 개의 파일이 있다면 그건 재앙일 터였다.
“그럼 두 번째 방법. <style> 태그를 쓰는 건? 그것도 마찬가지네. 세 개의 HTML 파일마다 <head> 안에 똑같은 CSS 규칙들을 전부 복사해서 붙여넣어야 하잖아. 수정할 때도 세 번 일해야 하고.”
“맞아. 그럼 마지막 방법은?” 루나가 style.css 파일을 가리켰다.
솔라의 눈이 커졌다. “아…! about.html과 posts.html에도 아까 그 <link> 태그 한 줄만 추가하면… 끝나는 거네?”
솔라는 재빨리 두 개의 새 파일에 <link rel="stylesheet" href="style.css"> 한 줄을 추가했다. 브라우저에서 두 페이지를 열자, index.html과 완벽하게 동일한 스타일이 적용되어 있었다.
“이제 style.css 파일에서 제목 색을 보라색으로 바꿔봐.”
솔라는 style.css 파일의 h1 규칙에서 color 값을 purple로 바꿨다. 그러고 나서 index.html, about.html, posts.html을 차례로 새로고침했다. 세 페이지의 제목이 모두 동시에 보라색으로 바뀌었다.
“이거구나…!”
솔라는 무릎을 탁 쳤다. “HTML은 내용과 뼈대, CSS는 디자인. 이 둘의 작업실을 아예 다른 건물에 만들어 버린 거네. 디자인을 바꿀 때 내용물을 전혀 건드릴 필요가 없어. 스타일리스트 한 명이 모든 페이지를 관리하니까, 수정은 딱 한 번만 하면 되고!”
지금까지 ‘실무에서는 외부 파일을 연결한다’는 말을 그저 따라야 할 규칙으로만 생각했던 솔라의 머릿속에, 그 이유가 명확한 그림으로 그려졌다. 그것은 취향의 문제가 아니라, 수많은 페이지를 효율적으로 관리하고 유지보수하기 위한 가장 실용적인 ‘전략’이었다.
“그럼 인라인 스타일이나 <style> 태그는 아예 안 쓰는 게 좋아?”
“아니, 각자의 역할이 있지. 인라인 스타일은 정말 딱 그 요소 하나만, 다른 무엇과도 상관없이 급하게 테스트할 때 유용해. <style> 태그는 이 페이지에만 적용되는 아주 특별한 규칙이 필요할 때 쓸 수 있고. 하지만 웹사이트 전체의 일관성을 유지하고 관리하려면, 외부 파일을 연결하는 게 거의 항상 정답이야.”
루나는 솔라가 작업하던 파일들을 모두 닫았다. 그리고 project.html이라는 이름의 새로운 파일을 화면에 띄웠다. 안에는 아무런 스타일도 적용되지 않은, 뼈대만 있는 구조가 들어 있었다.
<!DOCTYPE html>
<html>
<head>
<title>새 프로젝트</title>
</head>
<body>
<h1 id="project-title">나의 새 프로젝트</h1>
<p class="intro">이 프로젝트는 CSS 원리를 적용하여 완성됩니다.</p>
<p>구조와 디자인을 분리하여 관리합니다.</p>
</body>
</html>
루나는 책상 위 포스트잇에 간단한 지시사항을 적어 건넸다.
- 제목(#project-title): 글자색
#333, 아래쪽에 2px 실선 테두리- 소개 문단(.intro): 배경색
#f0f0f0, 안쪽 여백 10px
“자, 이제 네가 스타일리스트야. 이 문서에 가장 좋은 방식으로 스타일을 적용해 봐.”
솔라는 잠시 포스트잇과 화면을 번갈아 보더니, 망설임 없이 키보드로 손을 옮겼다. 그녀는 project.html 파일 자체를 건드리지 않았다. 대신, project-style.css라는 새 파일을 만들었다.
새로운 CSS 파일에, 솔라는 포스트잇에 적힌 지시사항을 정확한 선택자와 속성으로 옮겨 적었다.
#project-title {
color: #333;
border-bottom: 2px solid black;
}
.intro {
background-color: #f0f0f0;
padding: 10px;
}
마지막으로, 그녀는 project.html 파일의 <head> 태그 안으로 돌아가, 단 한 줄의 코드를 추가했다.
<link rel="stylesheet" href="project-style.css">
두 파일을 저장하고 브라우저를 새로고침하자, 밋밋했던 문서가 깔끔하게 정리된 모습으로 바뀌었다. 솔라는 화면에 나란히 떠 있는 두 개의 파일을 보았다. 내용과 구조를 담은 HTML, 그리고 그 모습을 결정하는 CSS. 둘은 이제 각자의 자리에서 서로를 연결하며 완벽하게 작동하고 있었다.
“이제 알겠어. CSS는 단순히 HTML을 꾸미는 게 아니었어. 페이지 전체의 스타일을 효율적으로 ‘관리’하는 언어였구나.”
솔라의 혼잣말에 루나가 조용히 미소 지었다. 솔라의 손끝에서, 어지럽게 흩어져 있던 개념들이 비로소 제자리를 찾고 있었다.