Guides · Updated
How CSS flexbox and grid map to Figma auto layout
A flex container becomes an auto layout frame: flex-direction sets the direction, gap and padding carry over, justify-content and align-items become alignment, and flex-grow, auto and fixed widths become Fill, Hug and Fixed. Margins, media queries and floats have no direct equivalent and need gaps, wrapper frames or separate frames per width.
Here is a card from almost any marketing site:
.card {
display: flex;
flex-direction: column;
gap: 16px;
padding: 24px;
align-items: flex-start;
width: 360px;
}
In Figma, the same card is a frame with vertical auto layout, 16 between items, 24 padding on all sides, children aligned left, and a fixed width of 360. The two systems were designed for the same job, so most of the mapping is direct. Figma’s auto layout is close to a subset of flexbox, and once you know where the subset ends, you can read any stylesheet as a set of Figma settings.
The container: direction, gap and padding
display: flex is the switch that turns a frame into an auto layout frame. flex-direction: row is horizontal auto layout and column is vertical. The -reverse variants have no setting of their own; in Figma you reverse the layer order instead.
gap maps straight onto the spacing between items. With wrapping on, Figma also has a separate gap between rows, which corresponds to row-gap. padding maps onto the frame’s padding, and Figma lets you set each side independently, just like padding-top and the rest.
Alignment
On the main axis, justify-content: flex-start, center and flex-end correspond to the alignment control in the auto layout panel. space-between is Figma’s Auto spacing: the gap is calculated so that the first and last children touch the edges.
space-around and space-evenly have no equivalent. To reproduce them you add padding to the container, or use Auto spacing with padding chosen to match the outer gaps.
On the cross axis, align-items: flex-start, center and flex-end are the same alignment control. stretch, which is the CSS default, has no alignment option because Figma models it on the child instead: each child set to Fill container on the cross axis stretches to the frame. baseline alignment exists for horizontal layouts with text.
Sizing children: Fill, Hug and Fixed
This is where people coming from CSS trip most often, because Figma names the result instead of the rule.
| CSS on the child | Figma sizing |
|---|---|
flex: 1 or flex-grow: 1 |
Fill container |
width: auto, fit-content, or content-sized |
Hug contents |
width: 240px |
Fixed, 240 |
align-self: stretch (cross axis) |
Fill container |
min-width / max-width |
Min and max width |
align-self: center |
No per-child option; wrap it in a frame |
Several children set to Fill share the space equally, like several flex: 1 siblings. Unequal ratios such as flex: 2 beside flex: 1 can’t be expressed. Use fixed widths, or nest frames to get the proportions.
Wrapping
flex-wrap: wrap corresponds to Figma’s Wrap option on horizontal auto layout. Children flow onto new rows when they run out of width, with the horizontal gap between items and the separate vertical gap between rows. It is the usual way to build tag lists, chip groups and simple card grids that reflow when the frame is resized.
Grid
CSS grid places children in explicit rows and columns, often with fractional tracks such as grid-template-columns: repeat(3, 1fr). Figma’s auto layout now has a grid flow next to horizontal and vertical. It has rows and columns, a gap for each direction, padding, and children that span several cells. Tracks set to fill share the space by fractional units, the same arithmetic as fr in CSS, and the row count can grow automatically as cells are added. One difference: grid children don’t wrap the way a wrapping flex row does, because each sits in its own cell.
For layouts the grid flow can’t express, the standard translation is nested auto layout: a vertical frame of rows, each row a horizontal frame whose children Fill the width.
Named grid areas, overlapping items and tracks sized by minmax() or content have no exact match. In those cases, keep the visual result and accept that resizing the frame won’t reflow it the way the browser does.
Things that sit outside the flow
position: absolute inside a flex container takes an element out of the flow while keeping it inside the parent. Figma has the same idea: a child of an auto layout frame can be set to absolute position, so it ignores the layout and keeps its coordinates. Badges, close buttons and decorative shapes usually belong here.
position: sticky and fixed describe behaviour during scrolling, which a static frame doesn’t have. In a design file they become ordinary layers at the position they had when captured. In a prototype, Figma can fix layers to the top or bottom while scrolling, which is the closest equivalent.
transform and negative margins move elements visually without changing layout in CSS. Figma has no such separation, so an imported element moved this way either keeps its position as an absolutely positioned child or shifts when auto layout is applied.
What has no equivalent
Margins. Figma has no margins. Space between siblings is the parent’s gap, and space around a single element needs a wrapper frame with padding. When the margins between siblings differ, CSS handles it easily and Figma needs either nested frames or a fixed spacer.
Media queries. A Figma frame has one size. Breakpoints become separate frames, one per width, and teams that need them to stay in sync use components with variants, or variables with modes for values that change between sizes.
Floats and inline flow. Text that wraps around an image, or a paragraph mixing links, bold words and inline icons, has no auto layout model. Inline text with mixed styles becomes one text layer with ranges of different styles; text wrapping around shapes has to be faked with separate text layers.
Calculated values. calc(), clamp() and percentages resolve to numbers in the browser. Figma stores the number for the size you captured, so a heading set with clamp(32px, 5vw, 64px) comes in at whatever size it had at that width.
Why this matters when you import
An importer that ignores all of this produces a pile of absolutely positioned boxes. They look right until you change a word, and then nothing moves. Figback reads the computed layout of each element and rebuilds it with the mappings above. Flex rows and columns become auto layout, wrapping rows keep their row gap, CSS grid becomes Figma’s grid flow with fixed, fill and hug tracks and the same spans, and absolutely positioned children keep their place with constraints taken from their CSS offsets. Fixed headers stay fixed when you scroll a prototype, and sticky elements get an annotation, since plugins can’t set sticky behaviour. If a layout can’t be rebuilt faithfully, that frame keeps absolute placement instead of a wrong auto layout. The imported card behaves like the card in the stylesheet: change the text and the card grows, remove an item and the rest close the gap.
The parts listed above as having no equivalent are where you should expect manual work after any import. Knowing them in advance lets you budget for that cleanup before the project starts.
Questions
What is the Figma equivalent of justify-content: space-between?
Set the spacing between items to Auto in the auto layout settings. Figma then pushes the first and last child to the edges and spreads the rest evenly, like space-between.
Does Figma have margins like CSS?
No. Space between siblings is the parent's gap, space inside a frame is its padding, and a one-off offset needs a wrapper frame with its own padding.
Waitlist
Get an email when Figback is live.
One message on launch day, with the link to the plugin. Tell us what you would import first, if you like.