Cloud Four Blog

Technical notes, War stories and anecdotes

Shifty Tile Flyouts

Although my favorite projects will always be those that allow us to re-evaluate a user experience from the ground up, sometimes that isn’t realistic. That’s where Responsive Retrofitting comes in: The process of making small, surgical changes to existing interfaces to improve the small-screen experience incrementally.

Each and every retrofit is a little different, but patterns do emerge. In the past couple of years, I’ve noticed one particularly challenging bit of UI that’s cropped up multiple times for multiple clients.

Illustration of tile-based interface with flyout

Here’s how it works: We have tiles separated into rows and columns. Each tile represents some form of summary content; contact info or payment options, for example. Selecting a tile (or clicking an “edit” button therein) expands a flyout below with some sort of form content, which spans the entire available width and “pushes” down any tiles below.

Every time I’ve encountered this, it’s been implemented in the same way. Because the design is fixed-width, the number of columns in each row is predictable. Flyout elements are simply inserted between rows:

<div class="Tiles">
  <div class="Tile">
    <div class="Tile-content">
      Tile 1
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 2
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 3
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 4
    </div>
  </div>
  <div class="Flyout is-open js-flyout">
    <div class="Flyout-content">
      Flyout 1
    </div>
  </div>
  <div class="Flyout Flyout--2of4 js-flyout">
    <div class="Flyout-content">
      Flyout 2
    </div>
  </div>
  <div class="Flyout Flyout--3of4 js-flyout">
    <div class="Flyout-content">
      Flyout 3
    </div>
  </div>
  <div class="Flyout Flyout--4of4 js-flyout">
    <div class="Flyout-content">
      Flyout 4
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 5
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 6
    </div>
  </div>
  <div class="Flyout js-flyout">
    <div class="Flyout-content">
      Flyout 5
    </div>
  </div>
  <div class="Flyout Flyout--2of4 js-flyout">
    <div class="Flyout-content">
      Flyout 6
    </div>
  </div>
</div>

See the Pen Shifty Tiles: Part 1 by Tyler Sticka (@tylersticka) on CodePen.

The content order’s pretty messed up, but it works as intended. Or it would have, if it hadn’t been for that meddling Ethan Marcotte and those media queries of his. When you throw responsive into the mix, that predictable column count we depended on goes right out the window:

Animation of responsive tiles with flyout

We could listen to resize events and move the flyouts around with JavaScript. But you and I both know that’s a bad idea. Let’s see how we can solve this problem with CSS alone, maybe even improving the content order along the way.

To Float or Not To Float

If we revise our markup so that the tiles and flyouts are unified (instead of separated by arbitrary “rows”), we’ll discover that the floats we were using to arrange tiles side-by-side do not handle change well. Depending on which tile flyout is expanded, subsequent tiles attempt to float around it, resulting in an inconsistent (and frankly, upsetting) experience for wider viewports:

See the Pen Shifty Tiles: Part 2 by Tyler Sticka (@tylersticka) on CodePen.

Well that’s it, then! Floats don’t work, we need tiles to float, time to throw in the towel and handle this with JavaScript.

Not so fast!

Instead of floating the tiles, we can steal borrow a technique from the SUIT CSS grid component and use display: inline-block instead. Combined with vertical-align: top, the tallest tile in a row should push down everything beneath it (just like a tall image in a line of text would affect adjacent rows).

Let’s give it a whirl:

See the Pen Shifty Tiles: Part 3 by Tyler Sticka (@tylersticka) on CodePen.

Success! Even as flyouts shove their way between rows, the tiles retain their horizontal position.

But those flyouts are still awfully narrow at larger sizes. Let’s fix that.

Manifest Destiny

Our goal is for the flyouts to occupy 100% of the available width across all viewports. So far, they’re only ever as wide as the tiles themselves. If we’re decreasing tile widths at larger breakpoints, we should also increase flyout widths by the same factor.

If you’re using a preprocessor like Sass and you hate solving the same math problems over and over as much as I do, now’s a great time to write a mixin to handle this logic across multiple breakpoints:

@mixin generate-tile-grid($columns) {
  .Tile {
    // divide the available width by the number of columns
    width: (100% / $columns);
  }
 
  .Tile-flyout {
    // extend beyond the tile width by the same factor
    width: (100% * $columns);
  }
 
  .Tile-flyout:before {
    // adjust the position of the flyout caret
    left: (100% / 2 / $columns);
  }
}
 
