A. M. Douglas

Some CSS Pointers

If you're a regular reader of articles in web development, you've probably seen a lot of literature being generated about the topic of developing client-side, single page applications using React.js (and all the baggage it more or less requires to be a good idea) and the shift away from CSS and toward attribute styles in JSX, in order to create discrete components.

This is not one of those articles. Nope, this is just a humble list of CSS gotchas that can result in noticeably poor perceived performance on your website—even if you don't use any JavaScript at all, complex and poorly planned visual effects composed with CSS3 transitions, animations and properties can cause a very real drop in framerate, which is ultimately the same complaint many users have with heavy JavaScript applications. Client-side apps use significant abstractions on vanilla JavaScript objects/methods in order to make the developer's life easier and to make a more fully rounded product—at the expense of operations per second and thence, perceived frames per second.

Don't use 'background-attachment: fixed'

I've seen background-attachment: fixed many times, usually where a web developer wanted to create a pseudo-parallax scrolling effect with no JavaScript involvement, due to the performance issues involved with true parallax scrolling, only to drop frames due to this ill-advised approach to CSS.

The problem is that background-attachment: fixed causes the browser to repaint on every scroll, which is damned expensive. You can watch your silky 60fps slashed by 75% even on a laptop because there is no simple way to get the GPU involved in processing this more complex visual effect.

Its use is not the crime, however. It's a nice effect and effortlessly nice to look at in many cases. The crime is not using the hardware-accelerated and simple alternative: position: fixed. Or, to put it more comprehensively:

            
.parallax-bg
  {
    position:fixed;
    top:0;
    left:0;
    right:0;
    bottom:0;
    will-change:transform;
    z-index:-1
  }
            
          

That's pretty much it. will-change creates a new compositing layer and gets the GPU to step up a gear, giving you silky smooth performance again. will-change is a standard property and not specific to any browser, but obviously that does not mean that it is implemented everywhere yet.

For those cases, like Safari (excluding 9.1 and above) and obviously IE, the GPU can be levied by adding transform: translateZ(0) which is a well known workaround, but this old approach presents a risk to performance if abused, especially on mobile devices which have less memory to play with. Scrolling past these elements can be smooth, but the elements themselves might look a little rough—it has been recommended to add backface-visibility: hidden and perspective: 1000 to try to mitigate this. On the whole, though, the old method does precisely the same thing as will-change—translates an element in dimension Z by 0𝑛 where 𝓷 is some unit like px or %, thereby preparing the element for GPU accelerated movement. Obviously some details will be specific to your use case: you may wish to define a height as a percentage of the viewport with vh and so on.

Responsive squares

Yes, it's funny, but creating things that are perfectly square in all viewports can seem challenging at first. You can imagine the problem: you want to display a grid of items—perhaps photographs—and, upon being floated, those elements lose their height.

Now, sure, if you supply square images, it's not a problem—max-width:100%;height:auto and you're more or less done; but what if you're making a real website, for real people, who do not have a process for photographic content on the web, who do not have you or your grid's ergonomics in mind.

Obviously, you'd use background-image and background-size:cover. That solves the responsive image issue—now any image will fit your containing element. Except now your photo has no height again, and it'd be understandably quite difficult to construct a square without a value for 𝑦. Sure, floated elements can at least be assigned a min-height to prevent this, but you'll end up with inconsistent heights— and we all know what happens in a traditional float-based grid when you just throw elements of different heights together (I discuss this in my previous post You Might Not Need Masonry).

One way some misguided developers try to achieve height equivalence is to use a min-height or height that is all but guaranteed to exceed the content the element will contain. This can be seen in many implementations of “card” design patterns, though the flexible box model offers a more reliable approach. But sometimes, you really need to display a square.

The correct (and by correct, I mean reliable) way to achieve this is to float your grid items and add a child element with a total vertical padding of 100% and no height or content. You can see this CSS technique demonstrated here.

Users of this technique, or more complex variants of it, include Instagram and the BBC.

Don't use inline-block

There is no justification for using inline-block. It's quite possibly the most useless thing in your CSS toolkit that you could ever be tempted to use. There was once an argument for its use over float in grid systems, if you were willing to hack your way around the white space problem, because inline-block elements behave like flex-flow:row wrap with better browser support.

However, setting your font-size to zero, eliminating white space in one particular part of your HTML, or not closing your HTML tags, are not exemplary practices in terms of maintaining clean code. After temporarily daring to use flexbox in a couple of small projects, I have concluded that the United Kingdom is not ready for it, and so I continue to use float based grid systems for my work, though I at least include calc with a percentage fallback for my own satisfaction. And float works very nicely for the most part, but there's one troublesome region of the typical web page where float sometimes doesn't cut it: the navigation bar.

Centering without flexbox

Navigation bars are pretty straightforward for your average website, but sometimes you get fed a design which just happens to stick a logo or main menu smack bang in the middle of said navigation bar. But you don't need to fear, you're a worldly front-ender, it's easy. Just use margin:0 auto and you'll be fine.

Oh dear. It looks like the design calls for social media icons on the left, and something else even dafter on the right. So you can either float those left and right respectively and then center the logo—or you could just use your grid system for a trio of columns in the navigation bar. Which will work great, except perhaps you want to vertically align these things as well. Not out of the woods yet. Some might say that you should use the following method:

            
.navbar
  {
    position:relative
  }

.valigned
  {
    position:absolute;
    top:50%;
    transform:translateY(-50%)
  }
            
          

Sure, it'll work, but I recommend caution, especially if you need to support IE8.

If you need to support antiquated browsers, you should use display:table and display:table-cell which gives you the vertical alignment powers of those <table> elements that most of us don't have to think about much any more (as an email coder as well as a web developer, I unfortunately have to deal with table elements every week—I do not think it is an activity for people who happen to possess souls).

You might be wondering how the hell you can make a table-navbar responsive. It's very simple actually: let your elements start as block elements floated left and then above a minimum width adjust their display property to table/table-cell.

background: url(video.webm) 50% / cover;

Nope, I'm sorry, this is not something newly implemented and I do not today have the pleasure of unveiling this amazing leap forward in CSS. But I can show you how to achieve the same effect:

            
.bg-video
  {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    min-width: 100%;
    min-height: 100%;
    width: auto;
    height: auto;
    z-index: -1
  }