← Back to the site changelog
Site Changelog
Original commit record
Fix iPad portrait responsive layout (#153)
Add a tablet breakpoint for compact navigation, prevent horizontal overflow, prioritize the main news column, stack the radar layout, and cover the breakpoint with regression tests.
SHA
31db04c68fa534b6924b855582c02729c096b59a
Commit date
2026-08-29T18:01:40Z
Author
nnneeeooo-nnneeeooo
Committer
web-flow
Changed files (3)
static/app.js
modified · +1 / −1
static/site.css
modified · +38 / −13
tests/test_mobile_layout.py
modified · +5 / −1
Full diff
@@ -102,7 +102,7 @@\n document.addEventListener("keydown", function (event) {\n if (event.key === "Escape") setNavOpen(false);\n });\n- var desktopNav = window.matchMedia("(min-width: 721px)");\n+ var desktopNav = window.matchMedia("(min-width: 901px)");\n desktopNav.addEventListener("change", function (event) {\n if (event.matches) setNavOpen(false);\n });\n@@ -563,31 +563,56 @@ a.flash-row:hover { color: inherit; }\n .changelog-group { grid-template-columns: 96px minmax(0, 1fr); }\n }\n \n-@media (max-width: 720px) {\n- .utility-row { padding: 8px 12px; gap: 8px 12px; }\n- .utility-date { flex-basis: 100%; }\n- .utility-update { margin-left: 0; }\n+/* Tablet portrait (including the 820px-wide iPad Air): use the compact\n+ navigation before the full desktop nav starts scrolling or squeezing. */\n+@media (max-width: 900px) {\n+ .page { width: 100%; overflow-x: clip; }\n .brand-row {\n- padding: 9px 12px; gap: 12px; flex-wrap: nowrap;\n+ padding: 9px 16px; gap: 12px; flex-wrap: wrap;\n justify-content: space-between;\n }\n- .brand-link { flex: 0 1 224px; min-width: 0; }\n- .brand-logo { max-width: 224px; }\n- .brand-name { font-size: 18px; }\n- .brand-tagline { font-size: 9px; letter-spacing: .11em; white-space: nowrap; }\n- .nav-toggle { display: inline-flex; flex-shrink: 0; }\n+ .brand-link { flex: 0 1 280px; min-width: 0; }\n+ .brand-logo { max-width: 280px; }\n+ .nav-toggle { display: inline-flex; flex-shrink: 0; margin-left: auto; }\n .site-nav {\n- order: 3; width: 100%; margin: 0; padding: 4px 0 0; overflow: visible;\n- display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;\n+ order: 3; width: 100%; flex: 0 0 100%; margin: 0; padding: 4px 0 0;\n+ overflow: visible; display: grid;\n+ grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px;\n white-space: normal;\n }\n .js .site-nav { display: none; }\n .js .site-nav.is-open { display: grid; }\n .nav-link {\n- min-height: 44px; padding: 10px 12px; display: flex; align-items: center;\n+ min-width: 0; min-height: 44px; padding: 10px 12px;\n+ display: flex; align-items: center;\n border: 1px solid var(--color-divider); border-bottom-width: 1px;\n+ overflow-wrap: anywhere;\n }\n .nav-link.active { border-color: var(--color-accent); }\n+ .center-col { order: 1; }\n+ .rail-left {\n+ order: 2; border-top: 2px solid var(--color-divider); border-bottom: 0;\n+ }\n+ .rail-right { order: 3; }\n+ .radar-layout { grid-template-columns: minmax(0, 1fr); min-height: 0; }\n+ .radar-map { min-height: 520px; }\n+ .radar-list-panel { border-left: 0; border-top: 1px solid var(--color-divider); }\n+ .radar-list { max-height: 360px; }\n+}\n+\n+@media (max-width: 720px) {\n+ .utility-row { padding: 8px 12px; gap: 8px 12px; }\n+ .utility-date { flex-basis: 100%; }\n+ .utility-update { margin-left: 0; }\n+ .brand-row {\n+ padding: 9px 12px; gap: 12px;\n+ justify-content: space-between;\n+ }\n+ .brand-link { flex: 0 1 224px; min-width: 0; }\n+ .brand-logo { max-width: 224px; }\n+ .brand-name { font-size: 18px; }\n+ .brand-tagline { font-size: 9px; letter-spacing: .11em; white-space: nowrap; }\n+ .site-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n .ticker-label { padding: 7px 10px; font-size: 11px; letter-spacing: .08em; }\n .marquee-track { --ticker-duration: 130s; }\n .ticker-pass {\n@@ -83,10 +83,14 @@ def main() -> None:\n "China Airlines Adjusts Two Taoyuan-Fukuoka Flights After Airport Restrictions")\n assert len(en_short.split()) <= 14 and "…" not in en_short\n \n+ assert "@media (max-width: 900px)" in css\n assert "@media (max-width: 720px)" in css\n+ assert ".page { width: 100%; overflow-x: clip; }" in css\n+ assert "grid-template-columns: repeat(3, minmax(0, 1fr))" in css\n assert ".js .site-nav.is-open { display: grid; }" in css\n assert "grid-template-columns: repeat(2, minmax(0, 1fr))" in css\n assert ".center-col { order: 1;" in css\n+ assert ".radar-layout { grid-template-columns: minmax(0, 1fr); min-height: 0; }" in css\n assert '". . summary summary"' in css\n assert '"summary summary"' in css\n assert ".summary-preview--feed { grid-area: summary; margin-top: 7px; }" in css\n@@ -106,7 +110,7 @@ def main() -> None:\n assert ".marquee-track .ticker-pass:nth-child(2) { display: none; }" in css\n assert 'setAttribute("aria-expanded"' in script\n assert 'event.key === "Escape"' in script\n- assert 'matchMedia("(min-width: 721px)")' in script\n+ assert 'matchMedia("(min-width: 901px)")' in script\n assert 'matches ? 32 : 52' in script\n assert 'style.setProperty("--ticker-duration"' in script\n