AI websites that design themselves

Join the evolution

Become a founding member

Position and dimension

lay it out like it's 1999

Positioning

Elements are positioned relative to the scope element, so its top-left corner is considered a (0, 0) point. GSS initialized upon document, <html>, <body> or <head> position against the <html> element. Global properties like $left, $right, $scroll-top and $bottom point to respective properties of ::window.

Cassowary is a general purpose solver, so it does not make any assumptions about the positioning or even geometry. If there's nothing that is bound to absolute values like zero or edges of the screen, the whole layout can be solved to be positioned off-screen. Negative top and left values is a common gotcha in underconstrained systems.

Top

#someElm[top] == 20;

/* equivalent to : */
#someElm[y] == 20;

Place the top of the element 20px from the top of the page.

Bottom

#someElm[bottom] == 100;

/* equivalent to : */
#someElm[bottom] == #someElm[top] + #someElm[height];

Place the bottom of the element 100px from the top of the page.

Left

#someElm[left] == 20;

/* equivalent to : */
#someElm[x] == 20;

Place the left of the element 20px from the left of the page.

Right

#someElm[right] == 100;

/* equivalent to : */
#someElm[rigth] == #someElm[left] + #someElm[width];

Place the right of the element 100px from the left of the page.

position

#someElm[position] == 100;

/* equivalent to : */
#someElm[top] == 100;
#somElm[left] == 100;

top-left, top-right

#someElm[top-left] == 100;
#otherElm[top-right] == 200;

/* equivalent to : */
#someElm[top] == 100;
#someElm[left] == 100;
#otherElm[top] == 200;
#otherElm[right] == 200;

Position the #someElm top-left corner to be at 100px from the top-left of the page. Same thing for #otherElm except it's the top-right corner that's been positioned 200px from the top-left of the page.

bottom-left, bottom-right

#someElm[bottom-left] == 100;
#otherElm[bottom-right] == 200;

Position the #someElm bottom-left corner to be at 100px from the top-left of the page. Same thing for #otherElm, except it's the bottom-right corner that's been positioned 200px from the top-left of the page.

center-x, cx

#someElm[center-x] == 100;

/* you can also use the condense syntax: */
#someElm[cx] == 100;

/* center-x will expand in the following constraints */
#someElm[left] + #someElm[width] / 2 == 100;

Set the horizontal coordinate for the center of the element at 100px from the left of the page.

center-y, cy

#someElm[center-y] == 100;

/* you can also use the condense syntax: */
#someElm[cy] == 100;

/* center-y will expand in the following constraints */
#someElm[top] + #someElm[height] / 2 == 100;

Set the vertical coordinate for center of the element at 100px from the top of the page.

Center

#someElm[center] == 100;

center is a 2d property shortcut for constraining both center-x and center-y at once.

Relative positioning

Elements that have parents with position: relative declared in CSS stylesheet will compute their position ignoring that declaration.

Cassowary won't know about relative parents. Visually you won't tell the difference. But the actual top and left styles assigned for each element will account for the relative positioning.

When position: relative is set on the element within a style attribute of the element, all its descendants will be positioned as if that relative parent was at the top-left corner of the screen.

<section class="container" style="position: relative">
  <div class="content"></div>
</section>

<section class="container" id="section-two" style="position: relative">
  <div class="content"></div>
</section>

<style type="text/gss">

.container {
  top: == 0;
  left: == 0;

  .content {
    top: == ^top;
    bottom: == ^bottom;
    height: == 100;
    width: == 100;
  }
}

</style>

In this example, each element having container class will have its top and left properties constrained to zero. But since the containers have explicit position: relative set, they will push one another by the means of regular CSS page flow. Otherwise each container would be positioned at the same spot each overlaying the other. Live example.

By employing CSS to lay out big chunks of layout, we make each section solution independent. This leads to smaller individual constraint graphs and better overall performance.

With the position: relative declared in the style attribute, GSS will solve independently each section which should result in better performance. Live example.

Dimensions

GSS provides a property to constrain the dimension of an element. We already saw the width and height properties. GSS provides syntax sugar called 2d properties to constrain both height and width of an element as a single property.

.selectorA {
  size: == 200;
}

Intrinsic values

Positioning elements with top and left properties doesn't require GSS to know the dimensions of those elements. But right and bottom properties need to know about width and height of the element respectively. Properly constrained systems will provide those values indirectly with no regard to an element's contents.

However, it's often desirable to know the computed dimensions of specific elements which GSS has no control over - be it text, images or blocks styled with CSS. Measurements provide dynamic "islands" to the layout, which can be automatically recomputed, whenever measured things are updated from the outside. It also may act as a feedback to the solver, disallowing content to shrink too much or helping to decide if things fit.

Prefixing a property with intrinsic- or computed- prefix makes GSS measure the value.

Prefixing a property with intrinsic- makes it read-only and it won't apply on the element. For example, declaring intrinsic-width will ensure that the width style is never applied to that element. This allows dimensions to change and update naturally. Otherwise, the width would be computed and applied only the first time, making it static.

computed-prefixed properties can be used to measure styles regardless of their origin - either GSS constraints or CSS styles. Computed properties will not make styles read-only, unlike intrinsic-prefixed properties.

// apply static width, measure height
// (height style will not be set)
.selectorA {
  width: == 200;
  height: == &intrinsic-height;
}

// only measure dimensions
// (height & width styles will not be set)
.selectorB {
  width: == &intrinsic-width;
  height: == &intrinsic-height;
}

// use dimension information to position elements
.selectorA[right] == .selectorB[left];

Read next

If you come from the CCSS guide continue your learning of CCSS

Learn how to use CCSS constraints

GSS provides conditional statements to allow you to do responsive design. Read our @if @else guide to learn more.

With only CCSS constraints at your disposal, constraining common layout scenarios quickly becomes tedious. Read our VFL guide to learn how to more efficiently constrain your layout.

privacy policy