미디어위키:MainPage.css

Nxdsxn (토론 | 기여)님의 2026년 5월 19일 (화) 07:08 판 (새 문서: →‎========================================= COASTLINE: BLACK ICE - MainPage 대문 전용 스타일 =========================================: /* 설계 목적 ----------------------------------------- 이 파일은 대문 전용 화면 구성만 담당한다. 이전 테스트 단계에서는 MediaWiki:Test.css 안에 대문 레이아웃, 이미지 피드, 방명록 더미, 스타일 매뉴얼, 카테고리 네비 실험 코드가 모두 섞여 있었다. 그 상태로 실...)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.

  • 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
  • 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
  • 인터넷 익스플로러 / 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
  • 오페라: Ctrl-F5를 입력.
/* =========================================
COASTLINE: BLACK ICE - MainPage
대문 전용 스타일
========================================= */

/*
설계 목적
-----------------------------------------
이 파일은 대문 전용 화면 구성만 담당한다.

이전 테스트 단계에서는 MediaWiki:Test.css 안에
대문 레이아웃, 이미지 피드, 방명록 더미, 스타일 매뉴얼,
카테고리 네비 실험 코드가 모두 섞여 있었다.

그 상태로 실사용에 넣으면 다음 문제가 생긴다.

1. 어느 코드가 대문 전용인지, 어느 코드가 공통 컴포넌트인지 구분하기 어렵다.
2. 나중에 일반 문서 네비바나 사이드바를 고칠 때 대문 코드가 같이 영향을 받을 수 있다.
3. 테스트용 더미와 실제 운영 UI가 같은 파일에 남아 유지보수가 어려워진다.

따라서 이 파일은 대문 본문 안에서 쓰는
.main-portal 스코프 내부만 담당한다.

주의:
- body, .liberty-content, .content-wrapper 같은 전역 레이아웃은 건드리지 않는다.
- 상단 공통 네비바, 좌우 사이드바, 관리자 패널은 이 파일의 책임이 아니다.
- 카테고리 네비는 JS가 DOM을 생성하고, 이 파일은 그 결과물의 모양만 담당한다.
*/

/* -----------------------------------------
0. Main portal scope
----------------------------------------- */

.main-portal {
--surface-page:#070707;
--surface-frame:#101010;
--surface-frame-soft:#141414;
--surface-title:#1d1d1d;
--surface-title-hover:#252525;
--surface-well:#080808;

--edge-top:#555555;
--edge-side:#2b2b2b;
--edge-bottom:#050505;
--edge-soft:#202020;

--text-main:#e2e2e2;
--text-soft:#c8c8c8;
--text-dim:#8a8a8a;
--text-faint:#626262;

--space-block:8px;
--space-inner:6px;
--pad-panel:8px;

--nav-h:30px;

width:100%;
margin:0 auto;
padding:var(--space-block);
box-sizing:border-box;
background:var(--surface-page);
color:var(--text-main);
font-size:11px;
line-height:1.5;
}

.main-portal *,
.main-portal *::before,
.main-portal *::after {
box-sizing:border-box;
}

.main-portal a {
color:var(--text-main) !important;
text-decoration:none !important;
}

.main-portal a:hover {
color:#ffffff !important;
text-decoration:none !important;
}

/* -----------------------------------------
1. Category nav mount
----------------------------------------- */

/*
[data-component="category-nav"]는 본문에 남겨두는 자리 표시자다.

본문에 위키문법으로 링크를 직접 조립하면,
MediaWiki가 생성한 <a>와 바깥 span이 분리된다.
그 상태에서는 실제 클릭 영역, 호버 영역, 사선 모양이 서로 어긋난다.

따라서 본문에는 비어 있는 mount만 두고,
CategoryNav.js가 실제 <a class="..."> 요소들을 생성한다.

이렇게 하면 하나의 <a>가 다음 역할을 동시에 담당한다.

1. 보이는 항목
2. 클릭되는 링크
3. 호버되는 면
4. clip-path로 잘린 사선 버튼

이 구조가 이번 문제의 핵심 해결책이다.
*/

.main-portal [data-component="category-nav"] {
display:block;
width:100%;
margin:0 0 var(--space-block);
}

/* -----------------------------------------
2. Category navigation
----------------------------------------- */

/*
카테고리 바의 시각 규칙
-----------------------------------------
- 전체는 하나의 긴 바처럼 보여야 한다.
- 각 항목은 독립 버튼처럼 외장을 가지면 안 된다.
- 부모 .portal-category-nav가 표면, 테두리, 상하 입체감을 담당한다.
- 각 .portal-cat-link는 클릭 영역과 호버 영역만 담당한다.
- 왼쪽 3개 항목은 \ 방향으로 잘린다.
- 가운데 프로젝트는 \ PROJECT / 형태다.
- 오른쪽 3개 항목은 / 방향으로 잘린다.
- 검은 획은 항목 외장이 아니라 구분선이다.

이전 실패 기록
-----------------------------------------
1. span 안에 [[위키링크]]를 넣고 span에 clip-path를 주는 방식:
   MediaWiki가 만든 <a>와 span이 분리되어 클릭/호버/시각 범위가 계속 엇갈렸다.

2. ::after로 사선 획을 각 버튼 내부에 넣는 방식:
   clip-path가 ::after까지 잘라먹어서 왼쪽 획이 사라지거나 위치가 어긋났다.

3. 버튼끼리 음수 margin으로 겹치는 방식:
   빈 사선 영역은 메워졌지만 호버 배경이 옆 칸으로 넘어갔다.

4. 호버와 획을 별도 overlay로 분리하는 방식:
   JS 없이 좌표를 수동 계산해야 해서 프로젝트 폭이 바뀔 때 유지보수가 어려웠다.

이번 구조
-----------------------------------------
JS가 실제 <a class="portal-cat-link ...">를 생성한다.
각 링크 자체에 clip-path와 :hover를 적용한다.
따라서 보이는 모양, 클릭 범위, 호버 범위가 같은 요소에 묶인다.
*/

.portal-category-nav {
--cat-cell-w:163px;
--cat-cut:10px;

position:relative;
display:grid;
grid-template-columns:
var(--cat-cell-w)
var(--cat-cell-w)
var(--cat-cell-w)
minmax(180px,1fr)
var(--cat-cell-w)
var(--cat-cell-w)
var(--cat-cell-w);
width:100%;
height:var(--nav-h);
margin:0;
padding:0;
overflow:hidden;

background:var(--surface-frame-soft);
border:1px solid;
border-color:
var(--edge-top)
var(--edge-side)
var(--edge-bottom)
var(--edge-side);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.055),
inset 0 -1px 0 rgba(0,0,0,0.72);
}

