From 5d1b535f820952c4f00794821c49a37d7e7d8ef6 Mon Sep 17 00:00:00 2001 From: Michal Vrba Date: Fri, 19 Dec 2025 15:49:40 +0100 Subject: [PATCH] Improve mobile responsiveness and accessibility Enhanced CSS for better mobile experience: added media queries for various screen sizes, improved touch targets, font sizes, and QR code scaling. Updated index.html with mobile meta tags and icons. Added accessibility features for reduced motion. --- QRPay/Pages/Home.razor.css | 274 ++++++++++++++++++++++++++++++++++++- QRPay/wwwroot/css/app.css | 112 ++++++++++++++- QRPay/wwwroot/index.html | 7 +- 3 files changed, 388 insertions(+), 5 deletions(-) diff --git a/QRPay/Pages/Home.razor.css b/QRPay/Pages/Home.razor.css index c75e3cf..e3b263f 100644 --- a/QRPay/Pages/Home.razor.css +++ b/QRPay/Pages/Home.razor.css @@ -45,6 +45,7 @@ -webkit-text-fill-color: transparent; background-clip: text; margin: 0 0 8px 0; + line-height: 1.2; } .qrpay-subtitle { @@ -52,6 +53,7 @@ font-size: 1.1rem; margin: 0; font-weight: 400; + line-height: 1.4; } /* Form Styles */ @@ -81,6 +83,8 @@ font-size: 1rem; transition: all 0.3s ease; background: #ffffff; + width: 100%; + box-sizing: border-box; } .form-control:focus { @@ -120,6 +124,8 @@ justify-content: center; gap: 8px; box-shadow: 0 4px 12px rgba(45, 90, 39, 0.3); + width: 100%; + min-height: 56px; } .btn-generate:hover:not(:disabled) { @@ -168,12 +174,14 @@ font-weight: 700; color: #2d5a27; margin: 0 0 8px 0; + line-height: 1.2; } .qrcode-header p { color: #6b7280; font-size: 1.1rem; margin: 0; + line-height: 1.4; } .qrcode-display { @@ -188,6 +196,9 @@ width: 280px; height: 280px; border-radius: 8px; + max-width: 100%; + height: auto; + aspect-ratio: 1; } /* Payment Details */ @@ -213,6 +224,7 @@ .detail-label { font-weight: 600; color: #374151; + white-space: nowrap; } .detail-value { @@ -239,6 +251,7 @@ justify-content: center; gap: 8px; width: 100%; + min-height: 56px; } .btn-back:hover { @@ -280,39 +293,145 @@ } } -/* Responsive Design */ +/* Enhanced Responsive Design */ + +/* Large tablets and small desktops */ +@media (max-width: 768px) { + .qrpay-container { + padding: 16px; + align-items: flex-start; + padding-top: 32px; + } + + .qrpay-card, + .qrcode-container { + padding: 32px; + border-radius: 20px; + } + + .qrpay-title { + font-size: 2.25rem; + } + + .qrcode-display img { + width: 260px; + height: 260px; + } + + .form-control { + font-size: 16px; /* Prevents zoom on iOS */ + } +} + +/* Portrait tablets and large phones */ @media (max-width: 640px) { + .qrpay-container { + padding: 12px; + min-height: auto; + padding-top: 20px; + padding-bottom: 20px; + } + .qrpay-card, .qrcode-container { padding: 24px; - margin: 16px; border-radius: 16px; + margin: 0; + } + + .qrpay-header { + margin-bottom: 32px; + } + + .qrpay-logo img { + width: 70px; + height: 70px; } .qrpay-title { font-size: 2rem; } + .qrpay-subtitle { + font-size: 1rem; + } + + .qrcode-header h2 { + font-size: 1.75rem; + } + + .qrcode-header p { + font-size: 1rem; + } + + .qrcode-display { + padding: 20px; + margin-bottom: 24px; + } + .qrcode-display img { width: 240px; height: 240px; } + .payment-details { + padding: 20px; + margin-bottom: 24px; + } + .detail-row { flex-direction: column; align-items: flex-start; gap: 4px; + padding: 16px 0; + } + + .detail-label { + font-size: 0.9rem; } .detail-value { max-width: 100%; text-align: left; + font-size: 0.95rem; + font-weight: 600; + } + + .form-group { + gap: 6px; + } + + .form-label { + font-size: 0.9rem; + } + + .btn-generate, + .btn-back { + padding: 16px 24px; + font-size: 1rem; } } +/* Mobile phones in portrait */ @media (max-width: 480px) { .qrpay-container { - padding: 12px; + padding: 8px; + padding-top: 16px; + padding-bottom: 16px; + } + + .qrpay-card, + .qrcode-container { + padding: 20px; + border-radius: 12px; + } + + .qrpay-header { + margin-bottom: 24px; + } + + .qrpay-logo { + margin-bottom: 16px; } .qrpay-logo img { @@ -324,8 +443,157 @@ font-size: 1.75rem; } + .qrpay-subtitle { + font-size: 0.95rem; + } + + .qrcode-header { + margin-bottom: 24px; + } + + .qrcode-header h2 { + font-size: 1.5rem; + } + + .qrcode-header p { + font-size: 0.95rem; + } + + .qrcode-display { + padding: 16px; + margin-bottom: 20px; + } + .qrcode-display img { width: 200px; height: 200px; } + + .payment-details { + padding: 16px; + margin-bottom: 20px; + } + + .detail-row { + padding: 12px 0; + } + + .qrpay-form { + gap: 20px; + } + + .form-control { + padding: 14px 16px; + font-size: 16px; + } + + .btn-generate, + .btn-back { + padding: 14px 20px; + min-height: 52px; + } +} + +/* Very small phones */ +@media (max-width: 360px) { + .qrpay-container { + padding: 4px; + padding-top: 12px; + padding-bottom: 12px; + } + + .qrpay-card, + .qrcode-container { + padding: 16px; + } + + .qrpay-title { + font-size: 1.5rem; + } + + .qrcode-display img { + width: 180px; + height: 180px; + } + + .form-control { + padding: 12px 14px; + } +} + +/* Landscape orientation adjustments */ +@media (max-height: 600px) and (orientation: landscape) { + .qrpay-container { + align-items: flex-start; + padding-top: 16px; + padding-bottom: 16px; + } + + .qrpay-header { + margin-bottom: 20px; + } + + .qrpay-logo img { + width: 50px; + height: 50px; + } + + .qrpay-title { + font-size: 1.5rem; + } + + .qrcode-header { + margin-bottom: 20px; + } + + .qrcode-display { + margin-bottom: 20px; + } + + .qrcode-display img { + width: 160px; + height: 160px; + } + + .payment-details { + margin-bottom: 20px; + } +} + +/* Touch improvements for mobile */ +@media (max-width: 768px) { + .btn-generate:hover, + .btn-back:hover { + transform: none; /* Disable hover transforms on mobile */ + } + + .form-control:focus { + transform: none; /* Disable focus transforms on mobile for better UX */ + } + + /* Larger touch targets */ + .btn-generate, + .btn-back { + min-height: 48px; /* WCAG recommended minimum touch target */ + } +} + +/* Accessibility improvements */ +@media (prefers-reduced-motion: reduce) { + .qrpay-card, + .qrcode-container { + animation: none; + } + + .validation-message { + animation: none; + } + + .spinner { + animation: none; + } + + * { + transition: none !important; + } } \ No newline at end of file diff --git a/QRPay/wwwroot/css/app.css b/QRPay/wwwroot/css/app.css index 75f9a93..b29d6f2 100644 --- a/QRPay/wwwroot/css/app.css +++ b/QRPay/wwwroot/css/app.css @@ -6,12 +6,25 @@ html, body { box-sizing: border-box; background: linear-gradient(135deg, #2d5a27 0%, #4a7c59 100%); min-height: 100vh; + /* Improve mobile performance */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + /* Prevent horizontal scrolling */ + overflow-x: hidden; + /* Better text rendering on mobile */ + text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; } *, *::before, *::after { box-sizing: inherit; } +/* Prevent zoom on input focus for iOS */ +input, select, textarea { + font-size: 16px; +} + h1:focus { outline: none; } @@ -84,6 +97,11 @@ a:hover, .btn-link:hover { font-size: 1.2rem; opacity: 0.8; transition: opacity 0.2s; + min-width: 24px; + min-height: 24px; + display: flex; + align-items: center; + justify-content: center; } #blazor-error-ui .dismiss:hover { @@ -91,7 +109,7 @@ a:hover, .btn-link:hover { } .blazor-error-boundary { - background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, linear-gradient(135deg, #dc2626, #ef4444); + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA9NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA6OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA86LjA1NDcgMjYzLjU3NiA4Ni4wNTQ3WiIgZmlsbD0iI0ZGRTUwMCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9nPjwvc3ZnPg==) no-repeat 1rem/1.8rem, linear-gradient(135deg, #dc2626, #ef4444); padding: 1rem 1rem 1rem 3.7rem; color: white; border-radius: 12px; @@ -175,4 +193,96 @@ code { ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.5); +} + +/* Mobile-specific improvements */ +@media (max-width: 768px) { + /* Improve tap highlighting */ + * { + -webkit-tap-highlight-color: rgba(74, 124, 89, 0.2); + } + + /* Better button touch targets */ + button, .btn, input[type="button"], input[type="submit"] { + min-height: 44px; + min-width: 44px; + } + + /* Improve form control touch targets */ + input, textarea, select { + min-height: 44px; + } + + /* Disable iOS zoom on inputs */ + input, textarea, select { + font-size: 16px !important; + } + + /* Loading progress adjustments for mobile */ + .loading-progress { + width: 6rem; + height: 6rem; + inset: 35vh 0 auto 0; + } + + .loading-progress-text { + inset: calc(35vh + 2.5rem) 0 auto 0.2rem; + font-size: 1rem; + } +} + +/* Very small screens */ +@media (max-width: 480px) { + body { + font-size: 14px; + } + + .loading-progress { + width: 5rem; + height: 5rem; + inset: 30vh 0 auto 0; + } + + .loading-progress-text { + inset: calc(30vh + 2rem) 0 auto 0.2rem; + font-size: 0.9rem; + } + + #blazor-error-ui { + padding: 0.75rem 1rem; + font-size: 0.9rem; + } +} + +/* Landscape mobile adjustments */ +@media (max-height: 600px) and (orientation: landscape) { + .loading-progress { + inset: 20vh 0 auto 0; + } + + .loading-progress-text { + inset: calc(20vh + 3.25rem) 0 auto 0.2rem; + } +} + +/* High DPI screens */ +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + /* Sharper rendering for high DPI */ + body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} + +/* Accessibility improvements */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .loading-progress circle { + transition: none !important; + } } \ No newline at end of file diff --git a/QRPay/wwwroot/index.html b/QRPay/wwwroot/index.html index 8330cc0..3fa5377 100644 --- a/QRPay/wwwroot/index.html +++ b/QRPay/wwwroot/index.html @@ -3,13 +3,18 @@ - + + + + + QRPay +