Viewport Unit Based Typography vs. Safari

font-size-vw-tamed

A common thing to do regarding font-sizing is to use Viewport Unit Based Typography, nowadays often combined with CSS min() or clamp():

:root {
  font-size: min(calc(1em + 1vw), 4em);
}

However, as Sara Soueidan details, Safari doesn’t co-operate here:

In Safari on macOS, the fluid text wasn’t really fluid—resizing the viewport did nothing to the font size, even though the latter is supposed to respond to the change in viewport width.

It’s a bug, slated to be fixed in the next version of Safari (Safari TP already has the fix). In the meantime there’s an easy workaround we can use.

More details + demo on Sara’s blog.

Working around the viewport-based fluid typography bug in Safari →

Re-reading that Viewport Unit Based Typography post from 2016 I now see that it also mentions that Safari doesn’t play nice with it. Let this underline the importance of filing bugs: because Sara filed a bug the Safari team came to know about the bug and fixed it (very fast too).

The new responsive: Web design in a component-driven world

In this session from Google I/O 2021, Una Kravets talks about “the new responsive”, short for being responsive to the user, container, and form-factor (text-version available via link below):

The web community is entering into a new era of responsive design and shifting our perspectives on what it means. With user preference queries, container queries, and other form-factor queries on the horizon, we’ll soon have the tools to create responsive designs far beyond what querying the global viewport allows.

To me, this post is the perfect successor to A List Apart’s A Dao of Web Design and Responsive Web Design. The timing is only off by one year …

The new responsive: Web design in a component-driven world →

Responsive Images the Simple Way

The logic behind displaying an image responsively is complicated. It involves determining how large the image will be displayed, as well as understanding whether the user is on a high-resolution display, among other things. Thankfully, the browser is better equipped than we are to handle this logic. All we need to do is give it some hints. We’ll use the srcset attribute to provide a list of image assets to choose from, and the sizes attribute to tell the browser how large the image will display at various breakpoints.

Yes, the syntax is still the same as in 2014, but it’s good to be remembered of it … I always find myself looking things up again when it comes to Responsive Images 😬

Responsive Images the Simple Way →

Responsive UIs in React Native

On the web it is – by now – obvious that you make your website responsive (*). Using a listener listening to the change event of the Dimensions API, it’s also possible to implement this kind of behaviour in React Native.

import {Component} from "react";
import {Dimensions} from "react-native";

export default class LogDimensionChanges extends Component {
    state = Dimensions.get("window");
    handler = dims => this.setState(dims);

    componentWillMount() {
        Dimensions.addEventListener("change", this.handler);
    }

    componentWillUnmount() {
      // Important to stop updating state after unmount
      Dimensions.removeEventListener("change", this.handler);
    }

    render() {
        const {width, height} = this.state.window;
        const mode = height > width ? "portrait" : "landscape";
        console.log(`New dimensions ${width}x${height} (${mode})`);
        return null;
    }
}

This logic is applied into the react-native-responsive-ui package, which provides you with a <MediaQuery /> component, ResponsiveStyleSheet class, etc.:

import React, {Component} from "react";
import {View} from "react-native";
import {MediaQuery} from "react-native-responsive-ui";

export default class Login extends Component {
    render(): React$Element<*> {
        return <View>
            <MediaQuery minHeight={450} orientation="portrait">
                <Logo />
            </MediaQuery>
        </View>;
    }
}

Responsive UIs in React Native →
react-native-responsive-ui

(*) I know, this site still uses a non-responsive WordPress theme … shame on me

Responsive Components: a Solution to the Container Queries Problem

Extensive writeup by Philip Walton on how he tackles the Container Queries problem.

Instead of narrowly focusing on the specific CSS feature proposal we call “container queries”, I want to focus on the broader concept of building components that respond to their environment. And if you accept this larger framing, there are actually new web APIs that already let you achieve this.

That’s right, we don’t need to wait for container queries to start building responsive components. We can start building them now!

His result takes about the same approach as Elementary takes, but then using the more modern ResizeObserver.

Must say I’m leaning more towards Elementary though, as:

  • Elementary targets the responsive elements themselves, and not their parent element.
  • Elementary defines the breakpoints in the CSS itself and not the HTML (something Philip points out too).
  • Philip’s solutions relies on ResizeObserver which is only available in Chrome right now.

Responsive Components: a Solution to the Container Queries Problem →

Responsive Typography

Mike Riethmuller:

It is possible to have precise control over responsive typography. Using calc() and viewport units you can create fluid type that scales perfectly between specific pixel values, within a specific viewport range.

The formula used is this one:

@media (min-width: #{$min_width}px) and (max-width: #{$max_width}px) {
    font-size: calc(#{$min_font}px + (#{$max_font} - #{$min_font}) * ( (100vw - #{$min_width}px) / ( #{$max_width} - #{$min_width})));
}

As 100vw resembles 100% of the viewport width, the font-size will adjust along with it (between the given min_width and max_width).

Looking for a more simple version, that only enforces a minimum font-size which isn’t limited by a given max_width? This way more simple viewport based typography method has got you covered.

It’s possible to also adjust the line-height, using the same formula. The full code then becomes:

// CONFIG
$min_width: 25;
$max_width: 50;

$min_font: 1;
$min_lineheight: 1.35;
$max_font: 1.2;
$max_lineheight: 1.8;

// DEFAULT (LOWER THAN MIN-WIDTH): USE MIN FONT-SIZE AND MIN LINEHEIGHT
:root {
  font-size: #{$min_font}em;
  line-height: #{$min_lineheight}em;
}

// BETWEEN MIN-WIDTH AND MAX-WIDTH: CALCULATE VALUES USING THE VARIANT 100VW
@media (min-width: #{$min_width}em) and (max-width: #{$max_width}em) {
  :root { 
    font-size: calc(#{$min_font}em + (#{$max_font} - #{$min_font}) * ( (100vw - #{$min_width}em) / ( #{$max_width} - #{$min_width})));
    line-height: calc(#{$min_lineheight}em + (#{$max_lineheight} - #{$min_lineheight}) * ( (100vw - #{$min_width}em) / ( #{$max_width} - #{$min_width})));
  }
}

// GREATER THAN MAX-WIDTH: USE MAX FONT-SIZE AND MAX LINEHEIGHT
@media (min-width: #{$max_width}em) {
  :root { 
    font-size: #{$max_font}em;
    line-height: #{$max_lineheight}em;
  }
}

If you’re looking for the Stylus variant (which is my preferred CSS Preprocessor), here’s one I’ve knocked up:

// CONFIG
$min_width = 10;
$max_width = 100;

$min_font = 1;
$min_lineheight = 1.35;
$max_font = 1.2;
$max_lineheight = 1.8;

// DEFAULT (LOWER THAN MIN-WIDTH) USE MIN FONT-SIZE AND MIN LINEHEIGHT
:root
  font-size unit($min_font, "em")
  line-height unit($min_lineheight, "em")


  // BETWEEN MIN-WIDTH AND MAX-WIDTH CALCULATE VALUES USING THE VARIANT 100VW
  @media (min-width: unit($min_width, "em")) and (max-width: unit($max_width, "em"))
    font-size "calc(%s + (%s - %s) * ((100vw - %s) / (%s - %s)))" % (unit($min_font, "em") $max_font $min_font unit($min_width, "em") $max_width $min_width)
    line-height "calc(%s + (%s - %s) * ((100vw - %s) / (%s - %s)))" % (unit($min_lineheight, "em") $max_lineheight $min_lineheight unit($min_width, "em") $max_width $min_width)

  // GREATER THAN MAX-WIDTH USE MAX FONT-SIZE AND MAX LINEHEIGHT
  @media (min-width: unit($max_width, "em"))
    font-size unit($max_font, "em")
    line-height unit($max_lineheight, "em")

Precise control over responsive typography →
Molten Leading in CSS →

Coding mobile-first emails

1-tVdHVHlw8RJY7cOy4DNwLQ

Typically, emails are coded starting with an old school, table based desktop version, with mobile styles applied through a max-width media query to reflow the tables. In email clients that don’t support this, this approach can result in inconsistent rendering and difficult to read emails.

We’re going to flip the formula and start with the mobile version first instead, then work our way back to the desktop version.

Great resource!

Coding mobile-first emails →

Mediaqueryless Responsiveness

Slides of the – highly entertaining – talk @Vasilis gave at CSS Day 2016 in which he elaborated on a few techniques he experimented with in order to get responsive-like sites without using any media queries.

Some neat tricks include:

  • Calling it “active whitespace” instead of floats getting stacked up 😛
  • Setting a unit-ed value (such as 15em) instead of a plain number as a value for columns
  • Using an URL fragment (window.location.hash) along with an id along with the :target psuedo-class
  • Using vmin and vmax values (in combination with quantity selectors)

iOS9 MobileSafari Viewport Problem

CQe0DfnUwAAqdG7

The viewport is set incorrectly when the viewport meta tag is specified with initial-scale=1 or width=device-width, and the page contains an element (e.g. div tag) that is wider than the desired viewport’s boundary.

In the screenshot above (courtesy @RWD) you can see that the off-screen menu actually appears on-screen in iOS9. Apple changed how iOS9 responds to width=device-width as it, according to them, got abused too much.

To fix this, append shrink-to-fit=no to your viewport meta tag, as such:

<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">