The Problem

On iOS, when the software keyboard appears, elements styled with position: fixed— toolbars, send buttons, nav bars — float up into the middle of the screen rather than staying anchored to the bottom of the visible area.

Messages

Footer displaced above keyboard

Root Cause

iOS separates the layout viewport (what CSS sees and position: fixed is relative to) from the visual viewport (the actual visible area of the screen). When the software keyboard appears, the visual viewport shrinks, but the layout viewport does not change.

position: fixed elements are positioned relative to the layout viewport. So a footer withbottom: 0 stays at the bottom of the full-screen layout viewport — which is now mostly hidden behind the keyboard.

Fix 1 — position: sticky for in-flow footers

The simplest fix when the footer is part of a flex/grid column layout: use position: sticky instead of fixed. Sticky elements stay attached to their scroll container without the layout-viewport problem.

chat.css
.app-shell {
  display: flex;
  flex-direction: column;
  height: 100dvh; /* tracks actual visible height */
}

.messages-list {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.chat-footer {
  position: sticky;
  bottom: 0;
  flex-shrink: 0;
  background: #1a1a1a;
  padding: 0.75rem;
}

Fix 2 — Visual Viewport API (Full control)

For complex cases — full-screen apps, iframes, or elements that genuinely need position: fixed— use the Visual Viewport API to track the actual visible window and adjust manually.

viewport-fix.js
const footer = document.querySelector('.app-footer');

function repositionFooter() {
  const vv = window.visualViewport;
  if (!vv) return;

  // Offset by the amount the keyboard has consumed
  const keyboardHeight = window.innerHeight - vv.height;
  footer.style.transform = `translateY(-${keyboardHeight}px)`;
}

window.visualViewport?.addEventListener('resize', repositionFooter);
window.visualViewport?.addEventListener('scroll', repositionFooter);
Note: The Visual Viewport API is supported on iOS Safari 13+ and all modern browsers. Always check for window.visualViewport before using it.

Browser Support

BrowserMin VersionStatusNotes
Safari iOS (all)AllNot supportedposition:fixed breaks when keyboard opens; layout viewport not resized
Safari iOS 15.4+15.4+Partialdvh partially improves this; Visual Viewport API is the full fix
Chrome iOSAllNot supportedSame WebKit engine, same behaviour
Chrome AndroidAllSupportedKeyboard resize handled correctly
FirefoxAllSupportedKeyboard resize handled correctly

Further Reading