@media (min-width: 30em) {
  @include generate-tile-grid(2);
}
 
/* etc. */

Here’s where that gets us:

See the Pen Shifty Tiles: Part 4 by Tyler Sticka (@tylersticka) on CodePen.

So close! The widths are correct, but we haven’t accounted for the tile’s changing horizontal position. Let’s revise that mixin we wrote, using :nth-child selectors to offset the flyouts per column:

@mixin generate-tile-grid($columns) {
  .Tile {
    width: (100% / $columns);
  }
 
  .Tile-flyout {
    width: (100% * $columns);
  }
 
  // for every column in this grid
  @for $column from 1 through $columns {
    .Tile:nth-child(#{$columns}n+#{$column}) {
      .Tile-flyout {
        // offset the left margin by the number of preceding columns
        margin-left: (-100% * ($column - 1));
      }
 
      .Tile-flyout:before {
        // adjust the caret position similarly
        left: (100% / $columns * ($column - 0.5));
      }
    }
  }
}

Drumroll, please…

See the Pen Shifty Tiles: Part 5 by Tyler Sticka (@tylersticka) on CodePen.

…and boom goes the dynamite.

In Practice

Because this technique is initially counter-intuitive (at least to me), I kept the examples pretty simple. If you’re still a little fuzzy on how this interface pattern might work in practice, here’s a more complex demo involving hypothetical payment methods and their associated edit forms. Tap or click a tile to toggle:

See the Pen Responsive tiles with column-spanning flyouts by Tyler Sticka (@tylersticka) on CodePen.

Having retrofitted this type of UI multiple times now, I’d be remiss if I didn’t voice some concerns I have about its usability. Because the vertical position of subsequent tiles changes as flyouts expand and collapse, it can be frustrating to use on smaller screens without a nightmarish amount of fragile and jank-inducing scroll management. If redesigning is an option for this pattern, I recommend reading Luke W’s post about dropdowns for some much more straightforward alternatives.

Or better yet, drop us a line. Solving these problems is kind of our thing.

Introducing Leveller: Please Avoid Using It

This happens to me over and over: I have a multi-column grid of tiles, each with varying heights. This means the bottom of certain rows can appear jagged and difficult to scan visually:

See the Pen Leveller: Before by Tyler Sticka (@tylersticka) on CodePen.

Ideally, I’d use flexbox to solve that problem with a shockingly small amount of CSS (especially if you use Autoprefixer). Seriously, look how well that works:

See the Pen Leveller: Flexbox Alternative by Tyler Sticka (@tylersticka) on CodePen.

Sadly, that solution rarely makes it into production on the projects I’ve worked on. Sometimes browser support is the culprit. Other times we’ve inherited particularly uncooperative grid patterns (either from an existing project, or an overzealous framework).

Over the last few years, I wrote and re-wrote project-specific, bespoke JavaScript to solve this problem. I’ve finally accepted that it isn’t going away, at least not as quickly as I’d like it to.

So I’ve written a jQuery plugin for equalizing element heights. It’s called Leveller:

See the Pen Leveller: After by Tyler Sticka (@tylersticka) on CodePen.

Don’t use Leveller if you can help it. Flexbox is way more appropriate. If you only need to adjust min-height properties, Equalizer is a leaner, dependency-free solution.

But if all else fails, Leveller is available now on GitHub (and also via npm). Godspeed!

Two pretty-good techniques for styling tricky form elements

Confession time: For most of my career, I despised form elements. Checkboxes, radios, selects and file inputs seemed to gleefully defy what little control I expected from an HTML element. Their penchant for idiosyncracy drove me to almost as much hair-pulling and teeth-gnashing as IE6 or web-safe fonts.

These days, my frustration with form elements has quieted. Partly that’s because browsers and development tools are so much better. But more significantly, I now understand the benefits of surrendering some control to the operating system. As devices continue to accept a greater and greater variety of input methods (keyboard, mouse, touch, voice, gesture, remote, etc.) while browsers adopt an astounding variety of new input types , it’s a gift for vendors to provide default experiences consistent with the user’s expectations of the platform.

So I no longer strive for “pixel perfection” when styling form elements. I don’t need absolute control. All I want is something easy to tap that feels intentional.

When the browser defaults don’t get me there, here are my go-to workarounds.

Checkboxes and Radios: Styled Sibling

This technique works in any browser that supports CSS3 selectors (basically IE9+). If you read Radio-Controlled Web Design a few weeks ago, this should feel familiar. Let’s start with a checkbox example.

We’ll need a few HTML elements:

  • The <input> itself.
  • A dummy element to style (right next to the <input>).
  • A containing <label> that passes click events to the aforementioned <input>.

I like to wrap the <input> and dummy elements in a container to keep everything nice and tidy, but strictly speaking it isn’t required. Here’s what that markup might look like:

<label>
  <span class="checkbox">
    <input type="checkbox">
    <span class="checkbox-value" aria-hidden="true"></span>
  </span>
  Set phasers to stun
</label>

We’re now free to visually hide the checkbox, styling .checkbox-value however we like:

/* hide the "real" checkbox visually */
.checkbox input {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}
 
/* style the "fake" checkbox */
.checkbox-value {
  /* default/unchecked styles */
}
input:checked + .checkbox-value {
  /* checked styles */
}

When the user clicks the label, the click is passed along to the <input>, which toggles the state of :checked, which affects the appearance of .checkbox-value.

Here’s an example that styles the checkbox like an iOS-style switch:

See the Pen Styled checkbox by Tyler Sticka (@tylersticka) on CodePen.

Here’s the same idea applied to radio buttons with a slightly more conventional design (incorporating a base64-encoded SVG checkmark):

See the Pen Styled radios by Tyler Sticka (@tylersticka) on CodePen.

This technique has a few drawbacks. It requires some extra markup. It won’t work in IE8 or earlier without a fallback. It could probably use another pass for accessibility. But compared to most of the JavaScript solutions I’ve tried, this feels straightforward, consistent and predictable.

Selects and File Inputs: Transparent Overlay + JavaScript

For more complex elements like <select> and <input type="file">, we can’t get by on CSS alone (though it gets us further than one might expect).

Our markup is similar to the previous set of checkbox/radio examples, except we won’t need a <label> for click events:

<div class="select">
  <select>
    <option>Option 1</option>
    <option>Option 2</option>
    <option>Option 3</option>
  </select>
  <span class="select-value" aria-hidden="true"></span>
</div>

Instead of hiding the <select> entirely, we want to position it over the rest of our element, allowing it to intercept click events and correctly position any dropdown it may display. Because this technique relies on JavaScript, we’ll qualify some of our selectors with .js (since you’re probably already using Modernizr).

.js .select {
  position: relative;
  /* default styles */
}
.js .select:hover {
  /* hover styles */
}
.js .select.focus {
  /* focus styles */
}
 
/* nicer default styles for "real" <select> */
.select select {
  cursor: pointer;
  display: block;
  width: 100%;
}
/* hide and overlay when JavaScript is enabled */
.js .select select {
  left: 0;
  height: 100%;
  min-height: 100%;
  min-width: 100%;
  opacity: 0;
  position: absolute;
  top: 0;
}

Already, this “works.” Options will display on click. But there are some problems. The value doesn’t update. There are no hover or focus styles. That’s where JavaScript comes in!

(Although I’ve chosen to write this in jQuery for the sake of readability, remember: You Might Not Need jQuery!)

// For each .select element
$('.select').each(function(){
  // Save some elements as variables
  var $element = $(this);
  var $select = $element.find('select');
  var $value = $element.find('.select-value');
  // Bind event handlers to <select>
  $select.on({
    // On change or keyup, update the value text
    'change keyup': function () {
      $value.text($select.val());
    },
    // On focus, add the focus class
    'focus': function () {
      $element.addClass('focus');
    },
    // On blur, remove the focus class
    'blur': function () {
      $element.removeClass('focus');
    }
  });
  // Trigger the change event so the value
  // is current
  $select.trigger('change');
});

Here’s how all of that comes together:

See the Pen Styled select by Tyler Sticka (@tylersticka) on CodePen.

With some tweaks, the same basic technique can also work for file inputs (assuming experimental WebKit/Blink features aren’t your thing):

See the Pen Styled file input by Tyler Sticka (@tylersticka) on CodePen.

This idea isn’t new. Peter-Paul Koch wrote about it quite a while back. Yet I rarely see it in use outside of a few large mobile frameworks. I’m honestly not sure why.

…and beyond?

What do all of these examples have in common? They don’t mess with the form element too much! By worrying less about customizing behavior and more on simply triggering it, we can indulge some of our designerly impulses without discarding all a given platform has to offer.

Consistency and functionality… no hair-pulling or teeth-gnashing required!

Update: September 8, 2014

