HTML/CSS/JS 스터디 세션 후기

Moonjeong Kim·2026년 9월 30일

코디세이

목록 보기
2/3
post-thumbnail

HTML/CSS/JS 스터디 세션 후기 — DOM · 이벤트 루프 · 전역 상태

준비한 슬라이드보다 질문이 훨씬 깊게 들어간 동료 학습 세션이었고, 설명하면서 저도 다시 배웠습니다.

세션 개요

코디세이 과정을 들으면서 주변에서 세션을 열어달라는 요청이 있었고, B1-1 미션(나를 소개하는 웹페이지)을 예시로 세션을 열었습니다. 대상은 완전 처음 접하시는 분들이라 가볍게 진행할 생각이었는데, 준비한 슬라이드는 생각보다 빨리 끝났고 나머지 시간은 질문으로 채워졌습니다.

처음에는 다들 조용히 들으셔서 잘 전달되고 있는지 확신이 없었습니다. 시간이 지나며 질문이 하나둘 나오기 시작했고, 예상보다 훨씬 깊은 질문도 있었습니다. 제 설명이 부족한 부분은 다른 참가자분이 직접 채워주셨고, 서로 부족한 것을 보완하며 배우는 동료 학습 세션다운 시간이었습니다.

기억나는 질문만 정리했습니다. 전부 기억하지는 못해서 빠진 것이 있을 수 있습니다.

세션 자료

질문 1. "DOM은 결국 눈에 안 보이는 거 아닌가요?"

개발자 도구의 Elements 탭이 곧 DOM이고, 거기서 직접 고쳐볼 수 있습니다.

  • 저는 "HTML은 설계도, DOM은 그 설계도로 지어진 집"이라는 비유로 설명했지만, 이 질문에는 명쾌하게 답하지 못했습니다.
  • 다른 참가자분이 브라우저 개발자 도구의 Elements 탭을 직접 보여주며 채워주셨습니다. 아무 페이지에서 우클릭 → 검사 → Elements 탭을 열면 그것이 DOM입니다.
  • 텍스트를 더블클릭해서 바꾸면 화면이 바로 바뀝니다. 이것은 HTML 파일을 고친 것이 아니라 DOM을 직접 고친 것입니다.
  • 새로고침하면 원래대로 돌아갑니다. 브라우저가 HTML 파일을 다시 읽어서 DOM을 처음부터 다시 만들기 때문입니다.

질문 2. "state 객체는 결국 전역변수 아닌가요?"

맞습니다. 다만 흩어진 전역이 아니라 하나의 이름 아래 정리된 전역입니다.

:root {
  --primary: blue;
  --danger: red;
}
const state = {
  theme: "light",
  allRepos: [],
};
  • CSS :root와 JS state는 "값을 한 곳에 모아두고 필요한 곳마다 참조한다"는 같은 생각을 다른 언어로 표현한 것입니다.
  • 진짜 전역변수(let a, let b처럼 흩어놓은 것)는 아무 데서나 예측 없이 바뀔 수 있어서 안티패턴으로 취급됩니다.
  • state는 전역변수를 쓰되 흩어지지 않게 객체로 묶은 절충안에 가깝습니다.

질문 3. "import 한 번으로 어디서든 쓸 수 있나요?"

CSS는 한 번이면 되고, JS는 쓰는 파일마다 가져와야 합니다.

Next.js의 global.css를 보여주며 설명하다가 나온 질문입니다.

  • CSS: global.css를 앱 최상위(layout.tsx)에서 한 번만 import하면 :root의 변수가 DOM 전체로 자동으로 cascade됩니다. 어느 컴포넌트에서든 import 없이 var(--primary)를 쓸 수 있습니다.
  • JS: state는 모듈 스코프 변수라서, 다른 파일에서 쓰려면 그 파일마다 export/import 짝으로 가져오거나 props나 Context로 넘겨야 합니다.
  • 정리하면 "CSS는 한 번 로드되면 끝, JS는 쓸 때마다 데려와야 한다"입니다.

질문 4. "동시에 요청이 여러 개 들어오면 인터럽트처럼 끼어드는 건가요?"

아닙니다. JS는 인터럽트가 아니라 이벤트 루프 방식이고, await에서 함수가 스스로 양보합니다.

가장 깊게 들어간 질문이었습니다.

