One of my retainer clients runs a B2B SaaS site on Webflow with about thirty modal dialogs across the marketing pages, and every one of them used to flicker on first open. The cause was the standard CSS transition gotcha where the element starts in display:none, gets switched to display:block, and the transition has nothing to interpolate from because the from-state never existed in the layout tree. CSS @starting-style fixes that exact pattern. Firefox 145 added support in November 2025, completing Baseline coverage. This piece walks through the working pattern I use inside Webflow Custom Code embeds, where it complements Webflow's native interactions, and the one specificity gotcha that cost me an hour the first time I shipped it.
What Is CSS @starting-style and What Problem Does It Solve?
CSS @starting-style is an at-rule that defines the initial state an element should transition from when it first becomes part of the rendered tree. The browser uses the @starting-style values as the from-state for the transition, then animates to the element's current declared values as the to-state. Without @starting-style, the element has no from-state to transition from when it appears, so it snaps directly to its final state.
The classic case is opening a modal. The modal sits in display:none until a button is clicked, then jumps to display:block with opacity:1 and transform:translateY(0). A transition declaration on the modal cannot smooth that change because the modal had no rendered state to transition from. With @starting-style, the modal's appearing state is opacity:0 and transform:translateY(20px), and the transition smoothly animates to the final state on every open.
The pattern matters for any element that enters the layout tree through display, popover, or dialog state changes. Tooltips, dropdowns, drawers, and toast notifications all have the same shape.
What Does Browser Support Look Like in May 2026?
Firefox 145 added @starting-style support in November 2025, which closed the Baseline coverage that Chrome had since version 117 in September 2023 and Safari since 17.5 in May 2024. Caniuse data as of May 2026 puts global usage at roughly 90 percent. The remaining 10 percent is older browsers where the missing @starting-style produces graceful degradation, the modal simply appears without animation rather than breaking layout.
For most Webflow client sites the practical coverage is closer to 94 percent because the buyer-facing browser distribution skews newer than the global average. The right pattern for sites with strict tail support requirements is to wrap the @starting-style block inside an @supports check and keep a fallback that uses opacity:1 from the start. Both audiences get a usable modal. The supported audience gets the smooth animation. The fallback audience gets an instant appear that is functionally identical to the pre-2023 web.
How Do I Add @starting-style to a Webflow Modal Without Breaking the Designer?
The pattern that works inside Webflow is to design the modal in the Designer with the visible state as the default, add a Custom Code embed at page or site level, and write the @starting-style block in that embed scoped to the modal's class. The Designer renders the modal in its visible state during design time. The Custom Code adds the transition behavior that activates at publish time when the modal is shown.
The class naming convention I use is to keep the modal's main class normal in the Designer (.modal for instance) and add the @starting-style block in the embed. The transition rule lives on the .modal class itself. The browser combines the declared state, the transition, and the @starting-style into a working animation. Webflow's Designer does not yet expose @starting-style as a native control, so the pattern lives in Custom Code embeds for now. I covered the related Custom Code discipline in my CSS @scope piece from yesterday.
What Does the Working Modal Pattern Look Like in Practice?
The working modal pattern has four pieces. The base class declares the visible state with opacity:1 and transform:translateY(0). The @starting-style block declares the appearing state with opacity:0 and transform:translateY(20px). The transition rule declares which properties animate and the duration. A display transition allowance lets the modal animate when display switches from none to block.
The fourth piece is the one that catches most developers on first use. Browsers do not transition display by default. The transition-behavior:allow-discrete property tells the browser to delay the display change until the transition completes. Without that property the modal still snaps to display:block and the @starting-style rule never gets a chance to apply. The pattern is documented well in the W3C CSS Transitions Level 2 spec and in Bramus van Damme's January 2026 deep-dive on web.dev. Both are worth reading once.
How Does @starting-style Interact With the HTML Popover API?
The HTML Popover API and @starting-style are designed to work together, and the combination handles most modal needs without JavaScript. A button with popovertarget="my-modal" toggles the popover state on the target element. The target element with popover="auto" gets browser-managed open and close behavior. The @starting-style block on the popover element handles the entrance animation. A standard transition with allow-discrete handles the exit.
The combination is the cleanest pattern in modern CSS for accessible, animated modals. The browser handles focus management, escape-to-close, and click-outside-to-dismiss for free through the popover attribute. The animation is pure CSS. Webflow does not yet expose the popover attribute as a Designer control, but adding it through Custom Code or the Element Settings panel is straightforward. Adam Argyle's web.dev piece from October 2025 walks through the integration in detail. The pattern reduces a typical modal implementation from forty lines of JavaScript to roughly fifteen lines of CSS plus an attribute on the trigger button.
Where Does @starting-style Complement Webflow's Native Interactions?
Webflow Interactions handle most animation needs through a timeline-based UI that ships JavaScript at runtime. For triggered animations like scroll-triggered fades or hover state changes, Webflow Interactions are usually the right tool. The native UI is faster to build with and easier for non-developer collaborators to maintain. @starting-style complements Interactions for the specific class of animations that involve display state changes.
The split I use in client work is to handle scroll-triggered, hover, and timeline animations through Webflow Interactions, and to handle modal, popover, and dialog entrance animations through @starting-style in Custom Code. The two coexist cleanly because they target different animation triggers. The total JavaScript bundle drops because the modal animations no longer need their own runtime code. I covered the related Interactions discipline in my component-scoped Interactions tutorial.
What Is the One Specificity Gotcha That Catches Developers on First Use?
The gotcha is that @starting-style does not change CSS specificity rules. A more-specific selector elsewhere on the page can override the @starting-style values and prevent the transition from animating from the intended starting state. The fix is to make the @starting-style block at least as specific as any competing rule on the same element.
The case that cost me an hour the first time I shipped @starting-style was a global utility class on the modal that set opacity:1 with !important. The @starting-style block declared opacity:0, but the !important rule won the cascade resolution and the modal still snapped without animation. Removing the !important resolved the issue immediately. The general principle is to test the from-state with the browser DevTools open, watching the computed style during the appearance moment. If the computed opacity at frame zero is not what @starting-style declared, the cascade is overriding it. Bramus van Damme's piece flagged the same gotcha in passing. Most developers hit it once, fix it, and never see it again.
What About Performance and Animation Frame Cost?
@starting-style has no measurable performance penalty beyond the cost of the transition itself. The browser handles the from-state computation efficiently because it already needs to compute the to-state for layout. For typical Webflow modals with a few transformed properties, the rendering cost is identical to a conventional CSS animation. The Chrome DevTools Performance tab confirms this in profiling I ran in March 2026.
The performance question that still matters is the number of properties being animated and whether they are GPU-accelerated. Animating opacity and transform stays cheap. Animating width, height, top, or left forces a layout recomputation per frame and gets expensive fast. The decision rule is the same one that has applied to web animation since 2015. Animate transforms and opacity. Avoid animating layout properties. The pattern works the same with or without @starting-style.
What Should I Try This Week to See If @starting-style Fits My Practice?
Pick one Webflow client site with a modal that flickers on first open or snaps without animation. Add a single Custom Code embed with the four-line @starting-style pattern scoped to the modal's class. Test that the modal animates smoothly on open. The exercise takes about twenty minutes including a verification pass in Chrome, Safari, and Firefox.
If the animation works, the pattern scales cleanly to the rest of the site's display-state-change animations. Tooltips, dropdowns, drawers, and toast notifications all use the same shape. The Custom Code stays in one embed and the Designer continues to handle the visual design of each element. I prefer to validate new CSS primitives on real existing problems rather than greenfield ones, because the existing problems are what justified looking at the primitive in the first place. I covered the foundational discipline in my CSS Anchor Positioning tutorial.
If you are running a Webflow site with modals that flicker or snap and you want a second set of eyes on the @starting-style migration, drop me a line and tell me which page has the worst current behavior. Let's chat.
Get your website crafted professionally
Let's create a stunning website that drive great results for your business
Get in Touch
This form help clarify important questions in advance.
Please be as precise as possible as it will save our time.