Chapter 7. Embrace the Future

Web developers reading about new and exciting specifications often plaintively ask, “But what about old browsers?” In this chapter, we’ll survey the modern browser landscape and the ways in which CSS itself is developing methods to help us embrace new technology without leaving old browsers out in the cold.

Test Your Assumptions with Data

In Chapter 2, I described how the concept of evergreen browsers is changing the way we think about browser support. Our users are increasingly likely to receive regular browser updates. Depending on the audience for the sites you work on, you may find that new CSS becomes usable far faster than you might expect.

It’s all too easy to make assumptions about browser support based on something we knew to be true ten years ago. If you’re starting a new project now, test those assumptions. If this is a redesign, look at the analytics for the site. Which browser versions are people using? Crucially, which features do those browsers support? You may be surprised, and that data can help you plan your implementation.

You can import Google Analytics data into caniuse.com (http://bkaprt.com/ncl/07-01/) to see how your data weighs up against global or local data (Fig 7.1).

Figure

Fig 7.1: caniuse.com shows that visitors to my personal website have better-than-average support for flexbox.

If you don’t have an existing site to mine data from, look at the global or local statistics and then combine that with your knowledge of the audience for the website. There are certain markets where you find higher usage of older browsers, just as there are places where you will find your audience skewed in terms of newer browsers. Do your research and find out where your project fits.

Check mobile support separately

It’s a good idea to separate out the statistics for mobile devices and desktops. You may find that the mobile devices typically accessing the site have far better support for new features than desktop computers. This may mean you can use newer features to assist in creating a better and more performant site for your mobile visitors, even if you need to use older methods in desktop-focused CSS.

Convincing your client or boss

This is all very well, you may be thinking, but my client expects the site to look identical in these older browsers. My suggestion is to move the conversation away from “looks the same” to talk about development more holistically. The way the site “looks” is just one aspect of a site; it just so happens that it’s the easiest for the client to understand, so they naturally focus on it. By helping them understand that there are lots of elements at play and several trade-offs to be made, you can help them become more informed about the full picture. It’s also worth digging into why they are focused on the site “looking the same.” What is their underlying concern?

Perhaps your client is concerned about search engines. Can they access the site? In response, you can talk about how modern search engines care about performance and mobile-friendliness. Newer layout methods can assist in making a search-engine-friendly site.

Or maybe your client worries that their brand identity will get lost in a version of the site tailored to less capable browsers. Some concrete examples may help illustrate how you would make sure users running older browsers will still get a consistent experience of your client’s brand and visual style. Here, you can draw parallels with responsive design. A site viewed on a phone differs from the same site viewed on the desktop, yet it still conveys the appropriate identity and visual style—tailored for the way it is being viewed. Older browsers are limited to some extent, but can nevertheless be provided with a good experience that will work well with their constraints.

Your client may also be very budget-conscious. If that’s the case, you can talk about how newer methods are faster in development and likely to create a site that is more future-proof; or how they could spend more money to get a site that is identical in IE9 and modern browsers, but that the money might be better spent on advertising or adding some features that will help more visitors convert. Help them see your advice as being focused on protecting their budget.

Perhaps the client has had a bad experience in the past, with customers complaining that the site doesn’t work for them. Put their mind at ease by explaining how, by serving a simpler layout to older browsers, they are less likely to run into these issues. Visitors with older browsers will get a fast and performant website, tailored to the device they have. That’s a far better proposition than trying to somehow create a modern experience using old technology, something that is more likely to cause them problems.

If you’ve already done your research, you’ll have data to back this up. You can show figures and compare those to other decisions the client makes that also potentially exclude sections of the audience from the “full” experience. The client can then start to understand that the way the site “looks” is not the full story, and you can work together to make sure the site meets the goals of the business.

Progressive Enhancement with CSS Feature Queries

You’ve looked at the data, you’ve argued the case for browser support to your client, and you’ve come to the decision that it makes sense to use features of CSS Grid Layout in your project. How should you go about ensuring that the percentage of users who do not have Grid Layout support can use the site, too?

CSS provides an answer to this question in the shape of feature queries. Feature queries are part of the CSS Conditional Rules Module (http://bkaprt.com/ncl/07-02/), the module that also includes media queries. If you’ve ever used a media query, feature queries will seem very familiar.

Feature queries are created by using the @supports rule, just as media queries use @media. When we use a feature query, rather than testing for support of a screen size or type of media, we test for support of a CSS feature. The basic syntax is as follows:

@supports (display: grid) {
  // code only for browsers that support CSS Grid layout
  .container {
	display: grid;
  }
}

We start with @supports; then, inside the brackets, we add the property and value we want to test for. Note that this works for prefixed properties, too. To check to see if the browser supports the legacy Internet Explorer implementation (which would give you current Edge browsers), you could use this:

@supports (display: -ms-grid) { }

You can test for multiple properties and values. For example, to test for support for either the modern CSS Grid specification or the earlier one in Edge, use the following:

@supports (display: grid) or (display: -ms-grid) { }

You could look for a browser that supports more than one feature:

@supports (display: grid) and (shape-outside: circle(50%)) { }

All of our modern browsers support feature queries, which means you can use them to detect and then write code for any new feature that lands in CSS from this point on. That code will be safely tucked away inside your @supports rule, so it won’t be executed by browsers that don’t have support—they won’t understand the rule and therefore will throw the CSS away.

The approach to take with feature queries is to layer on support in a progressively enhanced way. Write CSS for the simplest case, for the browsers with no support. Then layer on features, wrapping that code in a feature query. You’ll need to do some overwriting of earlier code inside those feature queries; because of the way CSS works, however, overwriting earlier layout methods for Grid and flexbox is easier than you might think.

Do you need to use a feature query at all?

Before using a feature query, check to see whether you need to use one. In CSS, if a browser doesn’t understand a feature, it simply throws the CSS away. This means that a lot of progressive enhancement involves writing old CSS, then writing the new CSS afterward, exploiting the fact that later CSS will overwrite earlier CSS in your stylesheet.

Feature queries are necessary whenever you want to include CSS to go along with the Grid or flexbox display—for example, decoration that only makes sense when an item is a grid item. In such cases, you’ll want to wrap the CSS in a feature query to prevent anything in that block from being executed. You might also use a feature query to overwrite something used as styling for older browsers that is either not necessary or would badly interact with the display when used in conjunction with the new CSS. The next few examples will examine both cases.

Overwriting floats

The specifications detail how flexbox and Grid interact with other layout methods. For both flexbox and Grid, the specification explains that float and clear have no effect on a flex or Grid item. This means that if you float an item, then make it a flex or Grid item, the float will have no effect.

In my next example, I have a set of floated items. The layout they create will work for all browsers, but has the issues that we explored in Chapter 1: uneven amounts of content can break the layout.

In addition to the float CSS, I’ve added rules that make the ul a flex container and assign the flex properties to the list items:

.cards {

  display: flex;
  flex-wrap: wrap;
}
.cards li {
  /* float for older browsers */
  float: left;
  width: calc(33.333333333% - 20px);
  /* flex for newer ones*/
  flex: 1 1 auto;
}

Code example: http://bkaprt.com/ncl/07-03/

If I want the flex-basis to use the width set on the item for the floated layout, I can set flex-basis to auto. In the previous example, flex-grow is set to 1, so items can grow and shrink from that flex-basis. If two items are on the last row, they split the space (Fig 7.2).

You can make flexbox use the width and not grow from that percentage by setting the flex-grow value to 0 and keeping the flex-basis as auto, in which case the width used on the item will be the value of the width property. Alternatively, you can override the width by setting the flex-basis to something else, such as 0. You don’t need to use any feature queries in this scenario, since older browsers ignore the flexbox rules; if a browser does use the flexbox rules, these override the float.

If we do the same thing with Grid Layout, we define our grid on the container element as a flexible grid with a flexible number of column tracks, each set to 1fr. We don’t need to define anything on the grid items.

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

Figure

Fig 7.2: Items can grow and shrink from a flex-basis of 33.333333333% - 20px.

But there’s a problem. While older browsers will ignore the Grid rules, newer browsers that do support Grid will also honor the width we’ve set on the individual items (Fig 7.3).

Figure

Fig 7.3: The width set on individual items is causing them to become 33.333333333% - 20px of the grid cell.

This is precisely the sort of scenario that might prompt us to reach for a feature query. If we reset the width for our items to auto, the grid layout will work as expected. But we don’t want that width to be used for non-supporting browsers. To make sure it won’t apply to older browsers, we can wrap that rule in a feature query:

@supports (display: grid) {
  .cards li {
    width: auto;
  }
}

Code example: http://bkaprt.com/ncl/07-04/

Resetting widths is one of the most common things you will do when creating layouts that work for old and new browsers. Rarely will you need to write two completely different sets of CSS. A lot of the styling of components is the same in both cases; a good amount of the overwriting is done simply by dint of the way CSS works, and the additional rules inside feature queries are there only to adjust small things for the supporting browsers.

Overwriting display: inline-block

In Chapter 1, we looked at some of the other methods we used to create multiple column layouts in browsers prior to flexbox and Grid. We used display: inline-block and display: table. How do these methods behave if we then override them with flex and Grid?

The good news: they behave in pretty much the same way as our floated example.

Let’s revisit the inline-block example from Chapter 1 and add flexbox properties to the container and child items. In browsers that support flexbox, the child items become flex items, which negates the inline-block behavior—as you can see if you reintroduce white space between the elements. The layout doesn’t break, as it did when we tried to use inline-block to create a neat grid in Chapter 1.

.cards {
  display: flex;
  flex-wrap: wrap;
}
.cards li {
  display: inline-block;
  vertical-align: top;
  width: calc(33.333333333% - 20px);
  flex: 1 1 auto;
}

Code example: http://bkaprt.com/ncl/07-05/

Note that the specification explains that vertical-align has no effect on flex and Grid items, so this property will not cause a conflict with any alignment properties set to work with flexbox or Grid.

If you perform this override using CSS Grid Layout, it will exhibit the same issue as the floated example above, and you will need to override the width set on the element to prevent issues with your grid.

Overwriting display: table

For display: table, how much overwriting we need to do depends on the properties we’ve used. However, the specification details what happens when an item is set to display: table-cell and later the parent is set to display: grid.

When we use table properties on things that are not tables, we would quite often use display: table-cell on the item itself, without adding any other table properties. As we discovered in Chapter 1, this is one way to create full-height columns, or centering on both axes in browsers, right back to IE8. When doing this, we may not add an element to represent the table row or table itself. A real HTML table does not just contain a td in isolation—it requires a tr and table element to wrap the cells; these elements are necessary for browsers to display a table correctly. For this reason, anonymous elements are created. These fix up the DOM tree, ensuring that our cell has a virtual row and table to display inside. For developers, this behavior is transparent. But what happens if your item set as a table cell becomes a grid item when the parent has display: grid?

Thankfully, the specification has you covered. In the next example, I have a three-column layout that uses display: table-cell on the individual columns to enable the columns to have equal height visually. I also use the vertical-align property to align the table cells, as we can use this alignment method when in a table layout.

.cards {
            margin: 0;
            padding: 0;
            list-style: none;
            border-spacing: 20px;
}
        .cards li {
            display: table-cell; 
            vertical-align: top;  
            padding: 10px;
            border-radius: 5px;
        }

Code example: http://bkaprt.com/ncl/07-06/

I then add display: grid to the parent. In a supporting browser, the grid items are blockified, transformed into block elements and not table-cell elements. This transformation happens before the anonymous boxes are created. The items then become grid items. Because the blockification happens before the items become table cells, we get no anonymous boxes created to wrap the items, so our two child elements become two separate grid items. We don’t need to worry about isolating the table and grid code from browsers.

.cards {
            margin: 0;
            padding: 0;
            list-style: none;
            border-spacing: 20px;
            display: grid;
            grid-template-columns: repeat(3,1fr);
            grid-gap: 20px;
        }

In this scenario, we only need to wrap code in a feature query with @supports if we have something that applies to both grid-supporting and non-grid-supporting browsers. In the table layout, we might use border-spacing to space out the items, which also adds space around the wrapper. For the grid layout, we could replace that by using a margin wrapped in a feature query (Fig 7.4).

@supports(display: grid) {
  .cards {
  margin: 20px;
  }
}

Figure

Fig 7.4: Overwriting display: table-cell with Grid Layout.

A Final Note on Browser Support

Even though you may need to provide a very high level of design consistency for older browsers, don’t assume that these newer methods are totally out of reach. Instead of thinking about using them for full-page layout, ask yourself how you might use them to enhance smaller UI elements. Or consider whether your mobile browser profiles enable more use in those small-screen views of your content.

You might also explore using Grid Layout during a prototyping phase. Even if you need to go back and rebuild some elements using older methods once decisions have been made, Grid makes it very easy to play around with how elements will work at various breakpoints. Using it to prototype can help you to really get to grips with the specification, even if business requirements mean it is too early to fully adopt right now.

This book has aimed to explain our newer layout methods, how they fit together, and how you can start using them in your work today. Before I leave you to do that, I’d like to encourage you to participate in the future of CSS. Let’s take a look at how to keep up to date with CSS, and how to get involved with pushing it forward.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset