쓸데없는 삽질 그만! 브라우저가 이미 다 해주는 9가지 기막힌 기능들
2026. 4. 4.
쓸데없는 삽질 그만! 브라우저가 이미 다 해주는 9가지 기막힌 기능들
안녕하세요, 10년 차 IT 실무자이자 테크 블로거, 여러분의 호기심을 자극할 준비가 된 제가 돌아왔습니다! 저는 평소 코드와 일상에 대한 철학적인 글쓰기를 즐기고, 깊이 있는 기술 탐구도 무척 좋아합니다. 하지만 여러분이 제가 정리한 '아직 잘 알려지지 않은 멋진 기능 목록'을 훨씬 더 좋아한다는 걸 잘 알죠. 😄
이번 주는 컨퍼런스 준비에 성능 문제 씨름, 그리고 다가오는 명절(홀리데이) 준비까지 정신없는 한 주를 보냈네요. 😉 그 와중에 기분 좋은 일도 있었습니다. 저는 기술 문서뿐 아니라 일반적인 글쓰기 자체를 즐겨요. 지난여름 제 삶에 꽤 큰 변화가 있었는데, 제 정신 건강을 지키기 위해 SF 소설을 쓰기 시작했죠. 폴란드 SF 재단 공모전에 제출했는데, 아쉽게도 수상은 못 했지만 179개 출품작 중 13위까지 진출했습니다. 이런 종류의 글쓰기 첫 시도였음을 감안하면... 훨씬 더 나쁠 수도 있었죠! 😄
SF 이야기가 나온 김에, 바로 우리 눈앞에서 펼쳐지는 '현실 SF'에 대해 이야기해 볼까요? 😉 오늘은 브라우저가 이미 해낼 수 있지만, 얼마 전까지만 해도 제 머리로는 상상하기 힘들었던 기능들을 잔뜩 준비해 봤습니다. 이 중 많은 기능이 아직 널리 알려지지 않았음에도 불구하고, 대부분의 최신 브라우저에서 이미 지원하고 있죠. 자, 재밌게 읽어주세요!
1. "이건 나중에 좀 실행해 줘" → requestIdleCallback
처음에는 이 API가 대체 왜 필요한가 싶었습니다. 브라우저가 '할 일이 없을 때' 코드를 실행하게 해주는 건데, 음... 괜찮긴 한데, 이게 그렇게 중요한가? 하고 말이죠.
그런데 막상 파고들면 활용 사례가 정말 많습니다. 예를 들어, 사용자가 페이지에서 어떻게 행동하는지 데이터를 수집하는 작업 같은 경우, 200개나 되는 컴포넌트가 렌더링되는 바쁜 와중에 처리하고 싶지는 않을 겁니다. 😅 이 외에도 중요도가 낮은 데이터를 로드하거나, 백그라운드에서 이미지를 전처리하거나 생성하는 등 다양한 상황에서 빛을 발하죠.
솔직히 말해, 개발자의 수만큼 활용 사례가 많다고 봐도 무방합니다. 제가 실무에서 유저 행동 데이터 수집 로직을 구현할 때, 초기에는 이벤트 리스너마다 지연을 줘서 처리했었는데, requestIdleCallback을 활용한 후로는 메인 스레드 부담 없이 훨씬 깔끔하게 처리할 수 있었습니다. 특히 애니메이션이나 사용자 인터랙션이 많은 페이지에서 큰 차이를 느낄 수 있었죠.
function trackUserScrolling() {
console.log("User scrolled. This changes everything.");
}
if ("requestIdleCallback" in window) {
requestIdleCallback(trackUserScrolling);
} else {
// 폴백: 구형 브라우저를 위해 setTimeout 사용
setTimeout(trackUserScrolling, 0);
}
지원: 최신 브라우저 (과거 Safari에서 누락되었으므로 폴백은 여전히 좋은 아이디어입니다)
2. "왜 내 인풋은 하이라이트가 안 되지?" → :focus-within
포커스를 받은 요소에 스타일을 적용하는 건 쉽습니다. 하지만 부모 div를 스타일링하고 싶다면 어떨까요? 예를 들어, 인풋에 포커스가 갔을 때 부모 div를 분홍색으로 만들고 꽃무늬를 추가하는 식으로요. 😉 40줄의 JavaScript 코드를 작성할 수도 있지만, :focus-within만 사용하면 간단하게 해결됩니다.
잘 작동하죠. 리스너도, 버그도, 고통도 없습니다.
.form-field {
border: 1px solid #ccc;
padding: 12px;
}
.form-field:focus-within {
border-color: hotpink; /* 자식 요소에 포커스가 있을 때 부모의 테두리 색상 변경 */
}
<div class="form-field">
<input placeholder="의미 있는 내용을 입력하세요..." />
</div>
지원: 거의 모든 주요 브라우저
3. "오프라인 모드를 보여주자" → navigator.onLine
PWA(Progressive Web App)를 만들어 본 적 있으신가요? 저는 몇 번 경험했는데, 사용자가 연결을 잃었을 때(예를 들어, 산속에 있거나 엘리베이터에 탔을 때 😄) 어떻게 해야 할지가 영원한 고민거리였습니다. 복잡한 if 문을 잔뜩 작성할 수도 있지만, 그보다는 offline 및 online 이벤트를 듣는 것이 훨씬 현명합니다. offline일 때는 IndexedDB에 데이터를 저장하고, 다시 online이 되면 서버로 전송할 수 있죠.
PWA를 개발하면서 오프라인 상태 관리가 정말 중요했는데, 처음에는 fetch 요청마다 catch 블록에서 네트워크 에러를 잡으려다 복잡해졌죠. navigator.onLine과 offline/online 이벤트를 활용하니 훨씬 명확하고 안정적으로 오프라인 UI를 제공할 수 있었습니다.
window.addEventListener("offline", () => {
alert("인터넷 연결이 끊겼습니다. 패닉할 시간입니다!");
});
window.addEventListener("online", () => {
alert("다시 연결되었습니다. 패닉 취소!");
});
지원: 널리 지원됨 (하지만 "온라인" ≠ "백엔드가 작동함"이라는 점을 명심하세요 😅)
4. "부드러운 애니메이션, 하지만 저주받은 버전으로" → requestAnimationFrame
이런 코드는 우리 모두 본 적 있을 겁니다.
setInterval(() => {
element.style.left = Math.random() * 100 + "px";
}, 16);
이게 최선의 방법이 아니라는 걸 느낌상 알죠. 😉 그냥 랙 걸립니다. 다행히 브라우저의 리페인트 주기와 동기화되는 requestAnimationFrame이 있어서, 실제로 부드러운 애니메이션을 만들 수 있습니다.
function animate() {
const element = document.getElementById("myElement"); // 예시로 element가 있다고 가정
if (element) {
element.style.transform = `translateX(${Date.now() % 300}px)`;
}
requestAnimationFrame(animate);
}
requestAnimationFrame(animate); // 애니메이션 시작
지원: 모든 브라우저
5. "이 카드는 여기에서만 반응형이어야 하는데..." → container queries
이 기능은 거의 '반칙'처럼 느껴집니다. 저는 경력상 CSS를 거의 작성하지 않는 시점에 와 있지만 (물론 가끔 2026년에 CSS를 배우는 것은 시간 낭비일까? 같은 글을 쓰는 순간은 제외하고요), 한때는 정말 많은 CSS를 썼습니다. 그리고 그때 '뷰포트 전체'가 아닌 '특정 요소'에 미디어 쿼리를 적용할 수 있다면 얼마나 좋았을까 항상 생각했습니다. 이제 마침내 그렇게 할 수 있습니다! 컴포넌트가 스스로 '나는 이 크기다!'라고 말해주는 느낌입니다. 덕분에 개발자는 커피 한잔의 여유를 가질 수 있게 되었죠.
.card-wrapper {
container-type: inline-size; /* 컨테이너 쿼리를 적용할 기준 설정 */
}
.card {
display: grid;
/* 기본 스타일 */
}
@container (min-width: 400px) {
.card {
grid-template-columns: 1fr 2fr; /* 컨테이너 너비가 400px 이상일 때 카드 레이아웃 변경 */
}
}
지원: 최신 브라우저 (필요시 폴백 추가)
6. "임의의 ID, 뭐가 문제겠어?" → crypto.getRandomValues
const id = Math.random().toString(36).slice(2);
버그는 이렇게 탄생합니다. 알리익스프레스산 '적당히 쓸만한' 암호화처럼 보이죠. 작동은 합니다... 망하기 전까지는요. 우선, 이는 엔진 구현에 따라 달라집니다. 내부적으로 무슨 일이 일어나는지 우리는 정확히 알 수 없죠. 특정 패턴이 얼마든지 발생할 수 있으며, 충분히 많은 ID를 생성하면 중복이 발생할 가능성이 매우 높아집니다.
다행히 이제 간단한 네이티브 솔루션이 있습니다. 만능 해결책은 아니지만, crypto.getRandomValues는 상당히 견고합니다. 훨씬 더 나은 엔트로피, 이상한 패턴 없음, 충돌 가능성 극적으로 감소. 브라우저가 알아서 제대로 해줍니다.
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짜리 라이브러리를 설치할 필요가 없어졌죠. 이 태그는 기본적으로 접근성까지 갖추고 있으니, 일석이조입니다. 예전에는 모달 하나 띄우겠다고 몇 킬로바이트짜리 라이브러리를 설치하거나, 스크롤 잠금, 키보드 접근성까지 직접 구현하느라 진땀을 뺐었죠. <dialog> 태그는 이런 번거로움을 한 방에 해결해 줄 뿐만 아니라, 기본적으로 웹 접근성까지 고려되어 있어서 개발자 입장에선 정말 큰 선물이라고 생각합니다.
<dialog id="modal">
<p>금요일에 배포하시겠습니까? 정말이요?</p>
<button onclick="modal.close()">취소</button>
<button onclick="alert('행운을 빌어요 😬')">배포</button>
</dialog>
<button onclick="modal.showModal()">모달 열기</button>
지원: 최신 브라우저
8. "음성 입력, 멋질 것 같은데..." → Speech API
음성 인식을 위해 벌써 transformers.js를 설치하고 계신가요? 잠깐, 진정하세요. 브라우저에도 비슷한 기능이 있다는 사실을 아셨나요? 음... 최소한 크로미움(Chromium) 기반 브라우저에서는 말이죠. 😄 따라서 사용자가 Chrome, Edge 또는 이와 유사한 브라우저를 사용하도록 "권장"할 수 있다면 충분히 활용할 수 있습니다. 개인적으로는 아직 프로덕션 사용에는 신중을 기하겠지만, 데모용으로는 어떨까요? 해볼 만하죠!
const SpeechRecognition =
window.SpeechRecognition || window.webkitSpeechRecognition; // 크로스 브라우저 호환성 고려
if (SpeechRecognition) {
const recognition = new SpeechRecognition();
recognition.onresult = e => {
console.log("당신은 이렇게 말했습니다:", e.results[0][0].transcript);
};
// 인식이 끝나면 자동으로 중지되므로, 필요하면 다시 시작해야 합니다.
recognition.onend = () => {
console.log("Speech recognition ended. Starting again...");
recognition.start();
};
recognition.start(); // 음성 인식 시작
} else {
console.warn("SpeechRecognition API is not supported in this browser.");
}
지원: 주로 크로미움 기반 브라우저
9. "이 CSS가 과연 터질까?" → @supports
여기에 고전적인 "제 컴퓨터에서는 잘 되는데요" 문제에 대한 현대적인 해결책이 있습니다. 최소한 CSS 영역에서는요. 😉 특정 CSS 속성이 레이아웃을 망가뜨릴지 추측할 필요가 없습니다. 그냥 @supports로 감싸주세요. 작은 함정이 있다면, 지원 범위가 매우 좋긴 하지만 '문자 그대로' 모든 곳은 아니라는 점입니다. 아이러니하게도 @supports를 @supports로 감싸는 상황도 생길 수 있겠죠!
.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-04 05:14:56