Category: 불면증 개선

  • 수면계산기: 미국수면재단 권장 범주

     

    #sleepcalc{–sc-bg:#ffffff;–sc-card:#fafafa;–sc-text:#111827;–sc-sub:#6b7280;–sc-primary:#3b82f6;–sc-accent:#10b981;–sc-border:#e5e7eb;–sc-danger:#ef4444;–sc-shadow:0 8px 30px rgba(0,0,0,.06);font-family:system-ui,-apple-system,Segoe UI,Roboto,Pretendard,Apple SD Gothic Neo,Noto Sans,Arial,sans-serif;color:var(–sc-text);}
    #sleepcalc *{box-sizing:border-box}
    #sleepcalc .sc-wrap{max-width:860px;margin:0 auto;background:var(–sc-bg);padding:16px}
    #sleepcalc .sc-card{background:var(–sc-card);border:1px solid var(–sc-border);border-radius:16px;box-shadow:var(–sc-shadow);overflow:hidden}
    #sleepcalc header{display:flex;gap:12px;align-items:center;padding:18px 20px;border-bottom:1px solid var(–sc-border);background:#fff}
    #sleepcalc .sc-title{font-weight:800;font-size:1.15rem;letter-spacing:-.015em}
    #sleepcalc .sc-sub{color:var(–sc-sub);font-size:.9rem}
    #sleepcalc .sc-body{padding:20px}
    #sleepcalc .grid{display:grid;gap:14px}
    @media(min-width:720px){#sleepcalc .grid{grid-template-columns:1fr 1fr}}
    #sleepcalc label{display:block;font-weight:700;margin:2px 0 8px}
    #sleepcalc select,#sleepcalc input[type=time],#sleepcalc input[type=number]{width:100%;padding:11px 12px;border:1px solid var(–sc-border);border-radius:12px;background:#fff;outline:none;transition:border .15s}
    #sleepcalc select:focus,#sleepcalc input:focus{border-color:var(–sc-primary)}
    #sleepcalc .radio-row{display:flex;flex-wrap:wrap;gap:8px}
    #sleepcalc .radio{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(–sc-border);border-radius:999px;background:#fff;cursor:pointer}
    #sleepcalc .radio input{accent-color:var(–sc-primary)}
    #sleepcalc .muted{color:var(–sc-sub);font-size:.88rem}
    #sleepcalc .row{display:grid;gap:8px}
    #sleepcalc .actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:10px}
    #sleepcalc button{border:0;border-radius:12px;padding:11px 14px;font-weight:800;cursor:pointer}
    #sleepcalc .btn-primary{background:var(–sc-primary);color:#fff}
    #sleepcalc .btn-ghost{background:#fff;border:1px solid var(–sc-border)}
    #sleepcalc .btn-link{background:transparent;color:var(–sc-sub);text-decoration:underline}
    #sleepcalc .result{margin-top:14px;border-top:1px dashed var(–sc-border);padding-top:16px}
    #sleepcalc .pill{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;border:1px solid var(–sc-border);background:#fff;font-weight:700}
    #sleepcalc .pill.primary{border-color:#bfdbfe;background:#eff6ff;color:#1d4ed8}
    #sleepcalc .pill.accent{border-color:#bbf7d0;background:#ecfdf5;color:#047857}
    #sleepcalc .pill.warn{border-color:#fecaca;background:#fff1f2;color:#b91c1c}
    #sleepcalc .times{display:flex;flex-direction:column;gap:10px;margin-top:12px}
    #sleepcalc .time-item{display:flex;align-items:center;gap:10px;justify-content:space-between;border:1px solid var(–sc-border);background:#fff;border-radius:12px;padding:10px 12px}
    #sleepcalc .time-left{display:flex;align-items:center;gap:10px}
    #sleepcalc .badge{font-size:.72rem;padding:4px 8px;border-radius:999px;border:1px solid var(–sc-border);color:var(–sc-sub)}
    #sleepcalc .best{border-color:#bfdbfe;background:#f0f9ff}
    #sleepcalc .note{font-size:.85rem;color:var(–sc-sub);margin-top:8px}
    #sleepcalc .foot{padding:14px 20px;border-top:1px solid var(–sc-border);background:#fff;color:var(–sc-sub);font-size:.86rem}
    #sleepcalc .icon{width:22px;height:22px}

    수면 계산기
    연령대와 기상/취침 시간 하나만 고르면 끝! (데이터 저장 안 함)

    선택하세요
    0–3개월 (신생아) · 14–17시간
    4–11개월 (영아) · 12–15시간
    1–2세 (유아) · 11–14시간
    3–5세 (유치) · 10–13시간
    6–13세 (학령기) · 9–11시간
    14–17세 (청소년) · 8–10시간
    18–25세 (청년) · 7–9시간
    26–64세 (성인) · 7–9시간
    65세 이상 (노년) · 7–8시간

    ※ 범주는 미국수면재단 권장안 요약입니다.


    예: 아침 8시 기상 기준으로, 전날 밤 취침 시각을 계산합니다.

    보통 10–20분. 기본 15분으로 계산합니다.

    연령대 권장 수면시간 범위 안에 드는 사이클 수만 자동 제시됩니다. (예: 성인 5–6사이클)


    ※ 이 도구는 건강 정보를 ‘편하게 이해’하도록 돕는 생활 도구이며, 의료적 진단·치료를 대체하지 않습니다.

    이 계산기는 JavaScript가 필요합니다. 브라우저 설정에서 JavaScript를 활성화해 주세요.

    (function(){
    const root = document.querySelector(‘#sleepcalc’);
    const form = root.querySelector(‘#sc-form’);
    const modeRadios = form.querySelectorAll(‘input[name=”mode”]’);
    const wakeRow = form.querySelector(‘#wakeRow’);
    const bedRow = form.querySelector(‘#bedRow’);
    const wakeEl = form.querySelector(‘#wake’);
    const bedEl = form.querySelector(‘#bed’);
    const ageEl = form.querySelector(‘#age’);
    const latencyEl = form.querySelector(‘#latency’);
    const resultEl = form.querySelector(‘#result’);

    // 모드 토글
    modeRadios.forEach(r=>r.addEventListener(‘change’,()=>{
    const v = getMode();
    if(v===’wake2bed’){wakeRow.style.display=’block’;bedRow.style.display=’none’;wakeEl.required=true;bedEl.required=false}
    else{wakeRow.style.display=’none’;bedRow.style.display=’block’;wakeEl.required=false;bedEl.required=true}
    resultEl.innerHTML=”;
    }));

    function getMode(){return form.querySelector(‘input[name=”mode”]:checked’).value}
    function parseTimeToMin(hhmm){const [h,m]=hhmm.split(‘:’).map(Number);return h*60+m}
    function minToHHMM(min){min=((min%1440)+1440)%1440;const h=Math.floor(min/60),m=min%60;return `${String(h).padStart(2,’0′)}:${String(m).padStart(2,’0′)}`}

    function compute(){
    const ageOpt = ageEl.options[ageEl.selectedIndex];
    if(!ageOpt || !ageOpt.dataset.min){resultEl.innerHTML=warn(‘연령대를 먼저 선택해 주세요.’);return}
    const minH = Number(ageOpt.dataset.min); // 권장 최소 (시간)
    const maxH = Number(ageOpt.dataset.max); // 권장 최대 (시간)
    const latency = Math.max(0, Math.min(60, Number(latencyEl.value||15))); // 분
    const mode = getMode();
    const CYCLE=90; // 분

    const pickCyclesInRange = ()=>{
    const picks=[];
    const minTotal = minH*60 + latency;
    const maxTotal = maxH*60 + latency;
    for(let c=3;c=minH*60+latency && total{
    const pref=(x)=>Math.abs(x-5.5);return pref(a)-pref(b)||a-b;
    });
    return picks;
    };

    let baseMin;
    try{
    baseMin = mode===’wake2bed’ ? parseTimeToMin(wakeEl.value) : parseTimeToMin(bedEl.value);
    }catch(e){resultEl.innerHTML=warn(‘시간을 올바르게 입력해 주세요.’);return}

    if(Number.isNaN(baseMin)){resultEl.innerHTML=warn(‘시간을 올바르게 입력해 주세요.’);return}

    const minTotal = minH*60 + latency;
    const maxTotal = maxH*60 + latency;

    const window = (mode===’wake2bed’)
    ? [baseMin – maxTotal, baseMin – minTotal]
    : [baseMin + minTotal, baseMin + maxTotal];

    // 사이클 추천
    const cycles = pickCyclesInRange();
    const suggestions = cycles.map(c=>{
    const total = c*CYCLE + latency;
    const when = (mode===’wake2bed’) ? baseMin – total : baseMin + total;
    return {cycles:c, total, ts:when, hhmm:minToHHMM(when), rel:relDay(when, baseMin, mode)}
    });

    // 최고의 두 가지를 선별: 균형(5사이클 근처), 깊은 휴식(6사이클 근처)
    const bestBalanced = suggestions.slice().sort((a,b)=>Math.abs(a.cycles-5)-Math.abs(b.cycles-5) || a.cycles-b.cycles)[0];
    const bestDeep = suggestions.slice().sort((a,b)=>Math.abs(a.cycles-6)-Math.abs(b.cycles-6) || a.cycles-b.cycles)[0];

    // 결과 렌더링
    const windowFrom = minToHHMM(window[0]);
    const windowTo = minToHHMM(window[1]);
    const windowRelL = relDay(window[0], baseMin, mode);
    const windowRelR = relDay(window[1], baseMin, mode);

    let html = ”;
    html += `

    권장 범위: ${minH}–${maxH}시간 · 입면 ${latency}분 포함

    `;
    html += `

    ${mode===’wake2bed’?’취침’:’기상’} 권장 시간대: ${badge(windowRelL)} ${windowFrom} ~ ${badge(windowRelR)} ${windowTo}

    `;

    if(suggestions.length){
    html += ‘

    ‘;
    const printed = new Set();
    const pushItem=(s,label,isBest)=>{
    if(!s || printed.has(s.cycles)) return; printed.add(s.cycles);
    const dur = fmtDur(s.total);
    html += `

    `
    + `

    ${label||(`${s.cycles}사이클`)}`
    + `

    ${badge(s.rel)} ${s.hhmm}

    `
    + `

    총 수면 ${dur} (입면 ${latency}분 포함)

    `
    + ``
    + `

    `;
    };
    pushItem(bestBalanced, ‘균형 추천’, true);
    pushItem(bestDeep, ‘깊은 휴식’, true);
    suggestions.filter(s=>s!==bestBalanced && s!==bestDeep).forEach(s=>pushItem(s));
    html += ‘

    ‘;
    } else {
    html += `

    해당 연령대 권장 시간 범위가 넓어 특정 사이클 추천이 어려워요. 위 권장 시간대를 참고해 주세요.

    `
    }

    resultEl.innerHTML = html;

    // 복사 버튼
    resultEl.querySelectorAll(‘button[data-copy]’).forEach(btn=>{
    btn.addEventListener(‘click’,()=>{
    const v=btn.getAttribute(‘data-copy’);
    navigator.clipboard?.writeText(v).then(()=>{
    btn.textContent=’복사됨’;
    setTimeout(()=>btn.textContent=’복사’,1200);
    });
    });
    })
    }

    function warn(msg){return `

    ${msg}

    `}
    function relDay(ts, base, mode){
    const diff = ts – base;
    if(mode===’wake2bed’){ // 과거로 이동
    return diff<=-1440? '이틀 전': diff=1440? ‘모레’: diff>=1440? ‘모레’: diff>=0? (diff>=1440?’모레’: (diff>=0 && diff<1440?'다음날':'')) : '';
    }
    }
    function badge(rel){return rel?`${rel}`:”}
    function fmtDur(min){const h=Math.floor(min/60),m=min%60;return `${h}시간 ${m?m+’분’:”}`.trim()}

    form.addEventListener(‘submit’,e=>{e.preventDefault();compute()});
    root.querySelector(‘#resetBtn’).addEventListener(‘click’,()=>{form.reset();wakeRow.style.display=’block’;bedRow.style.display=’none’;wakeEl.value=’08:00′;bedEl.value=’23:00′;latencyEl.value=15;resultEl.innerHTML=”});

    // 초기 계산 예시: 성인, 08:00 기상 → 22:45 / 00:15 제시
    compute();
    })();