Skip to content
← All posts
3 min read

Fixing mobile scroll and interrupted motion on Ninan's Steakhouse

Stable hero sizing, interruptible controls, and menu links that land below sticky navigation.

A moving hero and stalled carousel led us into viewport units, animation state, and exact-commit deploy checks.

Ninan's Steakhouse has image carousels, a sticky menu rail, and expandable cut descriptions. A screenshot captures their layout, but misses what happens when someone taps an arrow again before the previous slide has finished moving.

That distinction drove our September UI pass. We worked on the site, and the review covered both desktop and mobile layouts. The reports were specific: the hero seemed to expand during a scroll, rapid carousel taps could stall the loop, and menu links could leave the destination hidden behind sticky navigation.

We changed the sizing and interaction logic behind those reports.

The hero had two moving parts

The Premium Cuts hero used dynamic viewport height, which can change as mobile browser controls retract. A cover image then fills a changing box, which can look like a zoom even without an image-scale animation.

We switched the height calculation to svh, the small viewport unit. MDN documents the tradeoff: it stays stable as browser controls retract, but does not expand to occupy the newly available space. That matched the requested behavior.

The homepage already used svh. Its copy still needed attention: viewport-based bottom padding and an upward entrance animation could move the text independently of the image. We changed the padding unit and removed that upward transform from the heading, description, and actions. Image crossfades stayed.

These are the sizing declarations from the separate hero rules, with selectors shortened. The homepage padding rule is mobile-only:

.cuts-hero {
  min-height: min(760px, calc(100svh - 70px));
}

.hero-copy {
  padding-bottom: clamp(8px, 1.8svh, 22px);
}

A second tap is valid input

Slowing the Premium Cuts accordion exposed a different problem. Opening now takes 1320ms, while closing still takes 320ms to dismiss the panel. During that interval, the native details.open value cannot describe both what is currently visible and what the visitor wants next.

Each card now tracks its desired state separately. When another tap arrives, the handler reads the current rendered height, cancels the old animation, and animates from that height toward the new target. The panels open independently. Reduced-motion users get an immediate state change.

Waiting for every animation to finish before accepting another tap would avoid some overlapping work. It would also make a 1320ms opening feel unresponsive. We kept interruption in the design instead.

The signature carousel needed its own answer: a pending target and loop normalization. Our checks include repeated taps in one direction, reversals, and crossing the loop boundary. One completed slide is insufficient evidence.

Check the destination after layout

The Premium Cuts links already named the correct menu fragments for the selected type of cut. The landing position needed fixing. A shared scroll helper now places the category heading 18px below the sticky navigation and category bar, including incoming links after image and font layout settles.

There was also a page-boundary mismatch. Scrolling beyond an oxblood footer could expose a differently colored document background. We applied #5d0b0e to the document background across all six shared-design pages, while leaving the cream content surfaces intact. Recoloring every section would have changed the design without addressing the actual boundary.

A preview is not a release

We checked layouts in the built-in browser and kept focused regression scripts for the carousel, location parallax, menu scrolling, and accordions. Desktop emulation does not verify physical iOS Safari toolbar movement or rubber-band overscroll. Those remain separate device checks.

For deployment, a successful HTTP response was not enough. We compared the serving build's commit with the intended Git commit before reporting the release as live, then recorded the interaction rules in the repository's UI maintenance notes.

The shipped pages are Ninan's Steakhouse, the menu, and Premium Cuts.

Client workFrontend engineeringMobile UXNinansSteakhouseGattyWorksBuildInPublicWebDevelopmentMobileUXFrontendDevelopmentCSSJavaScriptAccessibilityWebAnimation

Ready to know?

Send what you want checked or built. Fixed scope, price, and date in writing inside 24 hours, or the website or audit fee on your first project is refunded in full.

24 clock hours. Weekends included.
Book a call