Layout: flow, flex and grid
Layout decides where each box goes: below the previous one, beside it, over it, or in a cell of a grid. In Salam you write the same CSS properties as plain names, and the compiler turns them into a stylesheet. This lesson goes from the normal flow to flexbox and grid and shows each idea with a page you can run.
- Normal flow
- Position and the offsets
- Sticky and fixed
- Stacking and z index
- Float and clear
- Flexbox: items in a line
- How flex items get their size
- Flexbox recipes
- Grid: rows and columns together
- Placing items: lines, spans and areas
- Alignment in flex and grid
- Multi-column text
- Right-to-left pages
- Reference: every layout property
- Try it yourself
Normal flow
If you set nothing, the browser lays boxes out in the normal flow. A block box, such as a box or a paragraph, takes the full width of its parent and starts on a new line. An inline box, such as a span or a link, stays inside the line of text and is only as wide as its content. Width and height do not apply to inline boxes. display = "inline-block" is the middle way: it sits in the line like a word, but it has a width, a height and vertical margins like a block.
page:
title = "Normal flow"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box: background = "#dbeafe" padding = 10 margin bottom = 8 content = "Block one takes the full width." end
box: background = "#bfdbfe" padding = 10 margin bottom = 8 content = "Block two starts on a new line." end
paragraph:
content = "Inline items stay in the line: "
span: background = "#fde68a" padding = "2 6" content = "one" end
span: background = "#fcd34d" padding = "2 6" content = "two" end
span: background = "#fbbf24" padding = "2 6" content = "three" end
end
box: display = "inline-block" width = 120 height = 50 background = "#bbf7d0" margin = 4 content = "inline-block" end
box: display = "inline-block" width = 120 height = 50 background = "#86efac" margin = 4 content = "inline-block" end
endEverything else in this lesson changes how boxes leave this flow. Most of the time you do not take boxes out of it. You set display = flex or display = grid on a parent, and the parent arranges its children.
Two things in the examples are worth knowing. global: box sizing = "border-box" makes width include padding and border, which is easier to reason about. And a bare number such as padding = 10 means pixels; for another unit write a string, like "2rem" or "50%".
Position and the offsets
position chooses how a box is placed, and top, right, bottom and left (or the shorthand inset) say how far from which edge. The default is static: normal flow, and the offsets do nothing.
relative: the box keeps its place and its space in the flow, and is then drawn shifted by the offsets. The other boxes do not notice.absolute: the box leaves the flow completely. It is placed against the nearest ancestor that is itself positioned (anything butstatic), or against the page if there is none.fixed: like absolute, but against the window, so it stays in place while the page scrolls. Use it for a bar that must always be visible.sticky: normal flow until the box would scroll past its offset, then it sticks there until its parent ends.
The usual pattern is a relative parent with absolute children: the parent is only there to be the reference. Below, the card is the reference for the badge and the bottom strip.
page:
title = "Relative and absolute"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
position = relative width = 280 height = 150 background = "#e0f2fe" border = "2px solid #0284c7"
paragraph: margin = 12 margin inline end = 70 content = "The card is the positioned parent." end
box: position = absolute top = 10 inset inline end = 10 background = "#dc2626" color = "white" padding = "4 10" border radius = 12 content = "New" end
box: position = absolute bottom = 0 left = 0 right = 0 background = "#0369a1" color = "white" padding = 8 content = "Pinned to the bottom edge" end
end
paragraph: content = "Text after the card is not pushed by the absolute boxes." end
endAn absolute box with no positioned ancestor is placed against the whole page, which is rarely what you want. If a badge flies off to a corner of the window, give its parent position = relative.
Try the three values yourself. The blue box has top = 30 and an offset from the start side. While it is static the offsets are ignored. With relative it moves but its space stays, so the green box does not move up. With absolute it leaves the flow: the green box moves up to take its place, and the blue box is measured from the dashed container.
import dom
page:
title = "Try every position"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 16 end
box:
display = flex gap = 8 margin bottom = 12
button: click = (): dom.SetStyle(dom.ById("target"), "position", "static") end content = "static" end
button: click = (): dom.SetStyle(dom.ById("target"), "position", "relative") end content = "relative" end
button: click = (): dom.SetStyle(dom.ById("target"), "position", "absolute") end content = "absolute" end
end
box:
position = relative height = 150 background = "#f1f5f9" border = "2px dashed #94a3b8" padding = 8
box: background = "#fca5a5" width = 90 height = 36 content = "first" end
box: id = "target" top = 30 inset inline start = 120 background = "#2563eb" color = "white" width = 90 height = 36 content = "target" end
box: background = "#86efac" width = 90 height = 36 content = "third" end
end
endThe offsets come in two families. top, right, bottom and left are physical: right is always the right of the screen. inset inline start, inset inline end, inset block start and inset block end are logical: they follow the writing direction, so the start is the left in English and the right in Persian. The two-value forms inset inline and inset block set both ends. Prefer the logical ones for anything that is about reading order, such as the badge above.
Sticky and fixed
A sticky box needs an offset to know where to stick, usually top = 0. It sticks inside the nearest scrolling ancestor, and it can never leave its own parent, so a sticky heading is pushed away when the next section arrives. The box has a fixed height and overflow = auto, so it scrolls by itself. Scroll it: each heading stays at the top until the next one takes over.
page:
title = "Sticky headings"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 16 end
box:
height = 220 overflow = auto border = "2px solid #94a3b8"
heading: size = 3 position = sticky top = 0 margin = 0 padding = 8 background = "#fde68a" content = "Fruit" end
paragraph: padding = 8 content = "Apples, pears and plums. Scroll this box and watch the heading stay at the top." end
paragraph: padding = 8 content = "Cherries and apricots in early summer." end
paragraph: padding = 8 content = "Quinces and medlars in the autumn." end
heading: size = 3 position = sticky top = 0 margin = 0 padding = 8 background = "#bbf7d0" content = "Vegetables" end
paragraph: padding = 8 content = "Carrots, leeks and beetroot keep well in a cool cellar." end
paragraph: padding = 8 content = "Spinach and lettuce grow fast but do not last." end
paragraph: padding = 8 content = "Potatoes and onions can be stored for months." end
end
endfixed works like this too, but against the window and without the parent limit. Give a fixed bar top = 0 left = 0 right = 0 and it spans the window. Because it leaves the flow, the content below it starts under the bar, so add the bar's height as padding at the top of the page.
Stacking and z index
When positioned boxes overlap, the one that comes later in the code is drawn on top. z index changes that: a bigger whole number is drawn above a smaller one, and a negative number goes behind. It applies to positioned boxes and to flex and grid items.
page:
title = "Stacking order"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
position = relative height = 180
box: position = absolute top = 60 left = 120 width = 150 height = 110 background = "#86efac" z index = 3 padding = 8 font size = 28 content = "3" end
box: position = absolute top = 0 left = 0 width = 150 height = 110 background = "#fca5a5" z index = 1 padding = 8 font size = 28 content = "1" end
box: position = absolute top = 30 left = 60 width = 150 height = 110 background = "#93c5fd" z index = 2 padding = 8 font size = 28 content = "2" end
end
paragraph: content = "The box with the biggest z index is painted on top, whatever the order in the code." end
endA few boxes create their own stacking context, a group that is ordered as one block: a positioned box with a z index, an element with opacity below 1, or one with a transform. Inside a context the numbers only compete with each other. This is why a menu with z index = 9999 can still hide behind a box that has z index = 2: they are in different contexts. When a number seems to do nothing, look for a parent that made a context.
Float and clear
A floated box leaves the line and moves to one side, and the text that follows wraps around it. That is its job today: a picture or a pull quote inside text. Pages were once built with floats, but flexbox and grid replaced that. clear makes a box start below the floats instead of beside them. The value inline-start follows the text direction, so the example works in both languages.
page:
title = "Text wrapping around a box"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 max width = 480 line height = 1.5 end
box: float = inline-start width = 110 height = 90 margin = "4 0 6" margin inline end = 14 background = "#fcd34d" padding = 8 content = "Floated" end
paragraph: content = "A floated box leaves the normal flow on one side, and the lines of text that follow flow around it. This is how a picture sits inside a paragraph in a magazine. Keep going until the text is longer than the box and it wraps underneath." end
box: clear = both background = "#e2e8f0" padding = 8 content = "clear = both: this box starts below the float." end
endA float is ignored on a flex or grid item. If the parent of a float is shorter than the float, the parent does not grow to hold it. Put a clear = both element after it, or make the parent display = "flow-root".
Flexbox: items in a line
Set display = flex on a parent and its children become flex items, laid out along one line called the main axis. The other direction is the cross axis. flex direction chooses the main axis: row (the default, along the text direction), column, or their -reverse forms. Two properties place the items:
justify contentspreads the items along the main axis:flex-start,flex-end,center,space-between,space-around,space-evenly.align itemsplaces them across the cross axis:stretch(the default, so items are as tall as the line),flex-start,flex-end,center,baseline.
Together they give the shortest way to center a box, both ways:
page:
title = "Centering"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
display = flex justify content = center align items = center height = 180 background = "#ede9fe" border radius = 12
box: background = "#7c3aed" color = "white" padding = "14 26" border radius = 8 content = "Centered both ways" end
end
endThe playground below changes the two properties and the direction with buttons. Notice how the meaning of justify and align swaps when you choose column: justify is always the main axis, whichever way it points.
import dom
page:
title = "Flex playground"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 16 end
box:
display = flex flex wrap = wrap gap = 6 margin bottom = 12
button: click = (): dom.SetStyle(dom.ById("row"), "flex-direction", "row") end content = "row" end
button: click = (): dom.SetStyle(dom.ById("row"), "flex-direction", "column") end content = "column" end
button: click = (): dom.SetStyle(dom.ById("row"), "justify-content", "flex-start") end content = "start" end
button: click = (): dom.SetStyle(dom.ById("row"), "justify-content", "center") end content = "center" end
button: click = (): dom.SetStyle(dom.ById("row"), "justify-content", "space-between") end content = "space-between" end
button: click = (): dom.SetStyle(dom.ById("row"), "align-items", "flex-start") end content = "items start" end
button: click = (): dom.SetStyle(dom.ById("row"), "align-items", "center") end content = "items center" end
button: click = (): dom.SetStyle(dom.ById("row"), "align-items", "flex-end") end content = "items end" end
end
box:
id = "row" display = flex align items = flex-start gap = 8 height = 170 background = "#f1f5f9" border = "2px solid #94a3b8" padding = 8
box: background = "#f87171" padding = 10 content = "1" end
box: background = "#60a5fa" padding = "20 10" content = "2" end
box: background = "#4ade80" padding = "30 10" content = "3" end
end
endgap puts space between items without margins on the items. One value is used both ways, two values are the row gap then the column gap. row gap and column gap set them one at a time. flex wrap = wrap lets items move to a new line when they do not fit, and flex flow sets direction and wrap together, as in "row wrap". When there is more than one line, align content distributes the lines in the container.
How flex items get their size
Each flex item starts from its flex basis (its width in a row, when the basis is auto), then the free space is shared out. flex grow says how many shares of the extra space the item takes, and flex shrink how much of a shortage it absorbs when the items do not fit. The shorthand flex sets all three: flex = 1 means "grow equally, starting from nothing", and flex = "0 0 120px" is a fixed 120 pixel item. Prefer the shorthand, because it resets the parts you did not write to sensible values.
page:
title = "Grow, shrink and basis"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
paragraph: margin = "0 0 6" content = "flex grow 1, 2 and 1" end
box:
display = flex gap = 8 margin bottom = 16
box: flex grow = 1 background = "#fca5a5" padding = 10 content = "1" end
box: flex grow = 2 background = "#93c5fd" padding = 10 content = "2" end
box: flex grow = 1 background = "#86efac" padding = 10 content = "1" end
end
paragraph: margin = "0 0 6" content = "fixed 120 pixel box, then flex = 1" end
box:
display = flex gap = 8
box: flex = "0 0 120px" background = "#fcd34d" padding = 10 content = "fixed" end
box: flex = 1 background = "#c4b5fd" padding = 10 content = "takes the rest" end
end
endTwo properties work on a single item. align self overrides align items for that item. order changes where it is drawn: items are sorted by their order number, the lowest first, and items with equal numbers stay in code order.
page:
title = "Order and align self"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
display = flex gap = 8 height = 130 background = "#f1f5f9" align items = flex-start padding = 8
box: order = 3 background = "#fca5a5" padding = 12 content = "order 3" end
box: order = 1 background = "#93c5fd" padding = 12 content = "order 1" end
box: order = 2 align self = flex-end background = "#86efac" padding = 12 content = "order 2, self end" end
box: align self = center background = "#fcd34d" padding = 12 content = "self center" end
end
endorder only changes what people see. Screen readers and the Tab key still follow the order of the code. Use it for small visual adjustments and write the content in its real reading order.
Flexbox recipes
Four layouts you will write again and again. A navigation bar: a flex row, and an auto margin on the end of the first item that pushes the rest away. The auto margin takes all the free space, and margin inline end follows the text direction.
page:
title = "Navigation bar"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 0 end
nav:
display = flex align items = center gap = 20 background = "#0f172a" color = "white" padding = "0 20" height = 56
span: font weight = 700 font size = 18 margin inline end = auto content = "Bakery" end
link: url = "#" color = "white" content = "Bread" end
link: url = "#" color = "white" content = "Cakes" end
link: url = "#" color = "white" content = "Contact" end
button: background = "#f59e0b" border = "none" padding = "8 14" border radius = 6 content = "Order" end
end
paragraph: padding = 20 content = "The auto margin on the name takes all the free space, so everything after it moves to the end." end
endA sidebar with content: the sidebar has a fixed basis and does not grow, the content takes whatever is left.
page:
title = "Sidebar and content"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 0 end
box:
display = flex min height = 260
aside: flex = "0 0 160px" background = "#1e293b" color = "white" padding = 16
heading: size = 3 margin = "0 0 8" content = "Menu" end
paragraph: content = "Inbox" end
paragraph: content = "Sent" end
paragraph: content = "Drafts" end
end
main: flex = 1 padding = 20 background = "#f8fafc"
heading: size = 2 margin = "0 0 8" content = "Inbox" end
paragraph: content = "The sidebar keeps 160 pixels. The content takes the rest and grows or shrinks with the window." end
end
end
endCards that wrap: every card has flex = "1 1 160px", which says "I would like 160 pixels, but I will grow and shrink". On a wide screen five cards fit in a line, on a phone one per line, with no media query. The last line stretches; if you prefer it not to, use grid below.
page:
title = "Cards that wrap"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
display = flex flex wrap = wrap gap = 12
box: flex = "1 1 160px" background = "#fecaca" padding = 16 border radius = 8 content = "Card one" end
box: flex = "1 1 160px" background = "#fed7aa" padding = 16 border radius = 8 content = "Card two" end
box: flex = "1 1 160px" background = "#fde68a" padding = 16 border radius = 8 content = "Card three" end
box: flex = "1 1 160px" background = "#bbf7d0" padding = 16 border radius = 8 content = "Card four" end
box: flex = "1 1 160px" background = "#bae6fd" padding = 16 border radius = 8 content = "Card five" end
end
endA footer at the bottom of a short page: the page is a column with at least the window's height, and the main part grows to fill it.
page:
title = "Sticky footer"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 0 end
box:
display = flex flex direction = column min height = "100vh"
header: background = "#0f766e" color = "white" padding = 14 content = "Header" end
main: flex = 1 padding = 16 content = "The page is short, yet the footer stays at the bottom." end
footer: background = "#134e4a" color = "white" padding = 14 content = "Footer" end
end
endGrid: rows and columns together
Flexbox lays out one line at a time. Grid lays out both directions at once. Set display = grid and describe the columns with grid template columns, with one size for each column. Sizes can be lengths, percentages, auto, and the unit fr, a fraction of the free space: "1fr 2fr" makes the second column twice as wide as the first. repeat(3, 1fr) is three equal columns. Rows are made as needed, and grid template rows and grid auto rows size them. gap, row gap and column gap work as in flexbox.
page:
title = "Grid columns"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
display = grid grid template columns = "100px 1fr 2fr" grid auto rows = 60 gap = 10
box: background = "#fca5a5" padding = 8 content = "100px" end
box: background = "#fcd34d" padding = 8 content = "1fr" end
box: background = "#86efac" padding = 8 content = "2fr" end
box: background = "#93c5fd" padding = 8 content = "4" end
box: background = "#c4b5fd" padding = 8 content = "5" end
box: background = "#f9a8d4" padding = 8 content = "6" end
end
endChange the columns in the next page and watch the same five boxes rearrange. The last button is the most useful grid line you will learn:
import dom
page:
title = "Change the columns"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 16 end
box:
display = flex flex wrap = wrap gap = 6 margin bottom = 10
button: click = (): dom.SetStyle(dom.ById("grid"), "grid-template-columns", "1fr 1fr 1fr") dom.SetText(dom.ById("code"), "1fr 1fr 1fr") end content = "three equal" end
button: click = (): dom.SetStyle(dom.ById("grid"), "grid-template-columns", "1fr 3fr") dom.SetText(dom.ById("code"), "1fr 3fr") end content = "1fr 3fr" end
button: click = (): dom.SetStyle(dom.ById("grid"), "grid-template-columns", "80px 1fr 80px") dom.SetText(dom.ById("code"), "80px 1fr 80px") end content = "fixed sides" end
button: click = (): dom.SetStyle(dom.ById("grid"), "grid-template-columns", "repeat(auto-fit, minmax(90px, 1fr))") dom.SetText(dom.ById("code"), "repeat(auto-fit, minmax(90px, 1fr))") end content = "auto-fit" end
end
paragraph: id = "code" font family = monospace margin = "0 0 10" content = "1fr 1fr 1fr" end
box:
id = "grid" display = grid grid template columns = "1fr 1fr 1fr" gap = 8
box: background = "#fca5a5" padding = 14 content = "A" end
box: background = "#93c5fd" padding = 14 content = "B" end
box: background = "#86efac" padding = 14 content = "C" end
box: background = "#fcd34d" padding = 14 content = "D" end
box: background = "#c4b5fd" padding = 14 content = "E" end
end
endrepeat(auto-fit, minmax(90px, 1fr)) reads "make as many columns as fit, each at least 90 pixels, and share the leftover space". minmax(a, b) gives a size between two limits. With auto-fit the empty columns shrink to nothing, so the real ones stretch. With auto-fill they stay and keep their width. A card grid built this way adapts to every screen with no media queries:
page:
title = "Responsive card grid"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
display = grid grid template columns = "repeat(auto-fit, minmax(140px, 1fr))" gap = 12
box: background = "#fecaca" padding = 24 border radius = 8 content = "One" end
box: background = "#fed7aa" padding = 24 border radius = 8 content = "Two" end
box: background = "#fde68a" padding = 24 border radius = 8 content = "Three" end
box: background = "#bbf7d0" padding = 24 border radius = 8 content = "Four" end
box: background = "#bae6fd" padding = 24 border radius = 8 content = "Five" end
box: background = "#ddd6fe" padding = 24 border radius = 8 content = "Six" end
end
endPlacing items: lines, spans and areas
Grid lines are numbered from 1: a grid with three columns has four vertical lines, and -1 is the last one. grid column and grid row place an item between two lines: "1 / 3" is from line 1 to line 3, which is two columns, and "span 2" means two tracks wide from wherever the item lands. grid column start, grid column end, grid row start and grid row end set the ends one by one. When items of different sizes leave holes, grid auto flow = "row dense" back-fills them, at the price of an order that no longer matches the code.
page:
title = "Spanning cells"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
display = grid grid template columns = "repeat(4, 1fr)" grid auto rows = 56 gap = 8
box: grid column = "1 / 3" background = "#fca5a5" padding = 8 content = "columns 1 to 2" end
box: grid row = "span 2" background = "#93c5fd" padding = 8 content = "two rows" end
box: grid column start = 4 background = "#86efac" padding = 8 content = "column 4" end
box: background = "#fcd34d" padding = 8 content = "auto" end
box: grid column = "span 2" background = "#c4b5fd" padding = 8 content = "span 2" end
box: background = "#f9a8d4" padding = 8 content = "auto" end
end
endFor a whole page, name the cells instead. grid template areas takes one string that draws the layout, one quoted name for each cell of each row; repeating a name merges cells. Then every child says where it goes with grid area. In Salam the string goes in backticks, on a single line, so the quotes inside need no escaping.
page:
title = "Page with named areas"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 0 end
box:
display = grid grid template columns = "150px 1fr" grid template rows = "50px 1fr 40px" grid template areas = `"top top" "side main" "foot foot"` gap = 6 height = 280 padding = 6
header: grid area = top background = "#0f766e" color = "white" padding = 12 content = "top" end
aside: grid area = side background = "#99f6e4" padding = 12 content = "side" end
main: grid area = main background = "#ccfbf1" padding = 12 content = "main" end
footer: grid area = foot background = "#134e4a" color = "white" padding = 10 content = "foot" end
end
endgrid template is the shorthand for rows, columns and areas together: `"top top" 50px "side main" 1fr / 150px 1fr`. The areas and the row sizes are written together, then a slash, then the column sizes. grid is the longest shorthand; it also sets the automatic tracks and the flow, as in "auto-flow 60px / 1fr 2fr". Beginners do well with the long names; the shorthands are for reading other people's code.
Notice that the page layout above needs no wrapper boxes and no floats, and that moving the sidebar to the other side means editing one string.
Alignment in flex and grid
The same few words appear everywhere, and a rule makes them easy: justify works along the inline axis (the way text runs), align along the block axis (the way paragraphs stack), content positions the whole set of tracks or lines inside the container, items aligns all the items inside their cells, and self does that for one item. place sets align and justify together. In flexbox justify always means the main axis and align the cross axis, and justify items and justify self do not apply to flex items.
The values are start, end, center, stretch and, for content, the three space- forms. The word end also closes an element in Salam, so write "end" in quotes when it is a value. The page below shows items inside grid cells, with place items on the container and a different alignment on some items.
page:
title = "Aligning inside cells"
global: box sizing = "border-box" end
global: selector = "body" font family = "system-ui, sans-serif" margin = 20 end
box:
display = grid grid template columns = "repeat(3, 1fr)" grid auto rows = 90 gap = 8 place items = center border = "2px dashed #94a3b8" padding = 8
box: background = "#fca5a5" padding = 8 content = "center" end
box: justify self = start background = "#93c5fd" padding = 8 content = "start" end
box: justify self = "end" background = "#86efac" padding = 8 content = "end" end
box: align self = start background = "#fcd34d" padding = 8 content = "top" end
box: align self = stretch justify self = stretch background = "#c4b5fd" padding = 8 content = "stretch" end
box: place self = "end" background = "#f9a8d4" padding = 8 content = "place self" end
end
endMulti-column text
A long paragraph is hard to read when the lines are very wide. columns splits the content of a box into newspaper columns that fill one after the other. Set column count for a fixed number, or column width for an ideal width and let the browser decide how many fit. columns = "10rem 3" says both: at least 10rem wide, at most 3 columns. column gap is the space between them and column rule draws a line in the middle of the gap, written like a border; its parts are column rule width, column rule style and column rule color, and the style must be set or nothing shows.
page:
title = "Newspaper columns"
global: box sizing = "border-box" end
global: selector = "body" font family = "Georgia, serif" margin = 20 end
box:
columns = "10rem 3" column gap = 28 column rule = "1px solid #94a3b8" line height = 1.5
heading: size = 2 column span = all margin = "0 0 10" content = "Harbour news" end
paragraph: margin = "0 0 10" content = "The ferry returned to its summer timetable on Monday after a month of repairs. Passengers filled every seat on the first crossing." end
paragraph: margin = "0 0 10" content = "Fishermen report a good catch of herring, and the market opened an hour early to cope with the demand." end
paragraph: break inside = avoid margin = "0 0 10" content = "The lighthouse keeper will give a talk on Saturday about the history of the harbour. Entry is free." end
paragraph: margin = "0 0 10" content = "Rain is expected on Sunday, clearing by the evening." end
end
endA child with column span = all stretches across all the columns, like the heading above. column fill chooses between balanced columns (the default) and filling one column to the box's height before starting the next. The break properties control where a column may end: break inside = avoid keeps a card in one piece, break after = avoid keeps a heading with the paragraph that follows it, and break before = column forces a new column. The same properties decide page breaks when the page is printed.
A single number as the value of columns is read as pixels, so columns = "3" does not mean three columns. Write column count = 3 for a count.
Right-to-left pages
Flexbox and grid follow the page direction by themselves. In a Persian page a row starts at the right, the first column of a grid is the right one, and flex-start and start mean the right edge. The same code gives the mirror image of the English page, which is what a Persian reader expects. You do not have to change anything.
The trap is in the physical names: left, right, margin left, float = left and text align = left never flip. Wherever the side is about reading order (a badge at the end of a line, a gap after an icon, text that wraps around a picture), use the logical names: inset inline start and end, margin inline start and end, float = inline-start, text align = start. This lesson's examples already do. Use left and right only when you mean the screen, as for a shadow that falls to the right.
Reference: every layout property
Each property below has an example the compiler checked, so you can paste it inside a page: block. The accepted values are listed in brackets. Many examples place a coloured box on a grey one, so the preview of your own page shows what the property did. Persian names work in any file, and the Persian lessons use them.
Position and the offsets
Placement of a box, the distance from its edges, and the stacking order.
| Property | What it does and what it accepts | Example |
|---|---|---|
positionموقعیت position | How the element is placed. static (the default) is normal flow. relative keeps its place in the flow and can be nudged with the offsets. absolute leaves the flow and is placed against the nearest positioned ancestor. fixed is placed against the window and stays when the page scrolls. sticky scrolls like normal until it reaches its offset, then sticks. [static, relative, absolute, fixed, sticky] | box: position = relative top = 10 left = 20 background = "#bfdbfe" padding = 12 content = "Moved 10 down and 20 right" end |
topبالا top | Distance from the top edge of the reference box: the element's own place for relative, the nearest positioned ancestor for absolute, the window for fixed. A number is pixels. Percentages and auto work. It does nothing on a static element. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute top = 8 left = 8 background = "#fca5a5" padding = 6 content = "8 px from the top" end
end |
rightراست right | Distance from the right edge of the reference box, with the same rules as top. It is a physical side: it does not flip in a right-to-left page. Use inset inline end when the side should follow the text direction. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute top = 8 right = 8 background = "#fca5a5" padding = 6 content = "8 px from the right" end
end |
bottomپایین bottom | Distance from the bottom edge of the reference box, with the same rules as top. Together with top on an element that has no height, it stretches the element between the two edges. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute bottom = 0 left = 0 right = 0 background = "#93c5fd" padding = 6 content = "A strip on the bottom edge" end
end |
leftچپ left | Distance from the left edge of the reference box, with the same rules as top. It is a physical side. Opposing offsets such as left and right together stretch an absolute element across its parent. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute top = 8 left = 24 background = "#fca5a5" padding = 6 content = "24 px from the left" end
end |
insetفاصله از لبه inset | Shorthand for top, right, bottom and left in one value, with up to four values in the same order as margin. inset = 0 makes an absolute box cover its whole reference box. [length / percentage / auto; up to 4 values] | box: position = relative height = 80 background = "#e2e8f0"
box: position = absolute inset = "10 40" background = "#86efac" content = "10 px above and below, 40 px at the sides" end
end |
inset blockفاصله از لبه بلوکی inset-block | Logical offsets for the block axis (top and bottom in horizontal writing) in one property, with one or two values: the start side, then the end side. [length / percentage / auto; up to 2 values] | box: position = relative height = 90 background = "#e2e8f0"
box: position = absolute inset block = "10 30" background = "#86efac" content = "10 px from the start, 30 px from the end" end
end |
inset block startفاصله از لبه بلوکی آغاز inset-block-start | The offset from the start edge of the block axis, which is the top in ordinary horizontal text. It is the logical form of top. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute inset block start = 12 background = "#fca5a5" padding = 6 content = "12 px from the block start" end
end |
inset block endفاصله از لبه بلوکی انتها inset-block-end | The offset from the end edge of the block axis, which is the bottom in ordinary horizontal text. It is the logical form of bottom. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute inset block end = 12 background = "#fca5a5" padding = 6 content = "12 px from the block end" end
end |
inset inlineفاصله از لبه خطی inset-inline | Logical offsets for the inline axis (the direction the text runs) in one property, with one or two values: the start side, then the end side. In an English page start is the left, in a Persian page it is the right. [length / percentage / auto; up to 2 values] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute top = 10 inset inline = "20 60" background = "#86efac" padding = 6 content = "20 px at the start, 60 px at the end" end
end |
inset inline startفاصله از لبه خطی آغاز inset-inline-start | The offset from the start edge of the inline axis: the left edge in a left-to-right page and the right edge in a right-to-left page. It is the logical form of left. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute top = 10 inset inline start = 16 background = "#fca5a5" padding = 6 content = "16 px from the start" end
end |
inset inline endفاصله از لبه خطی انتها inset-inline-end | The offset from the end edge of the inline axis: the right edge in a left-to-right page and the left edge in a right-to-left page. It is the logical form of right, and the right choice for a badge in the corner of a card. [length / percentage / auto] | box: position = relative height = 70 background = "#e2e8f0"
box: position = absolute top = 10 inset inline end = 16 background = "#fca5a5" padding = 6 content = "16 px from the end" end
end |
z indexترتیب لایه z-index | The stacking order of overlapping elements, as a whole number. A higher number is painted on top, a negative number goes behind. It works on positioned elements and on flex and grid items. auto is the default. [integer / auto] | box: position = relative height = 90 background = "#e2e8f0"
box: position = absolute top = 0 left = 0 width = 90 height = 60 background = "#fca5a5" z index = 2 content = "on top" end
box: position = absolute top = 20 left = 40 width = 90 height = 60 background = "#93c5fd" z index = 1 end
end |
Float
Wrapping text around a box.
| Property | What it does and what it accepts | Example |
|---|---|---|
floatشناوری float | Takes the element out of the normal line and pushes it to one side so the text wraps around it. Values: left, right, inline-start, inline-end and none. Use it to put a picture inside a paragraph, not to lay out a page. [left, right, none, inline-start, inline-end] | box: float = inline-end width = 80 height = 60 background = "#fcd34d" margin = 6 content = "Floated" end
paragraph: content = "The text wraps around the floated box on its side and carries on beneath it when the box ends." end |
clearپاکسازی شناوری clear | Makes the element start below floated boxes instead of wrapping beside them. Values: left, right, both (both sides, the usual choice), inline-start, inline-end and none. [left, right, both, none, inline-start, inline-end] | box: clear = both background = "#e2e8f0" padding = 8 content = "I start below any floated box" end |
Flexbox
Direction, wrapping and sizing of flex items. Put display = flex on the parent.
| Property | What it does and what it accepts | Example |
|---|---|---|
flexفلکس flex | Shorthand for flex grow, flex shrink and flex basis of a flex item. One number such as 1 means "grow equally from zero". "0 0 160px" is a fixed 160 pixel item. The keywords auto (1 1 auto) and none (0 0 auto) are also accepted. [CSS-wide keywords only] | box: display = flex gap = 8
box: flex = "0 0 100px" background = "#fcd34d" padding = 8 content = "fixed" end
box: flex = 1 background = "#c4b5fd" padding = 8 content = "takes the rest" end
end |
flex directionجهت فلکس flex-direction | The direction of the main axis of a flex container. row (default) goes along the text direction, column goes top to bottom, and row-reverse and column-reverse run the opposite way. [row, row-reverse, column, column-reverse] | box: display = flex flex direction = column gap = 6
box: background = "#fca5a5" padding = 8 content = "first" end
box: background = "#93c5fd" padding = 8 content = "second" end
end |
flex wrapپیچش آرایش flex-wrap | Whether flex items stay on one line or move to a new line when they do not fit. nowrap (default) squeezes them, wrap adds lines, and wrap-reverse adds them upwards. [nowrap, wrap, wrap-reverse] | box: display = flex flex wrap = wrap gap = 6 width = 220
box: width = 90 background = "#fca5a5" padding = 8 content = "one" end
box: width = 90 background = "#93c5fd" padding = 8 content = "two" end
box: width = 90 background = "#86efac" padding = 8 content = "three" end
end |
flex flowجریان فلکس flex-flow | Shorthand for flex direction and flex wrap in one value, for example "column wrap". [CSS-wide keywords only] | box: display = flex flex flow = "row wrap" gap = 6 width = 220
box: width = 90 background = "#fcd34d" padding = 8 content = "a" end
box: width = 90 background = "#bbf7d0" padding = 8 content = "b" end
box: width = 90 background = "#bae6fd" padding = 8 content = "c" end
end |
flex growرشد فلکس flex-grow | How much of the free space in the line this item takes, as a share compared with the other items. The default is 0 (do not grow). Items with 1, 2 and 1 split the free space in the ratio 1 to 2 to 1. [number] | box: display = flex gap = 6
box: flex grow = 1 background = "#fca5a5" padding = 8 content = "1" end
box: flex grow = 3 background = "#93c5fd" padding = 8 content = "3" end
end |
flex shrinkجمعشدن فلکس flex-shrink | How much this item gives up when the items together are wider than the container. The default is 1. With 0 the item keeps its size and may overflow. [number] | box: display = flex width = 240
box: flex shrink = 0 width = 160 background = "#fcd34d" padding = 8 content = "never shrinks" end
box: width = 160 background = "#c4b5fd" padding = 8 content = "shrinks" end
end |
flex basisپایه فلکس flex-basis | The starting size of the item along the main axis, before growing or shrinking. It takes a length, a percentage, auto (use the width) or content. [length / percentage / auto, content, min-content, max-content, fit-content] | box: display = flex gap = 6
box: flex basis = 120 background = "#fcd34d" padding = 8 content = "basis 120" end
box: flex basis = "30%" background = "#bbf7d0" padding = 8 content = "basis 30%" end
end |
orderترتیب نمایش order | The visual position of a flex or grid item, as a whole number. Items are drawn from the lowest to the highest, and items with the same number keep the order of the code. The default is 0. Keyboard focus still follows the code, so do not use it to reorder content that matters. [integer] | box: display = flex gap = 6
box: order = 2 background = "#fca5a5" padding = 8 content = "A (order 2)" end
box: order = 1 background = "#93c5fd" padding = 8 content = "B (order 1)" end
end |
Alignment and gaps
Most of these work in both flexbox and grid. justify items and justify self are for grid only.
| Property | What it does and what it accepts | Example |
|---|---|---|
justify contentچینش justify-content | Places the items along the main axis (the inline axis in a grid) when there is free space. Values: flex-start, flex-end, center, space-between (equal gaps, no space at the ends), space-around, space-evenly and stretch. [normal, start, end, center, flex-start, flex-end, ...] | box: display = flex justify content = space-between background = "#e2e8f0" padding = 8
box: background = "#fca5a5" padding = 8 content = "first" end
box: background = "#93c5fd" padding = 8 content = "middle" end
box: background = "#86efac" padding = 8 content = "last" end
end |
align itemsترازعمودی align-items | Places the items across the cross axis of a flex container (and the block axis in a grid). stretch is the default and makes items fill the line. flex-start, flex-end, center and baseline align them without stretching. [normal, stretch, center, start, end, flex-start, ...] | box: display = flex align items = center height = 90 background = "#e2e8f0" gap = 6
box: background = "#fca5a5" padding = "6 10" content = "short" end
box: background = "#93c5fd" padding = "24 10" content = "tall" end
end |
align contentمحتوا تراز align-content | Distributes the lines of a container that has more than one line (a wrapping flex box, a grid taller than its rows) along the cross axis. It has no effect on a single line. Values are like justify content: flex-start, center, space-between and so on. [normal, start, end, center, flex-start, flex-end, ...] | box: display = flex flex wrap = wrap align content = flex-start height = 120 width = 200 background = "#e2e8f0" gap = 6
box: width = 90 height = 30 background = "#fca5a5" content = "a" end
box: width = 90 height = 30 background = "#93c5fd" content = "b" end
box: width = 90 height = 30 background = "#86efac" content = "c" end
end |
align selfخود تراز align-self | Overrides align items for one item. auto (default) follows the container. The other values are flex-start, flex-end, center, stretch and baseline. [auto, normal, stretch, center, start, end, ...] | box: display = flex height = 90 background = "#e2e8f0" gap = 6
box: background = "#fca5a5" padding = 8 content = "default" end
box: align self = flex-end background = "#93c5fd" padding = 8 content = "self at the end" end
end |
justify itemsموارد چینش justify-items | In a grid, aligns every item along the inline axis inside its own cell. stretch (the default for grid) fills the cell, and start, end and center shrink the item and place it. It has no effect in a flex container. [normal, stretch, center, start, end, flex-start, ...] | box: display = grid grid template columns = "1fr 1fr" justify items = center gap = 6 background = "#e2e8f0"
box: background = "#fca5a5" padding = 8 content = "centered" end
box: background = "#93c5fd" padding = 8 content = "in its cell" end
end |
justify selfخود چینش justify-self | In a grid, aligns one item along the inline axis inside its cell and overrides justify items. Values: auto, start, end, center and stretch. [auto, normal, stretch, center, start, end, ...] | box: display = grid grid template columns = "1fr 1fr" gap = 6 background = "#e2e8f0"
box: justify self = "end" background = "#fca5a5" padding = 8 content = "end of its cell" end
box: background = "#93c5fd" padding = 8 content = "default" end
end |
place contentمحتوا جایگذاری place-content | Shorthand for align content and then justify content. One value sets both. It positions the whole set of tracks or lines inside the container. [normal, stretch, center, start, end, flex-start, ...; up to 2 values] | box: display = grid place content = center height = 100 background = "#e2e8f0"
box: background = "#fca5a5" padding = 10 content = "in the middle" end
end |
place itemsموارد جایگذاری place-items | Shorthand for align items and then justify items. One value sets both, so place items = center centres every item in its cell. [normal, stretch, center, start, end, flex-start, ...; up to 2 values] | box: display = grid grid template columns = "1fr 1fr" grid auto rows = 70 place items = center gap = 6 background = "#e2e8f0"
box: background = "#fca5a5" padding = 8 content = "one" end
box: background = "#93c5fd" padding = 8 content = "two" end
end |
place selfخود جایگذاری place-self | Shorthand for align self and then justify self of one grid item. One value sets both. [auto, normal, stretch, center, start, end, ...; up to 2 values] | box: display = grid grid template columns = "1fr 1fr" grid auto rows = 70 gap = 6 background = "#e2e8f0"
box: place self = center background = "#fca5a5" padding = 8 content = "centered" end
box: background = "#93c5fd" content = "fills its cell" end
end |
gapشکاف gap | The space between the items of a flex or grid container (and between columns of a multi-column box). One value is used both ways; two values are the row gap, then the column gap, as in "8 16". A number is pixels. [length / percentage / normal; up to 2 values] | box: display = flex gap = "8 20" flex wrap = wrap width = 200
box: background = "#fca5a5" padding = 8 content = "one" end
box: background = "#93c5fd" padding = 8 content = "two" end
box: background = "#86efac" padding = 8 content = "three" end
end |
row gapشکاف ردیف row-gap | The space between rows only, in a grid or a wrapping flex container. Together with column gap it is the long form of gap. [length / percentage / normal] | box: display = grid grid template columns = "1fr 1fr" row gap = 20
box: background = "#fca5a5" padding = 8 content = "a" end
box: background = "#93c5fd" padding = 8 content = "b" end
box: background = "#86efac" padding = 8 content = "c" end
box: background = "#fcd34d" padding = 8 content = "d" end
end |
Grid
Tracks, areas and the placement of items. Put display = grid on the parent.
| Property | What it does and what it accepts | Example |
|---|---|---|
gridشبکه grid | The grid shorthand. It sets the row and column tracks in one value, for example "auto-flow / 1fr 1fr" (rows are created as needed, two equal columns), or like grid template with areas and a slash between the rows and the columns. [track lists, area strings, auto-flow/dense; up to one /] | box: display = grid grid = "auto-flow 60px / 1fr 2fr" gap = 6
box: background = "#fca5a5" padding = 8 content = "narrow" end
box: background = "#93c5fd" padding = 8 content = "wide" end
box: background = "#86efac" padding = 8 content = "narrow" end
box: background = "#fcd34d" padding = 8 content = "wide" end
end |
grid templateالگو شبکه grid-template | Shorthand for grid template rows, grid template columns and grid template areas. Write the area strings with a size after each one, then a slash and the column sizes. [area strings, track sizes and line names; up to one /] | box: display = grid grid template = `"title title" 40px "menu body" 60px / 90px 1fr` gap = 6
box: grid area = title background = "#fca5a5" content = "title" end
box: grid area = menu background = "#93c5fd" content = "menu" end
box: grid area = body background = "#86efac" content = "body" end
end |
grid template columnsستون های شبکه grid-template-columns | The sizes of the columns, one value per column. A length, a percentage, a fraction such as 1fr (one share of the free space), auto, and the functions repeat(3, 1fr) and minmax(120px, 1fr). A bare number means pixels. [length / percentage / fraction; up to 999 values] | box: display = grid grid template columns = "80px 1fr 2fr" gap = 6
box: background = "#fca5a5" padding = 8 content = "80px" end
box: background = "#93c5fd" padding = 8 content = "1fr" end
box: background = "#86efac" padding = 8 content = "2fr" end
end |
grid template rowsردیفها الگو شبکه grid-template-rows | The heights of the rows, written like the columns. Rows that are not listed are created on demand and sized by grid auto rows. [length / percentage / fraction; up to 999 values] | box: display = grid grid template rows = "40px 1fr" height = 120 gap = 6
box: background = "#fca5a5" content = "40px" end
box: background = "#93c5fd" content = "the rest" end
end |
grid template areasنواحی الگو شبکه grid-template-areas | Names the cells of the grid. Write one string with a quoted row for each row of the grid, each holding one name per column. Use backticks around it so the inner quotes need no escape, keep it on a single line, and repeat a name to join cells. A dot (.) leaves a cell empty. Items choose their place with grid area. [string; up to 99 values] | box: display = grid grid template columns = "70px 1fr" grid template areas = `"head head" "nav main"` gap = 6
box: grid area = head background = "#fca5a5" padding = 6 content = "head" end
box: grid area = nav background = "#93c5fd" padding = 6 content = "nav" end
box: grid area = main background = "#86efac" padding = 6 content = "main" end
end |
grid auto flowجریان خودکار شبکه grid-auto-flow | How items that have no place of their own are put into the grid. row (default) fills row by row, column fills column by column, and dense backfills holes left by larger items, even if that changes the visual order. [row, column, dense; up to 2 values] | box: display = grid grid template columns = "repeat(3, 1fr)" grid auto flow = "row dense" gap = 6
box: grid column = "span 2" background = "#fca5a5" padding = 8 content = "wide" end
box: grid column = "span 2" background = "#93c5fd" padding = 8 content = "wide" end
box: background = "#86efac" padding = 8 content = "fills the hole" end
end |
grid auto columnsستونهای خودکار شبکه grid-auto-columns | The size of columns that are created automatically, for items placed outside the columns listed in grid template columns or with grid auto flow = column. [length / percentage / fraction; up to 99 values] | box: display = grid grid auto flow = column grid auto columns = 70 gap = 6
box: background = "#fca5a5" padding = 8 content = "a" end
box: background = "#93c5fd" padding = 8 content = "b" end
box: background = "#86efac" padding = 8 content = "c" end
end |
grid auto rowsردیفهای خودکار شبکه grid-auto-rows | The size of rows that are created automatically. minmax(60px, auto) gives each row at least 60 pixels and lets it grow with its content. [length / percentage / fraction; up to 99 values] | box: display = grid grid template columns = "1fr 1fr" grid auto rows = "minmax(50px, auto)" gap = 6
box: background = "#fca5a5" padding = 8 content = "a" end
box: background = "#93c5fd" padding = 8 content = "b" end
box: background = "#86efac" padding = 8 content = "c" end
end |
grid columnستون شبکه grid-column | Shorthand for grid column start and grid column end, written with a slash: "1 / 3" goes from line 1 to line 3 (two columns). "span 2" takes two columns from where the item falls. "1 / -1" goes all the way across. [integer / name; up to 3 values] | box: display = grid grid template columns = "repeat(3, 1fr)" gap = 6
box: grid column = "1 / 3" background = "#fca5a5" padding = 8 content = "lines 1 to 3" end
box: background = "#93c5fd" padding = 8 content = "one" end
end |
grid column startآغاز ستون شبکه grid-column-start | The grid line where the item starts in the column direction. Lines are counted from 1, the left edge of the first column in a left-to-right page. Take a number, a name, or span 2. [integer / name / auto, span; up to 2 values] | box: display = grid grid template columns = "repeat(3, 1fr)" gap = 6
box: grid column start = 2 background = "#fca5a5" padding = 8 content = "starts at line 2" end
end |
grid column endانتهای ستون شبکه grid-column-end | The grid line where the item ends in the column direction. "span 2" means "two columns past the start", and -1 is the last line. [integer / name / auto, span; up to 2 values] | box: display = grid grid template columns = "repeat(3, 1fr)" gap = 6
box: grid column end = "span 2" background = "#fca5a5" padding = 8 content = "two columns" end
end |
grid rowردیف شبکه grid-row | Shorthand for grid row start and grid row end, like grid column: "span 2" makes the item two rows tall. [integer / name; up to 3 values] | box: display = grid grid template columns = "1fr 1fr" grid auto rows = 40 gap = 6
box: grid row = "span 2" background = "#fca5a5" padding = 8 content = "two rows tall" end
box: background = "#93c5fd" content = "b" end
box: background = "#86efac" content = "c" end
end |
grid row startآغاز ردیف شبکه grid-row-start | The grid line where the item starts in the row direction, counted from 1 at the top. [integer / name / auto, span; up to 2 values] | box: display = grid grid template columns = "1fr 1fr" grid auto rows = 40 gap = 6
box: grid row start = 2 background = "#fca5a5" padding = 8 content = "starts in row 2" end
end |
grid row endانتهای ردیف شبکه grid-row-end | The grid line where the item ends in the row direction. "span 3" means three rows past the start. [integer / name / auto, span; up to 2 values] | box: display = grid grid template columns = "1fr 1fr" grid auto rows = 40 gap = 6
box: grid row end = "span 3" background = "#fca5a5" padding = 8 content = "three rows" end
box: background = "#93c5fd" content = "b" end
end |
grid areaناحیه شبکه grid-area | Places an item in one go. A name refers to an area from grid template areas. Four numbers separated by slashes are the row start, column start, row end and column end lines, as in "1 / 2 / 3 / 4". [integer / name; up to 3 values] | box: display = grid grid template columns = "repeat(3, 1fr)" grid auto rows = 40 gap = 6
box: grid area = "1 / 2 / 3 / 4" background = "#fca5a5" padding = 8 content = "rows 1-2, columns 2-3" end
end |
Columns and breaks
Newspaper columns, the lines between them and where they may break.
| Property | What it does and what it accepts | Example |
|---|---|---|
break afterشکستن پس از break-after | Whether a break is forced or avoided after this element, with the same values as break before. column ends the column here, and avoid keeps a heading together with the paragraph that follows it. [auto, avoid, always, all, avoid-page, page, ...] | box: column count = 2 column gap = 20 line height = 1.4
paragraph: break after = column margin = 0 content = "This paragraph ends the first column." end
paragraph: margin = 0 content = "So this one starts the second column." end
end |
break beforeشکستن پیش از break-before | Whether a column, page or region break is forced or avoided before this element. In columns, column starts a new column here and avoid asks to keep it with the content before it. The values page and always matter when you print. [auto, avoid, always, all, avoid-page, page, ...] | box: column count = 2 column gap = 20 line height = 1.4
paragraph: margin = 0 content = "First column." end
paragraph: break before = column margin = 0 content = "Forced into the second column." end
end |
break insideشکستن درون break-inside | Whether a break may fall inside this element. avoid keeps a card, figure or short paragraph in one piece when a column or page ends. The default is auto. [auto, avoid, avoid-page, avoid-column] | box: column count = 2 column gap = 20 line height = 1.4
box: break inside = avoid background = "#fef3c7" padding = 8 margin bottom = 8 content = "This card is never split across two columns." end
paragraph: margin = 0 content = "Other text may flow on as usual." end
end |
column countتعداد ستون column-count | The number of columns, as a whole number. With column width as well, it is the largest number of columns allowed. [integer / auto] | box: column count = 2 column gap = 20 line height = 1.5
paragraph: margin = 0 content = "Two columns of text, whatever the width of the box. The text is shared between them so that both end at about the same height." end
end |
column fillپرکردن ستون column-fill | How the content is shared between columns. balance (default) makes the columns about equal in height. auto fills one column to the height of the box before starting the next, which matters when the box has a fixed height. [auto, balance] | box: column count = 2 column gap = 20 column fill = auto height = 80 line height = 1.4
paragraph: margin = 0 content = "With auto the first column is filled to the full height of the box before any text moves to the second column." end
end |
column gapشکاف ستون column-gap | The space between columns. It also sets the gap between the columns of a grid or flex container. The default for multi-column text is normal (1em). [length / percentage / normal] | box: column count = 2 column gap = 40 line height = 1.5
paragraph: margin = 0 content = "A wide gap of 40 pixels separates the two columns of this text, which makes the break easy to see." end
end |
column ruleخط جداکننده ستون column-rule | Shorthand for the line drawn between columns: width, style and colour, written like a border, for example "1px solid #94a3b8". The rule takes no space of its own; it sits in the middle of the gap. [CSS-wide keywords only] | box: column count = 2 column gap = 30 column rule = "2px dashed #64748b" line height = 1.5
paragraph: margin = 0 content = "A dashed line runs down the middle of the gap between the two columns of this paragraph, just as in a printed newspaper." end
end |
column rule colorرنگ خط ستون column-rule-color | The colour of the line between columns. [color] | box: column count = 2 column gap = 30 column rule style = solid column rule width = 2 column rule color = crimson line height = 1.5
paragraph: margin = 0 content = "The rule between these two columns is drawn in crimson, set separately from its style and width." end
end |
column rule styleسبک خط ستون column-rule-style | The line style between columns: solid, dashed, dotted, double and the other border styles. none (default) draws nothing, so you must set a style for the rule to show. [none, hidden, dotted, dashed, solid, double, ...] | box: column count = 2 column gap = 30 column rule width = 3 column rule style = dotted line height = 1.5
paragraph: margin = 0 content = "A dotted rule separates these columns. Without a style the width and colour would draw nothing at all." end
end |
column rule widthضخامت خط ستون column-rule-width | The thickness of the line between columns: a length, or thin, medium or thick. It needs a rule style to show. [length / thin, medium, thick] | box: column count = 2 column gap = 30 column rule style = solid column rule width = 4 line height = 1.5
paragraph: margin = 0 content = "A thick rule four pixels wide runs between these two columns, so the division is easy to see." end
end |
column spanگستره ستون column-span | Lets an element inside a multi-column box stretch across all the columns. The values are none (default) and all. It is used for a heading above the columns. [none, all] | box: column count = 2 column gap = 20 line height = 1.5
heading: size = 3 column span = all margin = "0 0 8" content = "A heading across both columns" end
paragraph: margin = 0 content = "The text below the heading is shared between the two columns, while the heading itself is as wide as the whole box." end
end |
column widthعرض ستون column-width | The ideal width of a column. The browser makes as many columns of at least this width as fit and widens them to fill the box, so the number changes with the window. [length / auto] | box: column width = 140 column gap = 20 line height = 1.5
paragraph: margin = 0 content = "The number of columns follows the available width, never narrower than 140 pixels each, so a phone gets one column and a desktop gets several." end
end |
columnsچندستونی columns | Shorthand for column width and column count: "12rem 3" means "columns at least 12rem wide, at most 3". Write a single number with column count, because a bare number here becomes pixels. [CSS-wide keywords only] | box: columns = "9rem 3" column gap = 20 line height = 1.5
paragraph: margin = 0 content = "Text in a multi-column box flows down the first column and continues at the top of the next one, like a newspaper. The browser picks how many columns fit." end
end |
Try it yourself
- Build a page header with a logo on one side, three links in the middle and a button on the other side, using only a flex row and
justify content. - Make a photo gallery of nine coloured boxes with
repeat(auto-fit, minmax(120px, 1fr)). Make the first box span two columns and two rows. - Write a classic page layout with named areas: a header, a left menu, a main part, a right column and a footer. Then change one string so the menu moves to the right.
- Take the sticky example and give the headings
z indexand a shadow. What happens when you remove thetopvalue?