@@ -14,18 +14,54 @@ const searchResultsItems = document.getElementById("search-results__items");
1414let searchItemSelected = null ;
1515let resultsItemsIndex = - 1 ;
1616
17+ ////////////////////////////////////
18+ // Viewport Height Handler for Mobile
19+ ////////////////////////////////////
20+
21+ // Set CSS custom property for viewport height (for browsers without dvh support)
22+ function setViewportHeight ( ) {
23+ // Get the actual viewport height (excludes keyboard on mobile)
24+ const vh = window . visualViewport ? window . visualViewport . height * 0.01 : window . innerHeight * 0.01 ;
25+ document . documentElement . style . setProperty ( '--vh' , `${ vh } px` ) ;
26+ }
27+
28+ // Initialize and listen for viewport changes
29+ if ( window . visualViewport ) {
30+ setViewportHeight ( ) ;
31+ window . visualViewport . addEventListener ( 'resize' , setViewportHeight ) ;
32+ } else {
33+ // Fallback for browsers without visualViewport API
34+ setViewportHeight ( ) ;
35+ window . addEventListener ( 'resize' , setViewportHeight ) ;
36+ }
37+
1738////////////////////////////////////
1839// Modal Management
1940////////////////////////////////////
2041
2142function openSearchModal ( ) {
2243 searchModal . setAttribute ( "aria-hidden" , "false" ) ;
23- document . body . style . overflow = "hidden" ;
44+
45+ // Detect iOS devices
46+ const isIOS = / i P a d | i P h o n e | i P o d / . test ( navigator . userAgent ) && ! window . MSStream ;
47+
48+ if ( isIOS ) {
49+ // iOS-specific scroll lock (position: fixed approach)
50+ const scrollY = window . scrollY ;
51+ document . body . style . position = "fixed" ;
52+ document . body . style . top = `-${ scrollY } px` ;
53+ document . body . style . width = "100%" ;
54+ document . body . style . overflow = "hidden" ;
55+ document . body . setAttribute ( "data-scroll-y" , scrollY . toString ( ) ) ;
56+ } else {
57+ // Simple overflow: hidden for other browsers
58+ document . body . style . overflow = "hidden" ;
59+ }
2460
2561 // Focus the search input after a brief delay to ensure modal is visible
26- // Longer delay for mobile devices to ensure proper focus
62+ // Longer delay for iOS to account for position: fixed layout changes
2763 const isMobile = window . innerWidth <= 768 ;
28- const delay = isMobile ? 200 : 100 ;
64+ const delay = isIOS ? 300 : ( isMobile ? 200 : 100 ) ;
2965
3066 // On mobile, hide results when input is empty (input stays visible)
3167 if ( isMobile && searchResults ) {
@@ -38,12 +74,39 @@ function openSearchModal() {
3874 if ( isMobile ) {
3975 searchInput . click ( ) ;
4076 }
77+
78+ // iOS sometimes needs an additional nudge
79+ if ( isIOS ) {
80+ setTimeout ( ( ) => {
81+ searchInput . focus ( ) ;
82+ searchInput . click ( ) ;
83+ } , 50 ) ;
84+ }
4185 } , delay ) ;
4286}
4387
4488function closeSearchModal ( ) {
4589 searchModal . setAttribute ( "aria-hidden" , "true" ) ;
46- document . body . style . overflow = "" ;
90+
91+ const isIOS = / i P a d | i P h o n e | i P o d / . test ( navigator . userAgent ) && ! window . MSStream ;
92+
93+ if ( isIOS ) {
94+ // iOS-specific: restore scroll position
95+ const scrollY = document . body . getAttribute ( "data-scroll-y" ) ;
96+ document . body . style . position = "" ;
97+ document . body . style . top = "" ;
98+ document . body . style . width = "" ;
99+ document . body . style . overflow = "" ;
100+ document . body . removeAttribute ( "data-scroll-y" ) ;
101+
102+ if ( scrollY ) {
103+ window . scrollTo ( 0 , parseInt ( scrollY ) ) ;
104+ }
105+ } else {
106+ // Simple overflow restore for other browsers
107+ document . body . style . overflow = "" ;
108+ }
109+
47110 searchInput . value = "" ;
48111 searchResults . style . display = "none" ;
49112 searchItemSelected = null ;
0 commit comments