diff --git a/src/components/Lightbox/Lightbox.web.tsx b/src/components/Lightbox/Lightbox.web.tsx
index 8883bfb5e5..0222aa3156 100644
--- a/src/components/Lightbox/Lightbox.web.tsx
+++ b/src/components/Lightbox/Lightbox.web.tsx
@@ -1,5 +1,5 @@
import {useCallback, useEffect, useRef, useState} from 'react'
-import {Pressable, StyleSheet, View} from 'react-native'
+import {Pressable, ScrollView, StyleSheet, View} from 'react-native'
import {Image} from 'expo-image'
import {Trans, useLingui} from '@lingui/react/macro'
import {FocusGuards, FocusScope} from 'radix-ui/internal'
@@ -226,17 +226,21 @@ function LightboxGallery({
)}
{img.alt ? (
-
+ ]}
+ scrollEnabled={isAltExpanded}
+ contentContainerStyle={[a.px_4xl, a.py_2xl]}>
-
+
) : null}
{imgs.length > 1 && (
@@ -449,6 +453,14 @@ const styles = StyleSheet.create({
padding: 16,
boxSizing: 'border-box',
},
+ altScroll: {
+ // Size to content like the View it replaced, rather than filling the
+ // column via ScrollView's default flexGrow.
+ flexGrow: 0,
+ flexShrink: 0,
+ // @ts-ignore web-only -sfn
+ maxHeight: '50vh',
+ },
menuBtn: {
top: 20,
left: 20,
diff --git a/src/components/Lightbox/chrome/Footer.tsx b/src/components/Lightbox/chrome/Footer.tsx
index a20c80df3d..0a708c7545 100644
--- a/src/components/Lightbox/chrome/Footer.tsx
+++ b/src/components/Lightbox/chrome/Footer.tsx
@@ -1,6 +1,9 @@
import {useRef} from 'react'
import {LayoutAnimation, ScrollView, StyleSheet, View} from 'react-native'
-import {useSafeAreaInsets} from 'react-native-safe-area-context'
+import {
+ useSafeAreaFrame,
+ useSafeAreaInsets,
+} from 'react-native-safe-area-context'
import {BlurView} from 'expo-blur'
import {useLingui} from '@lingui/react/macro'
@@ -17,10 +20,16 @@ export function Footer({altText, isAltExpanded, onToggleAltExpanded}: Props) {
const {t: l} = useLingui()
const t = useTheme()
const insets = useSafeAreaInsets()
+ const {height: screenHeight} = useSafeAreaFrame()
const isMomentumScrolling = useRef(false)
if (!altText) return null
+ // Cap the overlay height so long alt text - or text enlarged by the OS via
+ // Dynamic Type / font scaling - scrolls within the overlay instead of growing
+ // past the top of the screen. Leaves the upper half clear for the header.
+ const maxHeight = screenHeight / 2
+
return (
{
isMomentumScrolling.current = true