With only inequality constraints at your disposal, constraining common layout scenarios quickly becomes tedious. To horizontally align 4 buttons within a panel with a gap of 10px requires something like:
Not to mention the obligatory size & vertical constraints needed to fully specify the panel and buttons - ugh…
This is where Grid-flavored VFL comes in. The brains at Apple came up with VFL as a more programatic way to install constraints in Cocoa AutoLayout. The idea is rather simple, the syntax should visually depict the layout. GSS takes the good parts of VFL and makes it more suitable for CSS, throws in some sugar and drops the cruft. So the above example of 4 buttons in a panel becomes:
Basics
Horizontal layouts can be created with the CSS directive @h
.
Vertical layouts with the CSS directive @v
.
An element is queried within parenthesis, ( Selector )
, and a connection
between elements is represented using a hyphen (or two hyphens separated by a number to represent the number of pixels apart the views should be). Similarly, a cushion
between elements is made with a tilde.
Internally, GSS compiles VFL into CCSS (in)equality constraints, so after each VFL example the compiled CCSS is included.
WARNING: The examples below are under-constrained, they only constrain elements along one dimension of alignment, to ensure an element’s size & position is fully-specified you will need to add more constraints.
Connections
Two elements can be horizontally connected without any gap. Live example.
Connection Gaps
To align elements with a gap, use a hyphen and gap( Number | Constraint Variable | Element Property )
:
If no gap()
is defined, but a hyphen is used to make a connection then a standard gap
variable is created.
The hgap
& vgap
variables can be used like normal variables and are declared in the current scope.
User defined variables can be used for gaps as well. Live example.
Containment within an Element
To align the whole VFL declaration within a specific element, a combination of in(#selector)
and vertical |
pipes can be used.
The pipes determine the edges of the element. In @h
VFL blocks leading and trailing pipes signify left and right edges of the containing element. In @v
declarations it’s top and bottom edges respectively. Live example.
Binding to both edges of the element is a safest bet, as it makes a two-way relation between element and its contents. The use case of binding to only one edges would be layouts growing in one direction without expanding the containing element, like scrollable content.
If there’s no in(selector)
provided, the edges will point to the current element within ruleset. Using in(&)
would have the same effect.
The above example can be written:
Outer-Gaps
The variable provided in gap()
declaration is used for all gaps between elements in VFL declaration. The outer-gap()
function can be used to set a different variable for gaps between the containing element and first and last contained elements.
Alignment to Points
Elements can be aligned relative to arbitrary positioned points of the document using angle bracket syntax. The points can be either numbers or variables. Live example.
To horizontally align two buttons, each 8px from the center of the window:
Elements can be positioned between points:
Numbers, variables and arithmetic can be used:
Consecutive points are not constrained to each-other:
Cushions
Cushions are expandable connection gaps. They use inequality instead of equality constraints. Live example.
Size Predicates
Size Predicates allow elements to be sized in the dimension parallel with the alignment. Live example.
Multiple size predicates:
VFL Selectors
VFL expressions can use any complex selectors:
VFL Splat
When a selector in a VFL expression finds more than one element, not all elements will be constrained if the number of elements within each selector’s expression are not equal. This is due to plural binding. Live example.
In this example, the last two article elements will not be constrained since there is no section element to bind to. As can be seen in the generated CCSS, the elements are constrained using plural binding.
If the number of selected elements matches, the position of the elements within each collection of selected elements will overlap since you’re basically constraining the whole collection to the same values. Live example.
Splats will iterate over the collection of selected elements and position elements next to each other. Live example.
In the previous example, the two sections will be positioned next to each other with a gap of 10px. The three articles will be positioned next to each other with a gap of 20px. Finally the two divs will be right next to each other without any gap.
Virtual elements with VFL
Virtual elements can be created and/or positioned using VFL expressions.
You can position a virtual element the same as any other element:
VFL rulesets
You can use a VFL expression as a selector in rulesets. It will create a collection of all elements positioned by the VFL declaration, not including the containing element. Properties defined in the body of the ruleset will be applied to each of those elements.
In the following example, each element width is bound to the same variable, making them equal width:
VFL Strengths
Strength used in VFL will be applied to all constraints generated by the statement:
Size Predicates may have their own strength: