feat(responsive): 모바일 대응 — 데스크톱 유지, 반응형 CSS 마지막 로드로 분리

문제: 기존 반응형 @media 가 base.css(2번째 로드)에 있어, 뒤에 로드되는
components/layout 규칙에 덮여 사실상 무력했음(폰에서 그리드가 안 접힘).

- public/css/responsive.css 신설, _header 에서 맨 마지막에 <link>
  → 미디어쿼리가 데스크톱 규칙을 !important 없이 정상 override
- base.css 의 죽은 반응형 블록 제거(responsive.css 로 이관)
- @media 640: 헤더 flex-wrap(검색창 둘째 줄 전체폭·숨김 해제),
  탭 영역 44px, 크롭 스테이지 aspect-ratio 정사각, 입력 16px(iOS 확대 방지),
  좌우 여백/모달 여백 축소, 프로필 히어로 세로 스택
- 데스크톱(>640)은 규칙 미적용 → 기존과 픽셀 동일

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-10 14:05:20 +09:00
parent 56430b7701
commit 75685e41da
3 changed files with 62 additions and 11 deletions

View File

@@ -56,14 +56,4 @@ svg { display: block; }
@keyframes aidev-fade { from{opacity:0} to{opacity:1} }
@keyframes aidev-toast { 0%{transform:translateX(-50%) translateY(12px);opacity:0} 12%{transform:translateX(-50%) translateY(0);opacity:1} 88%{transform:translateX(-50%) translateY(0);opacity:1} 100%{transform:translateX(-50%) translateY(8px);opacity:0} }
/* 반응형 */
@media (max-width: 900px) {
.tools-grid { grid-template-columns: repeat(2, 1fr); }
.myproj-grid { grid-template-columns: repeat(2, 1fr); }
.feed-grid { grid-template-columns: 1fr; }
.brand-sub { display: none; }
}
@media (max-width: 560px) {
.tools-grid, .myproj-grid { grid-template-columns: 1fr; }
.hdr-search { display: none; }
}
/* 반응형 규칙은 public/css/responsive.css 로 이동(로드 순서상 마지막이어야 실제 적용됨). */

59
public/css/responsive.css Normal file
View File

@@ -0,0 +1,59 @@
/* 반응형(모바일) — 데스크톱 규칙을 덮어써야 하므로 반드시 다른 CSS 이후 마지막에 로드한다.
(_header.ejs 의 <link> 순서가 바뀌면 미디어쿼리가 무력화됨. 특히 헤더 검색창 재노출이 로드 순서에 의존.)
데스크톱(>640px 등)은 아래 규칙이 적용되지 않아 기존과 완전히 동일하다. */
/* ===================== 그리드 단계 축소 ===================== */
/* (기존 base.css 에 있었으나 로드 순서 때문에 무력했던 규칙 — 여기로 옮겨 실제 작동) */
@media (max-width: 900px) {
.tools-grid { grid-template-columns: repeat(2, 1fr); }
.myproj-grid { grid-template-columns: repeat(2, 1fr); }
.feed-grid { grid-template-columns: 1fr; }
.brand-sub { display: none; }
}
@media (max-width: 560px) {
.tools-grid, .myproj-grid { grid-template-columns: 1fr; }
}
/* ===================== 모바일 레이아웃 · 터치 다듬기 ===================== */
@media (max-width: 640px) {
/* 헤더: 고정 높이 해제 → 줄바꿈 허용. 검색창은 둘째 줄 전체 폭으로. */
.hdr-inner { flex-wrap: wrap; height: auto; min-height: 56px; padding: 8px 16px; row-gap: 8px; }
.brand { flex: 1 1 auto; min-width: 0; }
.hdr-right { margin-left: auto; } /* 브랜드와 같은 첫 줄, 우측 정렬 유지 */
.hdr-search { display: flex; order: 10; flex-basis: 100%; max-width: none; } /* base 의 display:none 을 로드순서로 이김 → 둘째 줄 */
/* 터치 영역 ≥44px */
.icon-btn, .modal-close { width: 44px; height: 44px; }
.hdr-link, .usermenu-btn { min-height: 44px; }
.profile-bio-edit { width: 40px; height: 40px; } /* 배지형이라 44는 과함 */
.profile-avatar-edit { width: 36px; height: 36px; }
.filter-tab, .sort-tab, .vis-opt, .react-btn, .readme-btn,
.toggle-share-btn, .share-mini-btn, .new-proj-btn, .feed-star-btn,
.comment-link, .modal-action, .btn { min-height: 44px; }
/* 크롭 스테이지 정사각 유지(profile.js 의 clientWidth==clientHeight 가정 충족) */
.crop-stage { width: 100%; height: auto; aspect-ratio: 1 / 1; }
/* 입력창 16px — iOS 포커스 시 자동확대 방지 */
.hdr-search input, .share-input, .share-input.mono,
.comment-input, .profile-bio-form input { font-size: 16px; }
/* 좌우 여백 축소 (24px → 16px) */
.main { padding: 20px 16px 48px; }
.detail-wrap { padding: 20px 16px 48px; } /* project.ejs 단독 상세 */
.footer-inner { padding: 16px; }
/* 줄바꿈 / 프로필 히어로 세로 스택 */
.section-head, .feed-head, .feed-head-right { flex-wrap: wrap; }
.profile-hero { flex-direction: column; align-items: center; text-align: center; gap: 14px; }
.profile-idline, .profile-metaline, .profile-bio-row, .profile-bio-form { justify-content: center; }
/* 모달 여백 축소 */
.modal-overlay { padding: 16px 12px; }
.modal-head { padding: 16px 16px 14px; }
.modal-body { padding: 14px 16px 4px; }
.modal-foot { padding: 12px 16px 18px; }
.modal-foot-actions{ padding: 12px 16px; }
.share-head, .share-body, .crop-body { padding: 16px; }
.crop-head { padding: 14px 16px; }
}

View File

@@ -12,6 +12,8 @@
<link rel="stylesheet" href="/public/css/layout.css" />
<link rel="stylesheet" href="/public/css/components.css" />
<link rel="stylesheet" href="/public/css/modal.css" />
<!-- 반응형(모바일) — 데스크톱 규칙을 덮어써야 하므로 반드시 맨 마지막에 로드. 순서 바꾸지 말 것. -->
<link rel="stylesheet" href="/public/css/responsive.css" />
<script>
// FOUC 방지: 저장된 테마를 페인트 전에 documentElement 에 적용
(function () {