ui: add fluid sizing with clamp for responsive scaling

This commit is contained in:
2026-04-07 15:56:23 +02:00
parent 8bb5bc0a18
commit d035a6406b

View File

@@ -8,6 +8,30 @@
--link: #4a9eff;
--link-hover: #6bb3ff;
--link-active: #9966ff;
/* fluid typography scale */
--text-xs: clamp(0.625rem, 0.55rem + 0.25vw, 0.75rem); /* 10-12px */
--text-sm: clamp(0.6875rem, 0.6rem + 0.3vw, 0.8125rem); /* 11-13px */
--text-base: clamp(0.75rem, 0.65rem + 0.35vw, 0.9375rem); /* 12-15px */
--text-md: clamp(0.8125rem, 0.7rem + 0.4vw, 1rem); /* 13-16px */
--text-lg: clamp(0.875rem, 0.75rem + 0.45vw, 1.125rem); /* 14-18px */
--text-xl: clamp(1rem, 0.85rem + 0.5vw, 1.375rem); /* 16-22px */
--text-2xl: clamp(1.125rem, 0.95rem + 0.6vw, 1.5rem); /* 18-24px */
/* fluid spacing */
--space-xs: clamp(0.25rem, 0.2rem + 0.15vw, 0.375rem); /* 4-6px */
--space-sm: clamp(0.375rem, 0.3rem + 0.2vw, 0.5rem); /* 6-8px */
--space-md: clamp(0.5rem, 0.4rem + 0.3vw, 0.75rem); /* 8-12px */
--space-lg: clamp(0.75rem, 0.6rem + 0.5vw, 1rem); /* 12-16px */
--space-xl: clamp(1rem, 0.8rem + 0.7vw, 1.5rem); /* 16-24px */
--space-2xl: clamp(1.5rem, 1.2rem + 1vw, 2.5rem); /* 24-40px */
/* fluid sizing */
--poster-width: clamp(100px, 8vw + 60px, 180px);
--thumb-width: clamp(120px, 10vw + 40px, 200px);
--search-thumb: clamp(36px, 3vw + 20px, 50px);
--table-thumb: clamp(28px, 2vw + 16px, 40px);
--sidebar-width: clamp(200px, 15vw + 100px, 280px);
}
* {
@@ -18,7 +42,7 @@ body {
background-color: var(--bg);
color: var(--text);
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
font-size: 14px;
font-size: var(--text-lg);
line-height: 1.5;
margin: 0;
padding: 0;
@@ -27,7 +51,7 @@ body {
/* Header */
header {
padding: 8px 16px;
padding: var(--space-md) var(--space-lg);
background: var(--surface);
border-bottom: 1px solid var(--border);
position: sticky;
@@ -38,7 +62,7 @@ header {
.header-top {
display: flex;
align-items: center;
gap: 24px;
gap: var(--space-xl);
max-width: 1400px;
margin: 0 auto;
}
@@ -46,11 +70,11 @@ header {
.header-left {
display: flex;
align-items: center;
gap: 24px;
gap: var(--space-xl);
}
.logo {
font-size: 14px;
font-size: var(--text-lg);
font-weight: 700;
color: var(--text);
}
@@ -61,13 +85,13 @@ header {
.nav {
display: flex;
gap: 16px;
gap: var(--space-lg);
border-left: 1px solid var(--border);
padding-left: 16px;
padding-left: var(--space-lg);
}
.nav a {
font-size: 13px;
font-size: var(--text-md);
color: var(--link);
text-decoration: none;
}
@@ -89,9 +113,9 @@ header {
background: var(--surface);
border: 1px solid var(--border);
color: var(--text);
padding: 6px 8px;
font-size: 13px;
width: 320px;
padding: var(--space-sm) var(--space-md);
font-size: var(--text-md);
width: clamp(200px, 25vw + 80px, 400px);
font-family: inherit;
}
@@ -100,6 +124,11 @@ header {
border-color: var(--link);
}
.search-input:focus + .search-dropdown {
border-color: var(--link);
border-top-color: var(--link);
}
.search-input::placeholder {
color: var(--text-muted);
}
@@ -112,9 +141,9 @@ header {
right: 0;
background: var(--surface);
border: 1px solid var(--border);
border-top: none;
border-top: 1px solid var(--border);
margin-top: -1px;
max-height: 480px;
max-height: clamp(300px, 50vh, 600px);
overflow-y: auto;
z-index: 1000;
}
@@ -125,8 +154,8 @@ header {
}
.search-results-title {
padding: 8px 12px;
font-size: 11px;
padding: var(--space-md) var(--space-lg);
font-size: var(--text-xs);
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
@@ -135,8 +164,8 @@ header {
.search-result-item {
display: flex;
gap: 10px;
padding: 8px 12px;
gap: var(--space-md);
padding: var(--space-md) var(--space-lg);
border-bottom: 1px solid var(--border);
text-decoration: none;
color: inherit;
@@ -149,39 +178,39 @@ header {
}
.search-result-thumb {
width: 40px;
height: 60px;
width: var(--search-thumb);
aspect-ratio: 2/3;
object-fit: cover;
border: 1px solid var(--border);
flex-shrink: 0;
}
.search-result-no-image {
width: 40px;
height: 60px;
width: var(--search-thumb);
aspect-ratio: 2/3;
display: flex;
align-items: center;
justify-content: center;
background: var(--surface-hover);
border: 1px solid var(--border);
font-size: 9px;
font-size: var(--text-xs);
color: var(--text-muted);
flex-shrink: 0;
text-align: center;
padding: 4px;
padding: var(--space-xs);
}
.search-result-info {
display: flex;
flex-direction: column;
gap: 3px;
gap: var(--space-xs);
min-width: 0;
flex: 1;
padding-top: 2px;
}
.search-result-title {
font-size: 12px;
font-size: var(--text-base);
color: var(--text);
font-weight: 500;
display: -webkit-box;
@@ -192,16 +221,16 @@ header {
}
.search-result-type {
font-size: 11px;
font-size: var(--text-sm);
color: var(--text-muted);
}
.search-result-view-all {
display: block;
padding: 10px 12px;
padding: var(--space-md) var(--space-lg);
text-align: center;
color: var(--link);
font-size: 12px;
font-size: var(--text-base);
border-top: 1px solid var(--border);
text-decoration: none;
}
@@ -213,7 +242,7 @@ header {
/* Main */
main {
padding: 16px;
padding: var(--space-lg);
max-width: 1400px;
margin: 0 auto;
}
@@ -234,14 +263,14 @@ a:visited {
/* Grid */
.catalog-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 12px;
grid-template-columns: repeat(auto-fill, minmax(var(--thumb-width), 1fr));
gap: var(--space-lg);
}
.catalog-item {
display: flex;
flex-direction: column;
gap: 4px;
gap: var(--space-xs);
}
.catalog-thumb {
@@ -263,13 +292,13 @@ a:visited {
align-items: center;
justify-content: center;
color: var(--text-muted);
font-size: 12px;
font-size: var(--text-base);
background: var(--surface);
border: 1px solid var(--border);
}
.catalog-title {
font-size: 12px;
font-size: var(--text-base);
color: var(--text);
display: -webkit-box;
-webkit-line-clamp: 2;
@@ -281,14 +310,14 @@ a:visited {
.loading-indicator {
display: flex;
align-items: center;
gap: 8px;
gap: var(--space-md);
color: var(--text-muted);
font-size: 13px;
font-size: var(--text-md);
}
.loading-dot {
width: 3px;
height: 3px;
width: clamp(3px, 0.3vw + 2px, 5px);
height: clamp(3px, 0.3vw + 2px, 5px);
background: var(--text-muted);
animation: pulse 1.5s ease-in-out infinite;
}
@@ -307,18 +336,18 @@ a:visited {
/* Empty State */
.empty-state {
text-align: center;
padding: 48px 16px;
padding: var(--space-2xl) var(--space-lg);
}
.empty-state-title {
font-size: 16px;
font-size: var(--text-xl);
font-weight: 600;
color: var(--text);
margin-bottom: 8px;
margin-bottom: var(--space-md);
}
.empty-state-text {
font-size: 14px;
font-size: var(--text-lg);
color: var(--text-muted);
}
@@ -332,49 +361,49 @@ a:visited {
/* Login */
.login-container {
max-width: 280px;
margin: 60px auto;
max-width: clamp(260px, 20vw + 180px, 360px);
margin: var(--space-2xl) auto;
border: 1px solid var(--border);
padding: 16px;
padding: var(--space-lg);
background: var(--surface);
}
.login-container h2 {
font-size: 16px;
font-size: var(--text-xl);
font-weight: 600;
margin: 0 0 4px 0;
margin: 0 0 var(--space-xs) 0;
}
.login-subtitle {
color: var(--text-muted);
font-size: 12px;
margin: 0 0 16px 0;
font-size: var(--text-base);
margin: 0 0 var(--space-lg) 0;
}
.login-form {
display: flex;
flex-direction: column;
gap: 12px;
gap: var(--space-lg);
}
.form-group {
display: flex;
flex-direction: column;
gap: 4px;
gap: var(--space-xs);
}
.form-group label {
font-size: 12px;
font-size: var(--text-base);
color: var(--text);
font-weight: 500;
}
.form-group input {
padding: 6px 8px;
padding: var(--space-sm) var(--space-md);
background: var(--surface);
border: 1px solid var(--border);
color: var(--text);
font-size: 13px;
font-size: var(--text-md);
font-family: inherit;
}
@@ -384,14 +413,14 @@ a:visited {
}
.login-button {
padding: 6px;
padding: var(--space-sm);
background: var(--surface);
color: var(--text);
border: 1px solid var(--border);
font-size: 13px;
font-size: var(--text-md);
font-weight: 500;
cursor: pointer;
margin-top: 4px;
margin-top: var(--space-xs);
font-family: inherit;
}
@@ -405,11 +434,11 @@ a:visited {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
margin-bottom: var(--space-lg);
}
.watchlist-header h2 {
font-size: 16px;
font-size: var(--text-xl);
font-weight: 600;
margin: 0;
}
@@ -417,12 +446,12 @@ a:visited {
.watchlist-controls {
display: flex;
align-items: center;
gap: 16px;
font-size: 13px;
gap: var(--space-lg);
font-size: var(--text-md);
}
.text-link {
font-size: 13px;
font-size: var(--text-md);
font-family: inherit;
background: none;
border: none;
@@ -442,8 +471,8 @@ a:visited {
}
.view-toggle a {
padding: 4px 8px;
font-size: 12px;
padding: var(--space-xs) var(--space-md);
font-size: var(--text-base);
color: var(--link);
border-right: 1px solid var(--border);
text-decoration: none;
@@ -465,14 +494,14 @@ a:visited {
.status-tabs {
display: flex;
gap: 0;
margin-bottom: 16px;
margin-bottom: var(--space-lg);
border-bottom: 1px solid var(--border);
overflow-x: auto;
}
.status-tabs a {
padding: 8px 12px;
font-size: 12px;
padding: var(--space-md) var(--space-lg);
font-size: var(--text-base);
color: var(--link);
white-space: nowrap;
border-bottom: 2px solid transparent;
@@ -495,10 +524,10 @@ a:visited {
.watchlist-item .remove-btn {
position: absolute;
top: 4px;
right: 4px;
width: 20px;
height: 20px;
top: var(--space-xs);
right: var(--space-xs);
width: clamp(18px, 1.5vw + 12px, 24px);
height: clamp(18px, 1.5vw + 12px, 24px);
display: flex;
align-items: center;
justify-content: center;
@@ -506,7 +535,7 @@ a:visited {
border: 1px solid var(--border);
color: var(--text-muted);
cursor: pointer;
font-size: 12px;
font-size: var(--text-base);
opacity: 0;
transition: opacity 0.15s;
}
@@ -521,7 +550,7 @@ a:visited {
}
.watchlist-status {
font-size: 11px;
font-size: var(--text-sm);
color: var(--text-muted);
}
@@ -533,8 +562,8 @@ a:visited {
.watchlist-table th {
text-align: left;
padding: 8px 12px;
font-size: 12px;
padding: var(--space-md) var(--space-lg);
font-size: var(--text-base);
font-weight: 600;
color: var(--text);
border-bottom: 1px solid var(--border);
@@ -542,10 +571,10 @@ a:visited {
}
.watchlist-table td {
padding: 8px 12px;
padding: var(--space-md) var(--space-lg);
border-bottom: 1px solid var(--border);
vertical-align: middle;
font-size: 13px;
font-size: var(--text-md);
}
.watchlist-table tr:hover {
@@ -553,8 +582,8 @@ a:visited {
}
.watchlist-table .thumb {
width: 32px;
height: 48px;
width: var(--table-thumb);
aspect-ratio: 2/3;
object-fit: cover;
border: 1px solid var(--border);
}
@@ -565,12 +594,12 @@ a:visited {
.watchlist-table .status-cell {
color: var(--text-muted);
font-size: 12px;
font-size: var(--text-base);
}
.watchlist-table .remove-link {
color: var(--link);
font-size: 12px;
font-size: var(--text-base);
background: none;
border: none;
cursor: pointer;
@@ -586,7 +615,7 @@ a:visited {
/* Anime Page */
.anime-page {
display: flex;
gap: 24px;
gap: var(--space-xl);
max-width: 1200px;
}
@@ -597,13 +626,13 @@ a:visited {
.anime-hero {
display: flex;
gap: 16px;
margin-bottom: 24px;
gap: var(--space-lg);
margin-bottom: var(--space-xl);
}
.anime-poster {
flex-shrink: 0;
width: 140px;
width: var(--poster-width);
}
.anime-poster img {
@@ -617,52 +646,52 @@ a:visited {
}
.anime-info h1 {
font-size: 20px;
font-size: var(--text-2xl);
font-weight: 600;
margin: 0 0 4px 0;
margin: 0 0 var(--space-xs) 0;
}
.anime-alt-title {
font-size: 12px;
font-size: var(--text-base);
color: var(--text-muted);
margin: 0 0 12px 0;
margin: 0 0 var(--space-lg) 0;
}
.anime-quick-info {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
gap: var(--space-md);
margin-bottom: var(--space-lg);
}
.info-tag {
padding: 2px 6px;
padding: var(--space-xs) var(--space-sm);
background: var(--surface-hover);
border: 1px solid var(--border);
font-size: 11px;
font-size: var(--text-sm);
color: var(--text-muted);
}
.anime-actions {
margin-top: 12px;
margin-top: var(--space-lg);
}
.anime-synopsis {
margin-bottom: 24px;
margin-bottom: var(--space-xl);
}
.anime-synopsis h3,
.anime-relations h3 {
font-size: 12px;
font-size: var(--text-base);
font-weight: 600;
color: var(--text);
text-transform: uppercase;
letter-spacing: 0.05em;
margin: 0 0 12px 0;
margin: 0 0 var(--space-lg) 0;
}
.anime-synopsis p {
font-size: 13px;
font-size: var(--text-md);
line-height: 1.6;
color: var(--text);
margin: 0;
@@ -676,13 +705,13 @@ a:visited {
.relations-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 12px;
gap: var(--space-lg);
}
.relation-card {
display: flex;
flex-direction: column;
gap: 4px;
gap: var(--space-xs);
}
.relation-card.current {
@@ -709,7 +738,7 @@ a:visited {
}
.relation-title {
font-size: 11px;
font-size: var(--text-sm);
color: var(--text);
display: -webkit-box;
-webkit-line-clamp: 2;
@@ -720,10 +749,10 @@ a:visited {
/* Anime Sidebar */
.anime-sidebar {
flex-shrink: 0;
width: 240px;
width: var(--sidebar-width);
columns: 2;
column-gap: 8px;
padding: 12px;
column-gap: var(--space-md);
padding: var(--space-lg);
background: var(--surface);
border: 1px solid var(--border);
height: fit-content;
@@ -732,39 +761,39 @@ a:visited {
.sidebar-row {
display: flex;
flex-direction: column;
gap: 2px;
margin-bottom: 8px;
gap: var(--space-xs);
margin-bottom: var(--space-md);
break-inside: avoid;
}
.sidebar-label {
font-size: 11px;
font-size: var(--text-sm);
font-weight: 600;
color: var(--text);
text-transform: uppercase;
}
.sidebar-value {
font-size: 12px;
font-size: var(--text-base);
color: var(--text-muted);
line-height: 1.4;
}
.sidebar-row-wrap {
gap: 8px;
gap: var(--space-md);
}
.sidebar-tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
gap: var(--space-xs);
}
.sidebar-tag {
padding: 2px 6px;
padding: var(--space-xs) var(--space-sm);
background: var(--surface-hover);
border: 1px solid var(--border);
font-size: 11px;
font-size: var(--text-sm);
color: var(--text);
}
@@ -777,12 +806,12 @@ a:visited {
.dropdown-trigger {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-lg);
background: var(--surface);
border: 1px solid var(--border);
color: var(--text);
font-size: 13px;
font-size: var(--text-md);
font-family: inherit;
cursor: pointer;
}
@@ -793,7 +822,7 @@ a:visited {
}
.dropdown-arrow {
font-size: 10px;
font-size: var(--text-xs);
color: var(--text-muted);
}
@@ -802,7 +831,7 @@ a:visited {
top: 100%;
left: 0;
right: 0;
min-width: 160px;
min-width: clamp(140px, 12vw + 80px, 200px);
background: var(--surface);
border: 1px solid var(--border);
display: none;
@@ -819,11 +848,11 @@ a:visited {
align-items: center;
justify-content: space-between;
width: 100%;
padding: 8px 12px;
padding: var(--space-md) var(--space-lg);
background: none;
border: none;
color: var(--text);
font-size: 13px;
font-size: var(--text-md);
font-family: inherit;
cursor: pointer;
text-align: left;
@@ -845,7 +874,7 @@ a:visited {
.dropdown-item .check {
color: var(--link);
font-size: 12px;
font-size: var(--text-base);
}
.dropdown-item.remove {
@@ -861,9 +890,9 @@ a:visited {
/* Sort Filter */
.sort-filter {
display: flex;
gap: 16px;
margin-bottom: 16px;
padding: 12px;
gap: var(--space-lg);
margin-bottom: var(--space-lg);
padding: var(--space-lg);
background: var(--surface);
border: 1px solid var(--border);
}
@@ -871,11 +900,11 @@ a:visited {
.sort-filter-group {
display: flex;
align-items: center;
gap: 8px;
gap: var(--space-md);
}
.sort-filter-group label {
font-size: 12px;
font-size: var(--text-base);
color: var(--text-muted);
font-weight: 500;
}
@@ -884,8 +913,8 @@ a:visited {
background: var(--surface);
border: 1px solid var(--border);
color: var(--text);
padding: 6px 8px;
font-size: 12px;
padding: var(--space-sm) var(--space-md);
font-size: var(--text-base);
font-family: inherit;
cursor: pointer;
}
@@ -918,16 +947,16 @@ a:visited {
@media (max-width: 768px) {
header {
padding: 8px 12px;
padding: var(--space-md) var(--space-lg);
}
.header-top {
flex-wrap: wrap;
gap: 12px;
gap: var(--space-lg);
}
.header-left {
gap: 12px;
gap: var(--space-lg);
}
.nav {
@@ -947,49 +976,44 @@ a:visited {
}
main {
padding: 12px;
padding: var(--space-lg);
}
.catalog-grid {
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 8px;
gap: var(--space-md);
}
.anime-hero {
flex-direction: column;
gap: 12px;
gap: var(--space-lg);
}
.anime-poster {
width: 100px;
}
.anime-info h1 {
font-size: 16px;
width: clamp(80px, 15vw + 40px, 120px);
}
.relations-grid {
grid-template-columns: repeat(3, 1fr);
gap: 8px;
gap: var(--space-md);
}
}
/* Tabs */
.tabs {
display: flex;
gap: 16px;
margin-bottom: 24px;
gap: var(--space-lg);
margin-bottom: var(--space-xl);
border-bottom: 1px solid var(--border);
padding-bottom: 8px;
padding-bottom: var(--space-md);
}
.tab {
background: none;
border: none;
color: var(--text-muted);
font-size: 16px;
font-size: var(--text-xl);
cursor: pointer;
padding: 8px 16px;
padding: var(--space-md) var(--space-lg);
transition: color 0.2s;
text-transform: lowercase;
}