CSS to Figma Auto Layout: Flexbox and Grid Mapping Guide
How CSS to Figma Auto Layout mapping works: flex-direction, gap, padding, alignment, flex-grow, wrap, grid, absolute and max-width, plus tips for clean imports.
EUREKA! · · 10 min read
If you write front-end code, Figma's Auto Layout feels familiar: a direction, a gap, padding, alignment, children that hug or fill. It is tempting to assume CSS to Figma Auto Layout is a one-to-one translation. It isn't. Flexbox and Grid are richer, the browser resolves margins, percentages and intrinsic sizes that Auto Layout doesn't model, and the same visual result can come from very different CSS.
This guide explains how HTML to Frames maps CSS layouts onto Auto Layout, why every result is verified against the browser, where the limits are, and how to write CSS that imports cleanly.
The approach: geometry first, then inference
A naive converter reads display: flex and copies properties across. That breaks quickly: a flex container with gap: 0 and margins on children, a block element that only looks like a vertical stack, or a grid that renders as two neat rows.
HTML to Frames works from what the browser actually rendered:
- Build pixel-exact. The page is first built in Figma with absolute positions taken from the browser's measured geometry.
- Walk inside-out. Starting from the deepest frames, the plugin infers vertical stacks, horizontal stacks, wrapping rows, gaps, padding and alignment from positions and sizes.
- Add responsive meaning. Centred content becomes Center, max-width boxes stay centred, equal cards and
flex-growbecome Fill, and in a "logo … menu … icons" bar the gap item becomes Fill. - Verify. Auto Layout is applied, then every child's position is checked against the original, with a 2 px tolerance.
- Fall back safely. If it doesn't hold, a simpler plan is tried. If that also fails, the frame keeps absolute positions with sensible constraints (Stretch, Scale, Center, Min, Max).
Because inference starts from rendered geometry, a stack of block elements becomes a vertical Auto Layout just like a flex column does. The CSS mechanism matters less than the result. For a broader overview, see Auto Layout explained.
The mapping table
Here is how common CSS patterns typically map. Treat it as the expected result, not a promise; verification has the final say.
| CSS | Figma Auto Layout result | Notes |
|---|---|---|
flex-direction: column | Vertical Auto Layout | Normal block flow stacking also maps here |
flex-direction: row | Horizontal Auto Layout | |
row-reverse, column-reverse | Stack in the rendered order | Layers follow visual order |
gap: 24px | Item spacing 24 | Measured from actual distances |
| Equal margins between siblings | Item spacing | Inferred when distances are consistent |
padding: 32px 24px | Padding top/bottom 32, left/right 24 | Measured from child offsets |
justify-content: flex-start | Primary axis: start | |
justify-content: center | Primary axis: center | |
justify-content: flex-end | Primary axis: end | |
justify-content: space-between | Space between, or the gap item becomes Fill | Header bars often become logo, Fill, icons |
align-items: center | Counter axis: center | |
align-items: stretch | Children Fill on the counter axis | When children actually stretch |
flex: 1 / flex-grow: 1 | Fill container on the primary axis | Equal cards become equal Fill items |
Fixed width on a child | Fixed width | |
| Content-sized child | Hug contents | |
flex-wrap: wrap | Wrapping rows | Uses Auto Layout wrap |
display: grid with equal columns | Wrapping rows, or nested stacks | Depends on what verifies |
grid-template-columns with spans | Nested horizontal/vertical stacks | Or absolute if spans overlap |
max-width + margin: 0 auto | Centred box inside a full-width frame | Content box stays centred on resize |
position: absolute | Absolute within its frame, with constraints | Overlaps don't fit a stack |
position: fixed / sticky | Fixed or sticky behavior in Present mode | Headers keep working in prototypes |
z-index | Layer order | Matches browser stacking |
transform: rotate() / scale() | Rotation and scale applied | Skew and 3D not yet supported |
Flexbox in detail
Direction and order
flex-direction determines whether a container becomes a horizontal or vertical stack. Because inference uses rendered positions, reversed directions and order simply produce layers in visual order. What you see in the browser is what you get in the layers panel.
Gap and padding
gap is the cleanest input: a single, consistent distance between children that maps directly to Auto Layout item spacing. Margins between siblings work when they are consistent. When they are not, say 16, 24, 16, the plugin cannot represent that as one gap, and verification will either choose another plan or keep positions absolute.
Padding is measured from where children actually sit inside the container, so padding, border widths and inner margins all contribute to the result.
Justify and align
justify-content maps to primary-axis alignment and align-items to counter-axis alignment. The interesting case is space-between. In a header like "logo … menu … icons," the plugin turns the gap item into Fill, so on resize the logo stays left, the icons stay right and the middle stretches. That's the responsive meaning you'd expect, rather than a fixed spacing value that only works at one width.
flex-grow and Fill
Children with flex-grow or flex: 1 become Fill container. Rows of equal cards become equal Fill items, so resizing the parent frame resizes the cards together, just like in the browser.
Wrapping
flex-wrap: wrap maps to Auto Layout's wrap mode, producing wrapping rows. This is the natural fit for tag lists, logo walls and card grids built with flexbox.
CSS Grid in detail
Figma's Auto Layout is a stack model, not a two-dimensional grid. Grid layouts are therefore mapped to the closest structure that verifies:
- Uniform grids (equal columns, equal gaps) usually become wrapping rows.
- Asymmetric grids (a sidebar and main column, a 2:1 split) usually become nested stacks: a horizontal stack of vertical stacks, or the reverse.
- Spanning and overlapping cells that don't decompose into stacks keep absolute positions with constraints.
In every case, the visual result matches the browser within tolerance. What changes is how much of the frame you can resize fluidly in Figma.
Absolute positioning, centring and auto margins
position: absolute
An absolutely positioned badge, a decorative blob or an overlay doesn't belong in a stack, because it overlaps its siblings. Those elements keep absolute positions, and the plugin assigns constraints so they still behave sensibly when the parent is resized: a badge pinned top-right stays top-right, a full-cover overlay stretches.
max-width and margin: auto
The classic content container, max-width: 1200px; margin: 0 auto, becomes a centred box inside a full-width frame. This is also where Site width comes in: the plugin measures the page's real design width at import. Full-bleed designs come in at 1920 with the content box centred, truly boxed sites at their box width, and fluid sites at 1440. The measured value keeps your container logic intact.
Auto margins inside flex
margin-left: auto on a flex child pushes it to the end, a common pattern for nav bars. Like space-between, this is inferred from geometry, typically as a Fill gap item that keeps the pushed element at the far edge.
Why verification matters
Without verification, converters have two bad options: apply Auto Layout everywhere and accept that some frames shift, overlap or collapse, or avoid Auto Layout and hand you frozen absolute layers.
HTML to Frames applies Auto Layout, then checks every child's position within 2 px. If a frame fails, a simpler plan is tried; if that fails, the frame stays absolute. The design never breaks. You can trust that what you see in Figma matches the browser, and the Auto Layout you get is Auto Layout that actually holds.
The results screen shows the overall Auto Layout share, and for frames that stayed absolute it lists why (diagnostics). That turns "why isn't this Auto Layout?" into something you can act on in your CSS.
In our tests on real sites, Auto Layout was inferred on roughly 86 to 97 percent of frames, for example 93 percent on one product site and 88 percent on Linear and Stripe. Your numbers depend on how the CSS is written.
Limitations to know
- Two-dimensional grid semantics don't exist in Auto Layout; grids become wrapping rows or nested stacks, and complex spans may stay absolute.
- Inconsistent spacing between siblings can't be expressed as a single gap.
- Overlap (negative margins, absolute children) keeps those elements absolute.
- Skew and 3D transforms,
path()clip-paths, multi-layer masks and Display-P3 colors are not converted yet. - Embedded content such as iframes, WebGL canvases and videos without a poster comes in as a screenshot image of its box.
- One width at a time. Each screen is laid out at its own width. Use the responsive set (Desktop, Tablet, Mobile) to capture each breakpoint as a separate frame.
Tips: write CSS that imports cleanly
These habits make your layouts map to Auto Layout more often, and they're good CSS practice anyway.
- Use
gapinstead of sibling margins. One consistent value maps to item spacing directly. - Keep spacing consistent within a container. Mixed spacing forces fallbacks.
- Prefer flexbox for one-dimensional layouts. Navs, toolbars, button groups and card rows map directly.
- Use grid with equal tracks for card grids. Uniform columns become clean wrapping rows.
- Wrap asymmetric layouts in explicit containers. A sidebar and content area in their own flex row produces clear nested stacks.
- Use
flex: 1for elements that should stretch. It signals Fill. - Centre content with
max-widthandmargin: 0 auto. It becomes a centred box that stays centred. - Reserve
position: absolutefor true overlays. Don't use it for ordinary layout. - Avoid negative margins for layout. They create overlaps that can't be stacked.
- Name colors with custom properties. With Styles & variables (Pro),
--brand-primarybecomes abrand/primaryvariable. - Use real text. Text in images can't become editable text layers.
Seeing your own mapping
The quickest way to learn how your CSS maps is to import it. Paste code or upload a folder through the HTML to Figma flow, capture a local build with the Chrome extension, or have an AI tool send it over MCP. Then open the results screen, check the Auto Layout share and read the diagnostics for frames that stayed absolute.
Turn on Reference screenshot (Pro) to add a hidden, locked layer of the original page, so you can toggle between the import and the browser render. Turn on Detailed layers (Pro) when you want a more detailed layer structure.
For more on how pages become frames, read about HTML to frame conversion, and see features for everything the importer supports. The docs cover each import option in detail.
Frequently asked questions
- Does HTML to Frames read my CSS to create Auto Layout?
- It works from the browser's rendered geometry rather than copying CSS properties. The page is built pixel-exact first, then stacks, gaps, padding and alignment are inferred inside-out. Every child's position is verified within 2 px, so the result matches what the browser drew, whether the layout came from flexbox, grid or plain block flow.
- How is CSS Grid converted when Figma has no grid Auto Layout?
- Grids are mapped to the closest structure that verifies. Uniform grids with equal columns usually become wrapping rows, asymmetric layouts become nested horizontal and vertical stacks, and cells with complex spans or overlaps keep absolute positions with constraints. The visual result matches the browser either way.
- What happens when a frame can't become Auto Layout?
- A simpler layout plan is tried first. If that also fails verification, the frame keeps absolute positions and gets sensible constraints such as Stretch, Scale, Center, Min or Max, so it still behaves when resized. The results screen lists why each such frame stayed absolute, which helps you adjust your CSS.
- Does flex-grow become Fill container in Figma?
- Yes, in typical cases. Children that grow with flex-grow or flex: 1 become Fill container, and rows of equal cards become equal Fill items. In header bars with a logo, menu and icons spread apart, the gap item becomes Fill so the outer elements stay pinned to the edges when you resize the frame.
- How much of a page usually ends up in Auto Layout?
- In our tests on real sites, Auto Layout was inferred on roughly 86 to 97 percent of frames, for example 93 percent on one product site and 88 percent on Linear and Stripe. Results depend on how the CSS is written; consistent gaps, flexbox and explicit containers raise the share.
Stop redrawing the web.
Paste a link and get real, editable, responsive Figma layers in seconds. Free to start — 10 imports every month.