Displaying different text content based on viewport size

When building a responsive app one often comes across the situation where it is no longer viable to display all the text on mobile, that is displayed on a big screen. This especially occurs with things like buttons.

I have usually used media queries to display one text and hide the other. However, there are a bunch of downsides to it.

Recently I noticed the ember responsive addon, which is quite nice as one can decide which text to display using a simple if handlebars statement. However, I noticed a big downside: It does not work in fastboot, as the executed js can not know about the viewport size.

I now came across this solution, which basically adds the alternate text to the html element:

<div class="day" data-abbr="sun">
   <span>Sunday</span>
</div>
@media screen and (max-width: 500px) {
    /* Add a pseudo element with the 
       text from attribute 'data-abbr' */
    .day[data-abbr]::after { 
        content: attr(data-abbr); 
    }
    
    /* Hide the original label */
    .day > span { display: none; }
}

The nice thing about it is, that there is no way one can accidentally display both texts by making an error in the media query and the content is kept in an easily understandable format.

However, I wanted to ask if anyone has come across a better solution to solve this issue, which also is compatible with fastboot?

Yeah, for the reasons you’re describing I like solutions that are based on real browser media queries.

If you want a block-based API more like what you’d write with ember-responsive, but powered by browser media queries so it works in fastboot, you could package up some media queries as components. Named blocks works nice for this:

<Breakpoints>
  <:large>This is the large content</:large>
  <:medium>Getting smaller</:medium>
  <:small>Smallest</:small>
</Breakpoints>

could be implemented like:

{{! components/breakpoints.hbs }}
<style>
  .large, .medium, .small {
    display: none;
  }
  @media (min-width: 1200px) {
    .large {
      display: block;
    }
  }
  @media (min-width: 800px) and (max-width: 1200px) {
    .medium {
      display: block;
    }
  }
  @media (max-width: 800px) {
    .small {
      display: block;
    }
  }
</style>

<div class="large" ...attributes>
  {{yield to="large"}}
</div>

<div class="medium" ...attributes>
  {{yield to="medium"}}
</div>

<div class="small" ...attributes>
  {{yield to="small"}}
</div>

The above is just a sketch, although it does work. Probably you’d want to come up with more realistic rules and use has-block to do a more automatic sensible thing when you don’t want to repeat the same content at multiple breakpoints.

Note: named blocks is a new feature in ember 3.25, but you can add the polyfill to use it right away.

2 Likes

Thank you. That’s a nice idea.

The thing I quite like about putting the alternate text into an attribute of the html element, is that I don’t need to necessarily add html elements just in order to differentiate different viewport sizes. Usually I should be able to put that into the parent element.

Unfortunately named blocks don’t support things like this, so the short name will need to go into a parameter of the component.

This throws an error:

<span local-class="name" data-abbr="{{yield to="shortName"}}">