Designing for Display Density

Striking the right balance between an information-rich UI and a more open design is always a challenge. At Revalize, our software serves the full range of “power” to “casual” users. Building a UI that can respond to a display density user preference is one way we’re working to accommodate people of all backgrounds.

In this post:

The end result

Before we get into the technical details of how we designed for display density, I’ll share some screen shots of the end result.

Quote List at Default display density – View full size
Quote List at Compact display density – View full size
Quote List at Comfortable display density – View full size

Users are able to alter the entire appearance of the UI with a simple toggle in their preferences. It’s been an absolute joy observing how different users have their UI configured. The compact setting is especially popular with those users who are transitioning over from some of our legacy applications.

Where to start

Adding display density support to our existing modern UI took careful planning. There are a number of different approaches we could have taken—ranging from the complexity of redesigning every component for every density preference, to the simplicity of adding a basic modifier to all existing sizing values. In the end, we settled on the simpler side of the spectrum. This allowed us to introduce this new concept to our users in a way that had minimal impact on the codebase, but would still provide immediate value for those who could most benefit from its use. As more advanced use cases pop-up in response to this real-world feature, we can use the existing framework to handle those changes.

The display density is configured as one of three choices: default, compact, or comfortable. Users don’t have the option to change things on a per-page or per-component basis; it’s all-or-nothing.

To make things as easy as possible in the codebase, we chose to design and develop from the “default” perspective. We build our components the way we intend for them to look at the standard display density, then use CSS to calculate the “compact” and “comfortable” spacing.

Basic set up

The display density scale is influenced by three modifiers, defined first as SCSS variables:

  • $ui-density-default – 1x density
  • $ui-density-compact – 0.5x density
  • $ui-density-comfortable – 2x density

Each Org is able to customize these values to achieve their desired look.

These variables are fed into corresponding CSS Custom Properties:

:root {
  --ui-density-default: #{$ui-density-default};
  --ui-density-compact: #{$ui-density-compact};
  --ui-density-comfortable: #{$ui-density-comfortable};
}

We then define a single CSS Custom Property to use when authoring styles. This single property uses default as its initial value and fallback to ensure things don’t break if the value becomes corrupted in some way.

:root {
  --ui-density: var(--ui-density-default, var(--ui-density-default));
}

Finally, we use data- attributes to handle the density preference change:

[data-ui-density="compact"] {
  --ui-density: var(--ui-density-compact);
}

[data-ui-density="comfortable"] {
  --ui-density: var(--ui-density-comfortable);
}

Today, the user’s display density preference is added to the html tag. We don’t define a specific element for the CSS selector, however, so that we preserve some flexibility in the way we use the display density preference. There may be some instances where we only want part of a page to respond to this setting; leaving the selector open-ended like this gives us that freedom.

Writing a density-ready style

To write a display density-ready style, the developer calls the --ui-density custom property in a calc function, like so:

.my-class {
  padding: calc(.5em * var(--ui-density));
}

That padding value would then change based on the modifier value of --ui-density.

Developer aids

Having the ability to fine-tune the density of the UI is all well and good on the user-side, but actually implementing these styles as a developer is another matter. Some developers won’t have an issue working with the custom property like in the previous example, but others might. I built multiple helper utilities to make it as straightforward as possible to design for display density.

SCSS Functions

Our first helper is the size() function in our SCSS library. This function takes a scale degree, like '2', and returns the corresponding value from our global $SIZES_MAP. Along with a unit, the developer can also pass $density: true as an argument to return a size that is configured for the display density preference.

// source
.some-selector {
  margin: size('2', $unit: 'rem', $density: true);
}

// compiled
.some-selector {
  margin: calc(1rem * var(--ui-density));
}

This size() function also provides some dogfood for our size-list() function and space() mixin.

For a list of sizes, the size-list() function iterates through each value in the Sass list, runs it through the size() function, and returns the full result.

// source
$my-size-list: 'base' '2';

.some-selector {
  padding: size-list($my-size-list, $density: true);
}

// compiled
.some-selector {
  padding: calc(.5em * var(--ui-density)) calc(1em * var(--ui-density));
}

SCSS Mixin

The space() mixin makes writing margin-* and padding-* styles even easier than the previous examples.

// source
.my-selector {
  @include space(margin, horizontal, '3', $density: true);
  @include space(padding, all, 'base');
}

// compiled
.my-selector {
  margin-right: calc(1.5rem * var(--ui-density));
  margin-left: calc(1.5rem * var(--ui-density));
  padding: .5em;
}

This mixin outputs the appropriate property, using keywords from our $DIRECTIONS_MAP, and applies values from our $SIZES_MAP with the density preference, if desired. Internally, the space() mixin makes a call to the size() function to grab the appropriate spacing value.


This was a fun feature to implement. As we continue to transition our power users off of the legacy applications they’re used to, building accommodations like this will be an important part of supporting their experience.