async function a() {
  console.log("A 시작");
  await fetch(url1); // 여기서 A가 잠깐 빠짐 (끝난 게 아니라 멈춘 것)
  console.log("A 끝");
}
async function b() {
  console.log("B 시작");
  await fetch(url2);
  console.log("B 끝");
}
a();
b();
// 실제 출력 순서: "A 시작" → "B 시작" → (fetch가 끝나는 순서대로) "A 끝" 또는 "B 끝"
  • 인터럽트는 실행 중인 코드를 강제로 멈추고 끼어드는 방식인데, await는 함수가 스스로 제어권을 넘기는 것입니다.
  • a()가 완전히 끝나지 않았어도 b()가 바로 시작됩니다.
  • "하나가 다 처리돼야 다음이 처리된다"는 오해가 흔하지만, 정확히는 여러 개가 동시에 "대기 중"일 수 있고, 준비된 것부터 순서대로 처리됩니다.
  • 카페로 비유하면, 손님 A가 주문하고 진동벨을 받은 뒤 커피가 아직 안 나왔어도 손님 B가 이어서 주문하고 진동벨을 받을 수 있는 것과 같습니다.

질문 5. "미디어쿼리 브레이크포인트는 보통 몇 px로 나누나요?"

공식 표준은 없고, 내 콘텐츠를 줄여보다가 레이아웃이 어색해지는 지점이 기준입니다.

  • 이것을 content-based breakpoint라고 부르고, 디바이스 기준(태블릿 = 768px)이 아니라 내 디자인이 실제로 깨지는 지점을 보고 정하는 것이 정석입니다.
  • 그래도 업계에서 관행처럼 겹치는 값은 있습니다. (두 프레임워크의 기본값 기준)
    • Bootstrap: 576 / 768 / 992 / 1200 / 1400px
    • Tailwind: 640 / 768 / 1024 / 1280 / 1536px
  • 세세하게 쪼갤수록 화면은 예뻐지지만, 그만큼 CSS와 테스트 부담도 늘어나는 트레이드오프가 있습니다.

질문 6. "반응형과 middleware 기반 모바일 라우팅은 뭐가 다른가요?"

반응형은 "같은 걸 다르게 보여주기", 미들웨어 라우팅은 "아예 다른 걸 보내주기"입니다.

코디로그(개인 프로젝트)와 성분핏 코드를 보여주다가 이어진 질문입니다. Next.js의 middleware.ts에서 user-agent를 판별해 /m 같은 prefix로 리다이렉트하는 방식도 함께 보여드렸습니다.

  • 반응형(CSS 미디어쿼리): 같은 HTML/JS를 그대로 보내고 CSS만 다르게 적용합니다.
  • 미들웨어 라우팅: 서버 단계에서 아예 다른 페이지·컴포넌트를 결정해서 보냅니다.
  • prefix(/m, /mobile 등)는 표준이 없고 프로젝트마다 정하기 나름입니다.

세션에서 배운 것

  • 제가 설명하며 다시 배운 점: 이벤트 루프를 "양보"라는 말로 풀어 설명하면서, 제가 알던 개념을 어느 수준까지 설명할 수 있는지 확인할 수 있었습니다.
  • 다른 참가자분께 배운 점: DOM을 눈으로 직접 확인하는 방법(Elements 탭에서 직접 수정)을 그 자리에서 배웠습니다.

정리

  • DOM은 Elements 탭에서 직접 보고 고칠 수 있고, 새로고침하면 HTML 기준으로 다시 만들어집니다.
  • state는 묶인 전역이고, CSS는 한 번 import하면 전체에 적용되지만 JS는 쓰는 파일마다 가져와야 합니다.
  • await는 인터럽트가 아니라 스스로 양보하는 것이고, 브레이크포인트는 표준 값이 아니라 내 콘텐츠가 깨지는 지점으로 정합니다.

마무리

부족한 부분이 많았을 텐데도 끝까지 함께해주시고, 제가 놓친 부분까지 채워주신 모든 분들께 감사드립니다. 다음 세션에서는 이번에 나온 질문들을 바탕으로 비동기와 상태 관리를 조금 더 깊게 다뤄보고 싶습니다.

profile
만들면서 배우는 AI 풀스택 개발 기록

0개의 댓글