feat(a11y,ux): implement comprehensive accessibility and UX optimizations
Phase 1: Accessibility Optimizations - Add proper label associations and ARIA attributes to form inputs - Implement aria-required, aria-invalid, aria-describedby for better form accessibility - Add role='alert' for error messages - Enhance keyboard navigation with aria-expanded, aria-controls - Add aria-label for mobile menu button - Implement aria-current for active navigation items - Add semantic HTML with aria-labelledby for sections Phase 2: UX Optimizations - Create loading skeleton components for better loading states - Add FormSkeleton, SectionSkeleton, and LoadingSkeleton components - Prepare for lazy loading implementation Files modified: - src/components/ui/input.tsx: Enhanced with ARIA attributes - src/components/ui/textarea.tsx: Enhanced with ARIA attributes - src/components/layout/header.tsx: Added navigation ARIA labels - src/components/sections/hero-section.tsx: Added section labels - src/components/sections/services-section.tsx: Added section labels - src/components/ui/loading-skeleton.tsx: New loading state components Impact: - WCAG 2.1 AA compliance improvements - Better screen reader support - Enhanced keyboard navigation - Improved user feedback during loading
This commit is contained in:
@@ -104,7 +104,7 @@ export function Header() {
|
||||
/>
|
||||
</a>
|
||||
|
||||
<nav className="hidden md:flex items-center gap-1">
|
||||
<nav className="hidden md:flex items-center gap-1" role="navigation" aria-label="主导航">
|
||||
{NAVIGATION.map((item) => (
|
||||
<a
|
||||
key={item.id}
|
||||
@@ -118,6 +118,7 @@ export function Header() {
|
||||
: 'text-[#3D3D3D] hover:text-[#1C1C1C]'
|
||||
}
|
||||
`}
|
||||
aria-current={activeSection === item.id.replace('#', '') ? 'page' : undefined}
|
||||
>
|
||||
{item.label}
|
||||
{activeSection === item.id.replace('#', '') && (
|
||||
@@ -148,6 +149,9 @@ export function Header() {
|
||||
<button
|
||||
className="md:hidden p-2 -mr-2 text-[#3D3D3D] hover:text-[#1C1C1C] transition-colors"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls="mobile-menu"
|
||||
aria-label={isOpen ? '关闭菜单' : '打开菜单'}
|
||||
>
|
||||
{isOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
|
||||
</button>
|
||||
@@ -173,6 +177,9 @@ export function Header() {
|
||||
exit={{ y: -20, opacity: 0 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||
className="absolute top-16 left-0 right-0 bg-white/95 backdrop-blur-xl border-b border-[#E2E8F0] shadow-lg"
|
||||
id="mobile-menu"
|
||||
role="navigation"
|
||||
aria-label="移动端导航"
|
||||
>
|
||||
<nav className="container-wide py-4">
|
||||
{NAVIGATION.map((item, index) => (
|
||||
|
||||
Reference in New Issue
Block a user