Skip to main content
MybringDesign System

Building layout

Approach and resources

Interfaces have no formats and dimensions

Infinite number of screen sizes and user settings means there is nothing to target like we did in the early years of responsiveness. Instead of starting with predefined sizes to fill, we start working with and from content to make a structure that informs the layout.

All content has to be linear and prioritised, no one can read two things at once, and one thing cannot be as important as another. Even when we put things side by side, they have to be in some kind of relation to each other.

Letting content take up the space it needs is a good start, with some outer limit for readability, alignment and signifiers of relation to other content. This approach lets elements retain an important communicative aspect: size. Uniformity might look orderly, but it’s superficiality that can make it difficult to tell elements apart. For example if all buttons are equal, their size no longer communicate anything, and people have to put more effort into reading.

Declarative and intrinsic

Declarative means using the users’ environment to figure out the details of a layout. One example is responsiveness, where we define some outer limits and what the browser should use to calculate the layout behaviour instead of targetting arbitrary screen sizes.

Intrinsic means we let the content and elements take up the space they need. But there is room to adjust them when the situation calls for it. The opposite approach is imperative and extrinsic, which is explicit micromanagement using predefined formats and sizes, and changing them based on screen sizes. It’s not something we can avoid, but it’s something we only reach for when we have to achieve certain controlled behaviour, for example navigation toggling.

Instead of using grids and breakpoint sets in Mybring, we use Flexbox utilities for simple layouts and write custom CSS for more complex ones.

Examples

Resize viewport, zoom and scale to see how the examples behave.

Recommended: Intrinsic

Here is some text followed by another piece of text. Sometimes they are side by side, sometimes underneath each other. They flex, they change size at different rates, the smaller avoids becoming too narrow. The wrap and reflow happens when they reach a certain size, either because of the screen size or the font size settings of the user.

This is based on a calculation between sizing behaviour set on the elements and the user’s font size settings, not by referencing a screen size.

Avoid most of the time: Extrinsic

Here is some text followed by another piece of text. Sometimes they are side by side, sometimes underneath each other. They shrink and grow at the same rate, leading to a need for more detailed control and manual breakpoints.

The wrap and reflow settings are referencing specific screen sizes.

Grid content

While content should be a part of defining the size of an element, there are instances where the difference between content and layout isn’t clear. One example is tables, which is a lot of data laid out, but the table itself is more like content. Another one is tile view grids where it makes most sense to have just that, a grid, and let that be the frame for the content. A powerful grid technique when we want unison column width is the auto grid. And for that we turn to CSS Grid, which has no utility classes since it always require some specific code.

.grid-parent {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
}
Explanation

The repeat function takes two parameters. The first one is how (or for how many elements) the second parameter should repeat. The second parameter is the size. For the size, we use a function that also takes two parameters and it returns the size between the two. At least one parameter has to be dynamic so there can be a calculation. Then we add the min function as one of the parameters which again takes two parameters and returns the smallest.

In this case, the sizing should repeat for all the elements. The size of the elements should fill the remaining empty space when there isn’t room for more than one 16 rem wide column. So if the parent is 30 rem wide, the elements will be 30 rem wide, but as soon as it is 32 rem (plus spacing), we get two columns. And when the parent shrinks below 16 rem, 100 % becomes the smaller value and the column can continue to shrink indefinitely without overflowing.

HTML
<div class="mb-form mb-form--spaced gas grid-parent">

  <a href="#" class="mb-card pam">
    <div class="flex justify-csb mbm">
      <div class="mrm lh-tight">
        <h3 class="mbxs">Tall building</h3>
      </div>
      <div class="service-icon">
        <span data-serviceicon="serviceicon-building" data-serviceicon-width="40" data-serviceicon-height="40"
          data-serviceicon-class="icon-ui--green-dark"></span>
      </div>
    </div>
    <dl>
      <dt>Delivery:</dt>
      <dd>Expected tomorrow 10–14</dd>
    </dl>
  </a>

  <a href="#" class="mb-card pam">
    <div class="flex justify-csb mbm">
      <div class="mrm lh-tight">
        <h3 class="mbxs">
          Watchmaker’s dial
        </h3>
      </div>
      <div class="service-icon">
        <span data-serviceicon="serviceicon-clock-striped" data-serviceicon-width="40" data-serviceicon-height="40"
          data-serviceicon-class="icon-ui--green-dark"></span></span>
      </div>
    </div>
    <dl>
      <dt>Delivery:</dt>
      <dd>Tuesday before 09.00</dd>
    </dl>
  </a>

  <a href="#" class="mb-card pam">
    <div class="flex justify-csb mbm">
      <div class="mrm lh-tight">
        <h3 class="mbxs">
          Big crate
        </h3>
      </div>
      <div class="service-icon">
        <span data-serviceicon="serviceicon-crate" data-serviceicon-width="40" data-serviceicon-height="40"
          data-serviceicon-class="icon-ui--green-dark"></span>
      </div>
    </div>
    <dl>
      <dt>Delivery:</dt>
      <dd>Expected Tuesday 10–13</dd>
    </dl>
  </a>

  <a href="#" class="mb-card pam">
    <div class="flex justify-csb mbm">
      <div class="mrm lh-tight">
        <h3 class="mbxs">
          Crate on pallet
        </h3>
      </div>
      <div class="service-icon">
        <span data-serviceicon="serviceicon-crate-on-pallet" data-serviceicon-width="40" data-serviceicon-height="40"
          data-serviceicon-class="icon-ui--green-dark"></span>
      </div>
    </div>
    <dl>
      <dt>Delivery:</dt>
      <dd>Expected Tuesday 10–13</dd>
    </dl>
  </a>

  <a href="#" class="mb-card pam">
    <div class="flex justify-csb mbm">
      <div class="mrm lh-tight">
        <h3 class="mbxs">
          Ice cream truck
        </h3>
      </div>
      <div class="service-icon">
        <span data-serviceicon="serviceicon-truck" data-serviceicon-width="40" data-serviceicon-height="40"
          data-serviceicon-class="icon-ui--green-dark"></span>
      </div>
    </div>
    <dl>
      <dt>Delivery:</dt>
      <dd>At least 1 business day</dd>
    </dl>
  </a>

</div>

Media queries

Zero media queries isn’t a goal in itself, but they are mostly useful for making minor adjustments where necessary. This gives less code, which means the media queries are best nested inside declarations instead of made into separate sets. Container queries will become more relevant than media queries, but it’s not recommended to use them in Mybring yet because of browser support.

Resources