← 목록으로

삽질 그만! 브라우저가 이미 품고 있는 놀라운 기능 9가지 (10년 차 실무자의 꿀팁 대방출)

2026. 4. 3.

삽질 그만! 브라우저가 이미 품고 있는 놀라운 기능 9가지 (10년 차 실무자의 꿀팁 대방출)

저는 코드와 일상, 그리고 그 모든 것들에 대한 철학적인 에세이를 쓰는 걸 좋아합니다. 깊이 있는 기술 탐구도 즐기죠. 하지만 여러분이 진짜 좋아하는 건, 아직 많은 이들에게 알려지지 않은 멋진 기능 리스트라는 걸 저도 잘 알고 있습니다. 😄

요즘 제 근황은요? 이번 주는 컨퍼런스 준비에 성능 이슈와 씨름하며, 다가오는 연휴를 그럭저럭 맞이할 준비를 하고 있습니다. 😉

얼마 전에는 기분 좋은 일도 있었습니다. 저는 기술 문서뿐만 아니라 글 쓰는 행위 자체를 즐기는데, 지난여름 제 삶에 꽤 큰 변화가 찾아왔고, 정신 건강을 유지하기 위해 SF 소설을 쓰기 시작했어요. 이걸 폴란드 SF 재단 공모전에 제출했는데, 비록 수상은 못 했지만 179개 작품 중 13위까지 오르는 기염을 토했습니다. 처음 시도한 글쓰기였음을 감안하면, 이 정도면 꽤 선방했다고 생각해요. 😄

그리고 SF(Science Fiction) 이야기가 나왔으니 말인데, 지금 우리 눈앞에서 벌어지고 있는 현실 속 SF에 대해서도 이야기해볼까요? 😉 오늘은 브라우저가 이미 할 수 있는 일들 중에서, 솔직히 저도 얼마 전까지는 전혀 몰랐던 기능들을 몇 가지 준비했습니다. 이들 중 상당수는 아직 널리 알려지지 않았지만, 이미 최신 브라우저 대부분에서 지원하고 있습니다. 재밌게 봐주세요!


1. "아, 이건 나중에 실행해야 하는데..." → requestIdleCallback

처음 이 API를 접했을 때, '이게 왜 필요하지?' 싶었습니다. 기본적으로 브라우저가 아무런 중요한 작업을 하지 않을 때 특정 코드를 실행하게 해주는 기능이거든요. '음... 좋긴 한데, 이게 나랑 무슨 상관이지?' 하는 생각이 들었죠.

하지만 알고 보니 활용 사례가 어마어마했습니다. 예를 들어, 사용자가 페이지에서 어떻게 행동하는지에 대한 데이터를 수집하는 작업. 수백 개의 컴포넌트가 렌더링되고 있을 때 이런 작업을 돌리면 절대 안 되겠죠? 😅 아니면 중요도가 낮은 데이터를 로딩하거나, 백그라운드에서 이미지 전처리를 하는 등 다양한 작업에 쓸 수 있습니다. 사실 개발자 수만큼이나 많은 활용 사례가 있다고 봐도 무방해요.

제가 실무에서 복잡한 대시보드를 만들 때, 초기 로딩 후 사용자 행동 데이터를 수집하는 데 이 API를 활용했더니 사용자 경험을 해치지 않으면서 중요한 인사이트를 얻을 수 있었습니다.

function trackUserScrolling() {
  console.log("User scrolled. This changes everything.");
}

if ("requestIdleCallback" in window) {
  requestIdleCallback(trackUserScrolling);
} else {
  setTimeout(trackUserScrolling, 0);
}

지원: 최신 브라우저 (과거 Safari에서 누락된 이력이 있어 폴백은 여전히 좋은 선택입니다)


2. "왜 인풋에 하이라이트가 안 되지???" → :focus-within

특정 요소에 포커스가 갔을 때 스타일을 적용하는 건 쉽습니다. 하지만 부모 div를 스타일링하고 싶다면 어떨까요? 예를 들어, 부모 영역을 핫핑크로 만들고, 꽃도 몇 개 추가하고 싶다고 가정해 봅시다. 이럴 때 자바스크립트 코드 40줄을 쓸 수도 있겠지만... 그냥 :focus-within을 사용하면 끝입니다.

정말 간단하죠. 이벤트 리스너도 필요 없고, 버그도 없고, 고통받을 일도 없습니다. 예전에 이런 걸 자바스크립트로 구현하겠다고 blur, focus 이벤트를 덕지덕지 붙이다가 버그를 잡느라 밤샘했던 기억이 나네요. 지금 생각하면 정말 비효율적이었죠.

.form-field {
  border: 1px solid #ccc;
  padding: 12px;
}

.form-field:focus-within {
  border-color: hotpink;
}
<div class="form-field">
  <input placeholder="Type something meaningful..." />
</div>

지원: 사실상 모든 주요 브라우저


3. "오프라인 모드를 보여줘야 해" → navigator.onLine

PWA(Progressive Web App)를 개발해본 적 있으신가요? 저는 PWA 프로젝트를 진행하면서 사용자가 인터넷 연결을 잃었을 때(예를 들어, 산속에 있거나 엘리베이터에 갇혔을 때 😄) 어떻게 처리할지가 늘 골칫거리였습니다. 복잡한 if 문을 덕지덕지 쓸 수도 있겠지만, 단순히 offlineonline 이벤트를 리스닝하는 방법이 있습니다. offline일 때는 IndexedDB에 데이터를 저장하고, 다시 online 상태가 되면 서버로 전송할 수 있죠. PWA 프로젝트를 진행하면서 오프라인 모드 처리가 가장 골치 아픈 부분 중 하나였는데, 이 API 덕분에 개발 시간을 꽤 단축시킬 수 있었습니다.

window.addEventListener("offline", () => {
  alert("You are offline. Time to panic.");
});

window.addEventListener("online", () => {
  alert("You're back. Panic cancelled.");
});

지원: 광범위하게 지원 (하지만 "온라인"이 곧 "백엔드가 잘 작동한다"는 의미는 아닙니다 😅)


4. "부드러운 애니메이션, 하지만 망쳐버려!" → requestAnimationFrame

우리 모두 이런 코드를 본 적 있을 겁니다.

setInterval(() => {
  element.style.left = Math.random() * 100 + "px";
}, 16);

딱 봐도 뭔가 좋지 않은 아이디어라는 느낌이 오지 않나요? 😉 그냥 렉이 걸립니다. 다행히 브라우저의 리페인트 주기와 동기화되는 requestAnimationFrame이 있어서, 훨씬 부드러운 애니메이션을 구현할 수 있습니다. 프레임 드롭 없이 부드러운 UI 애니메이션을 구현해야 할 때마다 requestAnimationFrame은 저의 든든한 동반자입니다. 특히 게임적인 요소가 들어가는 인터랙티브 웹을 만들 때 그 진가를 발휘하죠.

function animate() {
  element.style.transform = `translateX(${Date.now() % 300}px)`;
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

지원: 거의 모든 브라우저


5. "이 카드, 여기서만 반응형이어야 하는데..." → container queries

이 기능은 거의 '반칙'처럼 느껴집니다. 저는 경력상 CSS를 거의 쓰지 않는 지점까지 왔지만 (가끔 2026년에 CSS를 배우는 건 시간 낭비일까? 같은 글을 쓸 때 빼고는요).

하지만 한때 CSS를 정말 많이 쓰던 시절이 있었죠. 그때는 뷰포트 전체가 아닌 특정 요소에만 미디어 쿼리를 적용할 수 있었다면 얼마나 좋았을까, 하고 늘 생각했습니다. 이제 드디어 그게 가능해졌습니다! 컴포넌트가 스스로 '나는 이 너비에서는 이렇게 보여야 해'라고 인지하게 되는 거죠. 그럼 우리는 커피 한 잔 하러 가면 됩니다. 제가 처음 프런트엔드를 시작했을 때만 해도 이런 꿈같은 기능은 상상도 못 했어요. @media 쿼리로만 씨름하던 시절이 있었는데, 이제 컴포넌트 단위로 반응형을 제어할 수 있다니, CSS의 신세계가 열린 느낌입니다.

.card-wrapper {
  container-type: inline-size;
}

.card {
  display: grid;
}

@container (min-width: 400px) {
  .card {
    grid-template-columns: 1fr 2fr;
  }
}

지원: 최신 브라우저 (필요시 폴백 추가)


6. "랜덤 ID, 뭐가 문제겠어?" → crypto.getRandomValues

const id = Math.random().toString(36).slice(2);

이렇게 버그가 탄생합니다. 알리익스프레스에서 산 '그럭저럭 괜찮은' 암호화처럼 보이고, 작동은 하는 것 같지만... 어느 순간 삐걱거리기 시작하죠. 우선, 이 방식은 자바스크립트 엔진 구현에 의존하므로 내부적으로 어떤 일이 일어나는지 정확히 알 수 없습니다. 특정 패턴이 발생할 가능성이 충분하고, ID가 많아질수록 중복이 생길 확률은 기하급수적으로 늘어납니다.

다행히 이제는 간단하고 기본적으로 제공되는 해결책이 있습니다. 만능 해결책은 아니지만, crypto.getRandomValues는 꽤 견고합니다. 훨씬 더 좋은 엔트로피를 제공하고, 이상한 패턴이 없으며, 충돌 가능성을 극적으로 줄여줍니다. 브라우저가 알아서 제대로 처리해 주는 거죠. 보안이 중요한 서비스에서는 절대 Math.random으로 ID를 생성해서는 안 됩니다. 제가 과거에 이런 문제로 한 번 크게 데인 적이 있는데, 그 이후로는 무조건 이 API나 서버에서 안전한 ID를 받아옵니다.

const bytes = new Uint8Array(8);
crypto.getRandomValues(bytes);

const id = Array.from(bytes)
  .map(b => b.toString(16).padStart(2, "0"))
  .join("");

console.log("Secure-ish ID:", id);

지원: 광범위하게 지원


7. "모달이 필요해" → <dialog>

브라우저가 드디어 나서서 '자, 여기 너희가 원하던 모달이야!'라고 말해준 것이 솔직히 반가웠습니다. 😄 사용자들이 그렇게나 좋아하는 다이얼로그 하나 열겠다고 12KB짜리 라이브러리를 설치하던 시대는 이제 끝났습니다. 이 태그는 기본적으로 접근성도 보장되니, 그야말로 일석이조죠. 모달 하나 띄우겠다고 몇 KB짜리 라이브러리를 설치하던 시절이 있었죠. 이제는 <dialog> 태그 하나로 접근성까지 보장되는 모달을 만들 수 있으니, 정말 개발자들의 삶이 윤택해졌다고 봅니다.

<dialog id="modal">
  <p>Are you sure you want to deploy on Friday?</p>
  <button onclick="modal.close()">Cancel</button>
  <button onclick="alert('Good luck 😬')">Deploy</button>
</dialog>

<button onclick="modal.showModal()">Open modal</button>

지원: 최신 브라우저


8. "음성 입력이 되면 멋질 텐데..." → Speech API

음성 인식이 필요하다고 벌써 transformers.js를 설치하고 계신가요? 잠깐 진정하세요. 브라우저에도 이 기능이 있습니다. 물론... Chromium 기반 브라우저에서만요. 😄 그러니 사용자들에게 Chrome, Edge 또는 비슷한 브라우저를 사용하도록 "권장"할 수 있다면 괜찮습니다. 개인적으로는 아직 프로덕션 환경에서의 사용은 신중하게 고려하겠지만, 데모용으로는 왜 안 되겠습니까? 물론 아직 완벽하진 않지만, 간단한 음성 인터랙션 데모를 만들 때 이 API를 활용하면 '와, 브라우저가 이런 것도 해줘?' 하는 반응을 자주 받습니다.

const SpeechRecognition =
  window.SpeechRecognition || window.webkitSpeechRecognition;

if (SpeechRecognition) {
  const recognition = new SpeechRecognition();

  recognition.onresult = e => {
    console.log("You said:", e.results[0][0].transcript);
  };

  recognition.start();
}

지원: 주로 Chromium 기반 브라우저


9. "이 CSS, 터질까 안 터질까?" → @supports

여기에 고전적인 "제 컴퓨터에서는 잘 되는데요?" 문제에 대한 현대적인 해결책이 있습니다. 최소한 CSS에서는요. 😉 특정 CSS 속성이 레이아웃을 망가뜨릴지 추측할 필요가 없습니다. 그냥 @supports 안에 감싸면 됩니다. 작은 함정이 하나 있는데, 지원이 매우 좋긴 하지만 '모든' 곳에서 지원되는 건 아니므로, 아이러니하게도 @supports 자체에 @supports를 쓸 수도 있습니다. 새로운 CSS 기능을 도입할 때 하위 호환성 때문에 늘 망설였는데, @supports 덕분에 안심하고 실험적인 스타일을 적용해볼 수 있게 됐어요. 마치 CSS에 try-catch 문이 생긴 것 같달까요?

.card {
  background: white;
}

@supports (backdrop-filter: blur(10px)) {
  .card {
    backdrop-filter: blur(10px);
    background: rgba(255, 255, 255, 0.6);
  }
}

지원: 매우 좋음


⚠️ 하지만 오해는 마세요

라이브러리는 정말 훌륭합니다. 때로는 라이브러리가 절실하게 필요할 때도 분명히 있죠. 하지만 가끔은... 브라우저가 이미 몇 년 전에 해결해 둔 문제를 위해 의존성을 설치하고 있는 자신을 발견하게 될 겁니다. 어떤 것을 설치하기 전에, 자신에게 (또는 구글에게) 이렇게 물어보세요. "여기서 브라우저가 나보다 더 똑똑할까?" 때로는 그 대답이 "네"일 때가 있습니다. 그리고 그건... 전혀 문제 될 게 없죠.

결국 중요한 건 특정 기술에 맹목적으로 의존하는 것이 아니라, 문제를 해결하기 위한 가장 효율적이고 견고한 방법을 찾는 것입니다. 때로는 브라우저 자체가 최고의 라이브러리일 때도 있다는 사실을 잊지 마세요. 이런 숨겨진 보석 같은 기능들을 잘 활용하면 개발 속도는 물론, 서비스의 안정성과 사용자 경험까지 한 단계 끌어올릴 수 있을 겁니다.


원문: https://dev.to/sylwia-lask/9-things-youre-overengineering-the-browser-already-solved-them-o99 수집일: 2026-04-03 05:51:21