Silence as design

디자인으로서의 침묵

The deliberate choice not to add sound. When every event makes noise, eventually none of it gets heard.

Also known as: Sound restraintNotification fatigue
···
html
<div class="wrap">
  <div class="col">
    <div class="cap">알림 폭탄 → <b>소리 남발</b></div>
    <div class="list" id="loud">
      <div class="item"><span class="skel"></span><span class="wave"></span></div>
      <div class="item"><span class="skel"></span><span class="wave"></span></div>
      <div class="item"><span class="skel"></span><span class="wave"></span></div>
    </div>
    <button class="play" id="playLoud" type="button" aria-label="play noisy sound"><span class="tri"></span></button>
  </div>
  <div class="col">
    <div class="cap">침묵 설계 → <b>배지만</b></div>
    <div class="list" id="quiet">
      <div class="item"><span class="skel"></span><span class="badge"></span></div>
      <div class="item"><span class="skel"></span><span class="badge"></span></div>
      <div class="item"><span class="skel"></span><span class="badge"></span></div>
    </div>
    <button class="play" id="playQuiet" type="button" aria-label="trigger silent badge"><span class="mute"></span></button>
  </div>
</div>
css
.wrap{position:relative;width:96%;height:88%;display:flex;gap:5%}
.col{position:relative;flex:1;border:1px solid var(--line);border-radius:12px;background:var(--surface);padding:8px;display:flex;flex-direction:column;gap:6px}
.cap{font:600 10px/1.3 monospace;color:var(--muted)}
.cap b{color:var(--fg)}
.list{display:flex;flex-direction:column;gap:6px;flex:1}
.item{position:relative;height:22%;border-radius:8px;background:var(--bg);border:1px solid var(--line);display:flex;align-items:center;padding:0 30px 0 10px}
.skel{display:block;width:60%;height:20%;border-radius:3px;background:var(--line);opacity:.6}
.wave{position:absolute;top:50%;right:10px;transform:translateY(-50%);width:8px;height:8px;opacity:0}
.wave::before,.wave::after{content:'';position:absolute;border:1.5px solid var(--accent-2);border-radius:50%;inset:0}
.wave::after{inset:-4px}
.item.go .wave{animation:pop .5s ease-out}
@keyframes pop{0%{opacity:.9;transform:translateY(-50%) scale(.6)}100%{opacity:0;transform:translateY(-50%) scale(1.3)}}
.badge{position:absolute;top:6px;right:6px;width:8px;height:8px;border-radius:50%;background:var(--line)}
.item.go .badge{background:var(--accent-3);animation:badgepulse .5s ease-out}
@keyframes badgepulse{0%{transform:scale(1.6)}100%{transform:scale(1)}}
.play{align-self:flex-end;width:26px;height:26px;border-radius:50%;border:1px solid var(--line);background:var(--bg);display:grid;place-items:center;cursor:pointer}
.play .tri{width:0;height:0;border-style:solid;border-width:5px 0 5px 8px;border-color:transparent transparent transparent var(--fg);margin-left:1px}
.play .mute{width:8px;height:8px;border-radius:50%;background:var(--fg)}
.play:active{transform:scale(.92)}
@media (min-width:460px){
  .col{padding:16px}
  .cap{font-size:14px}
  .item{border-radius:12px}
  .skel{height:16%}
  .play{width:40px;height:40px}
  .play .tri{border-width:8px 0 8px 12px;margin-left:2px}
  .play .mute{width:12px;height:12px}
}
js
const loudItems = document.querySelectorAll('#loud .item');
const quietItems = document.querySelectorAll('#quiet .item');
let idx = 0;
setInterval(() => {
  loudItems.forEach((it) => it.classList.remove('go'));
  quietItems.forEach((it) => it.classList.remove('go'));
  loudItems[idx].classList.add('go');
  quietItems[idx].classList.add('go');
  idx = (idx + 1) % loudItems.length;
}, 900);
function beep(ctx, t, freq) {
  const osc = ctx.createOscillator();
  const gain = ctx.createGain();
  osc.type = 'square';
  osc.frequency.value = freq;
  gain.gain.setValueAtTime(0, t);
  gain.gain.linearRampToValueAtTime(0.08, t + 0.008);
  gain.gain.exponentialRampToValueAtTime(0.0001, t + 0.09);
  osc.connect(gain).connect(ctx.destination);
  osc.start(t);
  osc.stop(t + 0.1);
}
document.getElementById('playLoud').addEventListener('click', () => {
  const ctx = new (window.AudioContext || window.webkitAudioContext)();
  const now = ctx.currentTime;
  [880, 990, 830, 1040].forEach((f, i) => beep(ctx, now + i * 0.11, f));
  loudItems.forEach((it) => { it.classList.remove('go'); void it.offsetWidth; it.classList.add('go'); });
  setTimeout(() => ctx.close(), 700);
});
document.getElementById('playQuiet').addEventListener('click', () => {
  // 의도적으로 소리를 재생하지 않는다 — 이게 이 항목의 핵심이다.
  quietItems.forEach((it) => { it.classList.remove('go'); void it.offsetWidth; it.classList.add('go'); });
});

The hardest decision in sound design is often not "should this event make a sound" but "should it not." Ring a sound on every notification and users quickly mute everything or delete the app — most smartphone users actually leave most app notification sounds off. Silence isn't a lack of design; it's an active tool that signals "this doesn't need your attention right now."

Before attaching a sound to an event, ask whether it's actually important enough to interrupt the user right now. Minor state changes (a like count updating, a background sync finishing) are well served by a quiet badge or color change alone. The one thing that keeps a truly important sound (payment failure, security alert) effective is restraint elsewhere — a real emergency gets buried in a stream of routine dings.

Used in default notification settings, a messaging app's "mute this conversation" feature, background task completion indicators, and do-not-disturb mode during meetings.

When to use

Before attaching sound to an event, ask whether it needs attention right now. If not, a visual signal alone is enough.