A reader pointed out that the select example wasn’t responding to keyboard input in Firefox. I discovered that Firefox doesn’t fire the change event for selects like other browsers do, so I’ve updated the demo and example code so that it binds to both change and keyup.

I also learned that Firefox doesn’t show the full dropdown on any keypress, but this seems to be true of unstyled <select> elements as well. I encourage developers to use these examples as a starting point, and to augment usability shortcomings on a case-by-case basis if the default browser behavior isn’t cutting it.

Pixels are ruining my life

It’s been a strange few years for the pixel, that unit we love to hate and generally blithely use anyway.

First, there is the weird brain-bending device pixel versus CSS pixel math we’re all trying to do in our head since we started seeing a lot of high-density digital displays on the market.

Then there’s the whole schizophrenia in the standards worlds about what a pixel even is. Ask the W3C currently, and you’ll get a wholly incomprehensible definition (kind of fun as a drinking game/party laugh) that in the end claims "absolute unit." Ask the Mozilla Developer Network, and you’ll get a brief answer of "relative."1

The reference pixel is the visual angle of one pixel on a device with a pixel density of 96dpi and a distance from the reader of an arm’s length. For a nominal arm’s length of 28 inches, the visual angle is therefore about 0.0213 degrees. For reading at arm’s length, 1px thus corresponds to about 0.26 mm (1/96 inch). —Excerpt from the W3C definition of a reference pixel

And this all before we’ve even reached the lively world of viewports: layout viewports, visual viewports, viewport scales. And the different treatment by browsers of zooming—Webkit browsers don’t really scale pixel-based units after a zoom, Mozilla and Opera do. @ppk may understand pixels2, but I think he may be superhuman.

So, pixels may be relative or absolute, big or small, device-specific or theoretical. Here’s the rub at this point: I don’t care.

What’s a pixel? I don’t care

When I wrote the post about The Ems Have it (em-based media queries) a few weeks ago, I was mostly just focusing on the surgical problem of getting Webkit browsers to behave, when you get down to it. I spoke of practicalities: em-based media queries don’t break when you zoom.

But whether or not pixels ultimately do scale in Webkit browsers is beside the (deeper) point. If we’re staying true to a "content first" maxim, it follows, logically, that our media queries—as well as our layouts overall—might benefit by being subordinate to the content itself.

From my perspective, ems are more true to content.

For me, thinking in pixels for media queries ties me into some bad habits. I start thinking as if there is some 320 x 480px inviolable "mobile smartphone" reality that we can rely on. On the other hand, 30em is a readable column width regardless of the surrounding pixel complexities.

We’re moving further into a world where content is king, and we know it needs to "flow like water." The containers we build to hold it can likewise be based on the proportions of the content itself. Ideal line lengths, space to breathe around text—those are things most naturally derived by using units tied to the text itself. Ems.

The fact that baseline ems tend to be loosely tied to pixels, i.e.: 1em ~= 16px ~= 14pt should help control freaks to unclench a bit. But, as I’ve been arguing for a while now, that control is illusory anyway. Your content has already broken free of its jail cell. You just might not know it yet.

In his talk at Breaking Development Orlando, Ethan Marcotte (the Great Father of Responsive Web Design) mentioned his support for em-based media queries going forward. While he didn’t delve into the specifics of his reasoning, my hunch is that his motives are generally in line with this notion: content first.

So, I’ve done some of the convolutions. I’ve tried to understand exactly what a pixel is in a zoomed viewport on a pixel-dense device vis-a-vis its CSS-to-device pixel ratio. I’m done with that for now. Long live ems.


  1. Sitepoint also says relative. This may be an artifact of both MDN and Sitepoint referencing CSS2.1. This change doc appears to represent the switch between relative (2.1) and fixed (3). I dunno. I can’t really make a whole lot of sense of it.

  2. PPK "A Pixel is not a Pixel" (YouTube)

More on CSS Media Queries for Mobile

My previous post on CSS Media Queries kicked off quite a bit of conversation. I wanted to follow up on a few points that have been made and a couple of things I failed to communicate well in the original post.

CSS Media Queries are a Useful Tool for Mobile

One of the unfortunate side effects of the strident title I chose was that it gave many people the impression that I didn’t think CSS Media Queries were useful at all for mobile.

That’s not the case. We’re using them in two mobile projects right now and contemplating using them for a third.

I wrote in the post that “CSS media queries are a tool, but they are not a silver bullet.” But that point was overshadowed by the post title and the rest of the article talking about the problems that you need to be aware of when using them.