/*
각 링크는 실제 버튼이다.

여기서는 개별 버튼 외장을 만들지 않는다.
background는 평소 transparent이고, hover 때만 아주 약하게 밝아진다.
개별 border, 개별 box-shadow를 넣으면 7개의 독립 버튼처럼 보이므로 금지한다.
*/

.portal-cat-link {
position:relative;
display:flex !important;
align-items:center !important;
justify-content:center !important;
height:var(--nav-h);
min-width:0;
padding:0 10px !important;
box-sizing:border-box !important;

background:transparent;
border:none;
box-shadow:none;

color:var(--text-main) !important;
font-size:10px !important;
font-weight:700 !important;
line-height:1.2 !important;
text-align:center !important;
text-decoration:none !important;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;

text-shadow:
1px 1px 0 #000,
0 0 2px rgba(0,0,0,0.85) !important;
}

/*
중앙 프로젝트는 의미상 허브이므로 글자만 살짝 키운다.
표면이나 색으로 강조하지 않는다.
*/

.portal-cat-project {
font-size:11px !important;
letter-spacing:0.2px;
}

/*
사선 형태
-----------------------------------------
왼쪽군:
- 오른쪽 경계가 \ 방향으로 깎인다.

프로젝트:
- 왼쪽 경계는 \ 쪽과 맞물린다.
- 오른쪽 경계는 / 쪽과 맞물린다.

오른쪽군:
- 왼쪽 경계가 / 방향으로 깎인다.

첫 항목과 마지막 항목은 바깥 프레임과 맞닿으므로
바깥쪽은 직각으로 유지한다.
*/

.portal-cat-left-start {
clip-path:polygon(
0 0,
calc(100% - var(--cat-cut)) 0,
100% 100%,
0 100%
);
}

.portal-cat-left-mid,
.portal-cat-left-end {
clip-path:polygon(
0 0,
calc(100% - var(--cat-cut)) 0,
100% 100%,
var(--cat-cut) 100%
);
}

.portal-cat-project {
clip-path:polygon(
0 0,
100% 0,
calc(100% - var(--cat-cut)) 100%,
var(--cat-cut) 100%
);
}

.portal-cat-right-start,
.portal-cat-right-mid {
clip-path:polygon(
var(--cat-cut) 0,
100% 0,
calc(100% - var(--cat-cut)) 100%,
0 100%
);
}

.portal-cat-right-end {
clip-path:polygon(
var(--cat-cut) 0,
100% 0,
100% 100%,
0 100%
);
}

/*
호버
-----------------------------------------
호버는 각 <a>에 직접 적용한다.
이전처럼 별도 overlay를 좌표로 맞추는 방식은 쓰지 않는다.
그래야 화면 크기와 프로젝트 폭이 바뀌어도 호버 범위가 유지된다.
*/

.portal-cat-link:hover {
background:rgba(255,255,255,0.035);
color:#ffffff !important;
text-decoration:none !important;
}

.portal-cat-link:active {
background:rgba(0,0,0,0.20);
padding-top:1px !important;
}

/*
검은 구분 획
-----------------------------------------
획은 각 링크 안에서 그린다.

이전에는 clip-path가 ::after를 잘라먹어서
왼쪽 항목의 획이 사라지는 문제가 있었다.
이번 구조에서는 <a> 자체가 링크이므로 시각과 호버가 일치하고,
획도 버튼 내부에서 같은 clip-path 기준으로 움직인다.

다만 획이 지나치게 두꺼우면 '틈'처럼 보이므로 1px로 둔다.
*/

.portal-cat-link::after {
content:"";
position:absolute;
top:-5px;
bottom:-5px;
right:calc(var(--cat-cut) - 1px);
width:1px;
z-index:3;
pointer-events:none;
background:#050505;
opacity:0.96;
display:none;
transform-origin:top center;
}

.portal-cat-left-start::after,
.portal-cat-left-mid::after,
.portal-cat-left-end::after {
display:block;
transform:skewX(18.5deg);
}

.portal-cat-project::after,
.portal-cat-right-start::after,
.portal-cat-right-mid::after {
display:block;
right:0;
transform:skewX(-18.5deg);
}

/*
반응형
-----------------------------------------
좁은 화면에서는 사선 구조를 유지하면 읽기가 어려워진다.
대문용 큰 네비의 축소판을 억지로 유지하지 않고,
한 줄씩 쌓이는 일반 버튼 목록으로 전환한다.
*/

@media screen and (max-width:1180px) {
.portal-category-nav {
height:auto;
grid-template-columns:minmax(0,1fr);
}

.portal-cat-link,
.portal-cat-project {
height:var(--nav-h);
clip-path:none;
}

.portal-cat-link::after {
display:none !important;
}
}