I got a chance to chat with Ethan Marcotte via Twitter. He wrote:

I think we agree on the fundamental points, honestly—the implementation should always be tailored to the site/audience.

I wholeheartedly agree. In fact, Ethan wrote in his article about Responsive Web Design:

That’s not to say there isn’t a business case for separate sites geared toward specific devices; for example, if the user goals for your mobile site are more limited in scope than its desktop equivalent, then serving different content to each might be the best approach.

In the same way in which my more nuanced opinion about media queries was skewed by my poor choice of title, I think Ethan’s nuanced opinion about when and how media queries can be used for mobile has been skewed by the enthusiasm that people had in response to his A List Apart article and how they might use the technique for mobile.

As I said in my post and reaffirmed to Ethan over Twitter, I’m actually quite excited about Responsive Web Design. I’m going to write more about that separately.

What I really meant to say was…

Even though Ethan never intended media queries to be seen as a total solution for mobile, that view has been enthusiastically adopted by others. I’ve read many blog posts and tweets on the topic. There was a session at Web Visions called Mobile Web Dev without Developing a Mobile Site based on building sites using media queries.

PPK got is right when he said that I “challenged the conventional view that media queries are all we need to make a website mobile-friendly.” There was a growing consensus that media queries were all that was needed and that consensus needed to be challenged.

In rereading my post, there is one sentence that I think best summarizes my view:

The way in which CSS media query has been promoted for mobile hides tough problems and gives developers a false promise of a simple solution for designing for multiple screens.

I’ve modified the sentence slightly to make it clearer that it was the way media queries were being promoted as a solution for mobile that was the real problem.

It is also clear that fool’s gold is not the right phrase. Fool’s gold is something that looks like something of worth, but in reality has no intrinsic value. Media queries do have value and are useful tools.

I’m sorry for poor title choice.

Great Ways to Use CSS Media Queries

There are a few great use cases for media queries for mobile. I highlighted selected web apps and html emails in my previous email. A few others are:

  • As PPK suggests, pairing media queries with javascript could be the core of a mobile web solution. The javascript can be used to swap the correct images in for each context. This is most effective if you start from a mobile design and use media queries and javascript to add functionality for desktop users. You also need to understand which devices your customers are using to make sure this technique works for those browsers.
  • As Pim Derks commented on my post, in situations where “a client has a limited budget, but wants his site to look good on iPhone.” Given the alternative of no mobile web site, it makes sense. I’d suggest looking to see what you can do to stop unnecessary downloads where possible.
  • And the most likely use of media queries, as a small part of a larger mobile optimization effort or a discrete tool being used in one off situations like web apps or html emails.

You’ll notice that the solution that PPK suggests is quite a bit different than starting from the desktop web and simply adding media queries.

It requires images to be uploaded in multiple sizes. For optimal use, it requires html to be retooled to start with mobile web appropriate html only and then javascript to enhance it.

It is entirely possible that a great mobile solution could be built that way. I question the likelihood that web sites are going to be retooled to deliver mobile html first and then progressively enhanced with javascript and css. But I’d be happy to be wrong about that.

What are the Tough Problems that Discussion of Media Queries Obscures?

I’ve enumerated many of the technical challenges with media queries, but when I talk about media queries hiding tough problems, I’m not talking about any of the issues I raised in my previous post.

What I was referring to was the idea that there was a simple solution to creating a mobile web site obscures a series of infrastructure issues that I believe web developers are going to be confronting over the next few years.

Let’s assume for a moment that there are situations in which you need to deliver different html and associated assets to different mobile devices. To do so requires that your content management or ecommerce system is equipped to do the following:

  • Detect different devices and the capabilities of those devices.
  • Select the correct template based on the device. This implies that your system gracefully handles multiple templates.
  • Separate assets added by authors from the words that they write so that those photos, video, etc. can be resized and reformatted appropriately for the device.
  • Provide tools or establish processes for resizing images and videos. Either manually, or better yet automatically, encode video in multiple formats based on the device.
  • Support non-web consumption of content (e.g., native applications). This will likely require further consideration of how to remove markup and presentation from content.

And many more obstacles created by legacy web publishing tools designed long before we started thinking seriously about mobile.

The big challenges our clients face are rethinking and retooling their infrastructure for mobile. It’s going to be a massive undertaking for a lot of businesses.

The sooner we realize this fact, the sooner we can get to work figuring out the best ways to build that infrastructure.