Developer News

Haunted: Hooks for Web Components

Css Tricks - Wed, 07/03/2019 - 4:36am

I was just chatting with Dave and he told me about Haunted. It's hooks, but for native web components! Pretty cool. I think the existence of stuff like this makes using web components more and more palatable — particularly in that totally-native no-build-step-needed-at-all kinda way.

I get that there are all sorts of issues with web components, but the things that typically turn me away from them are a lack of nice templating and rerendering and no state management.

But we can knock those two out right quick these days...

First, making a component like <my-app> is perfectly comfortable:

import { html } from "https://unpkg.com/lit-html/lit-html.js"; import { component } from "https://unpkg.com/haunted/haunted.js"; function App() { return html` <div class="module"> Hello, World! </div> `; } customElements.define("my-app", component(App));

Then we could add some state with hooks:

import { html } from "https://unpkg.com/lit-html/lit-html.js"; import { component, useState} from "https://unpkg.com/haunted/haunted.js"; function App() { const [name, setName] = useState("Chris"); return html` <div class="module"> Hello, ${name}! </div> `; } customElements.define("my-app", component(App));

The CodePen Challenge this week is using the Star Wars API, so let's make a fetch request and use that to fill state. That's a great use case for useEffect.

import { html } from "https://unpkg.com/lit-html/lit-html.js"; import { component, useState, useEffect } from "https://unpkg.com/haunted/haunted.js"; function App() { const [planets, setPlanets] = useState([]); useEffect(() => { fetch('https://swapi.co/api/planets/?page=2') .then(response => { return response.json(); }) .then(data => { let planets = data.results; // remove ones with no diameters planets = planets.filter(planet => planet.diameter !== "0"); setPlanets(planets); }); }, []); return html` <style> /* Shadow DOM styles */ </style> <div class="all-planets"> ${planets.map(planet => html` <div class="planet" style="--dia: ${planet.diameter}px"> <span class="planet-name"> ${planet.name} </span> </div> `)} </div> `; } customElements.define("my-app", component(App));

That's a proper little web component!

See the Pen
Star Wars API with Haunted.js
by Chris Coyier (@chriscoyier)
on CodePen.

The post Haunted: Hooks for Web Components appeared first on CSS-Tricks.

Graphical User Interfaces for Git

Css Tricks - Tue, 07/02/2019 - 12:41pm

Git is command-line-driven software, but that doesn't mean you have to use the command line to make it work. There are lots of options! Some of the deepest programmer nerds I know prefer to use GUIs for Git (Graphic
User Interface, or you know, software you can see things and click stuff), and some near pure-designers I know prefer working with the command line for Git. Swear to Git.

Lemme round up what look like the major players for Git GUIs these days.

No matter how much you love the CLI, don't GUI-shame. Lots of perfectly amazing programmers like working with GUIs, and it's perfectly fine.

There's some weird gatekeeping tendencies centered around the command line. #DevDiscuss

— Ben Halpern &#x1f917; (@bendhalpern) November 28, 2018

Tower

I've used Tower for ages and it's the one used the most. I'm not sure the exact release dates of all these, but I feel like Tower was an early player here. They've been around a long time and continuously improve, which I always respect.



Fork

It's free and actively developed, incredibly.



GitHub Desktop

This is a 2.0 of the original GitHub Desktop. I had some gripes with the 1.0 version in that its terminology was weird (to me) and seemed to vastly deviate from Git, which was more confusing than it was worth (again, to me). This version cleans most of that up. It's deeply integrated into GitHub so it makes GitHubb-y things (e.g. pull requests) feel like first-class citizens, but it will still happily work with any Git repo.



GitKraken

I'm pretty intrigued by this one. Upgrading (monthly cost) to get the in-app merge conflict tool seems worth it, but you also have to upgrade to access private repos. It seems highly feature rich, but I think my favorite part is the dark-with-rainbow-accent-colors theme.



Sourcetree

You might be compelled by Sourcetree if you're a big Bitbucket user because they are both Atlassian products. I know it works for any Git repo though. I imagine there is some smooth Bitbucket integration stuff with this, similar to the GitHub/GitHub Desktop connection.



Coda

You don't really think of Coda as a version control tool (it's more of a direct-to-FTP thing), and even though I'd argue the support for it is fairly half-baked, it does work! Seems likely the next evolution of Coda will address this.



VS Code

Having version control right in your IDE like this, to me, feels like kind of a tweener between GUI and CLI. There are a lot of features here, but it's not really a full-blown GUI to me, but you've got a terminal built in right there so it almost encourages that. A lot of Git usage is pretty basic pulling, committing, and pushing — so having this right within the app is kinda sweet.

(I imagine there are lots of other IDEs that offer version control features. PHPStorm, etc.)



The post Graphical User Interfaces for Git appeared first on CSS-Tricks.

Toast

Css Tricks - Tue, 07/02/2019 - 12:40pm

One day, all the sudden, I started hearing jokes about toast. I had no idea what the context was. I assumed some friends just got started telling toast jokes, which isn't rare by any means. But it turns out it was a whole thing. It got me thinking, jeez, if I can't keep up with this stuff when it's kinda my job, it must be extra tough for people who actually do work for a living.

Anyway. Thankfully Jeremy summed it up nicely:

First off, this all kicked off with the announcement of “intent to implement”. That makes it sounds like Google are intending to, well, …implement this. In fact “intent to implement” really means “intend to mess around with this behind a flag”. The language is definitely confusing and this is something that will hopefully be addressed.

Secondly, Chrome isn’t going to ship a toast element. Instead, this is a proposal for a custom element currently called std-toast. I’m assuming that should the experiment prove successful, it’s not a foregone conclusion that the final element name will be called toast.

The drama around it, hence the cause of all the jokes and such, was the fact that it felt like it came out of nowhere and was Chrome strongarming a feature through the standards process, or perhaps kinda skipping that process. Terence's humorous post digs into that a bit more.

I'm not sure if Google is actually doing anything nefarious here. It's behind a flag, so I guess the point of that is to explore and research and stuff. Feels very similar to kv:storage to me, a "native module" much like a "native custom element."

But we should be extra watchful about stuff like this. If any browser goes rogue and just starts shipping stuff, web standards is over. Life for devs gets a lot harder and the web gets a lot worse. The stakes are high. And it's not going to happen overnight, it's going to happen with little tiny things like this. Keep that blue beanie on.

Regarding the element itself, it's always a bit surprising to me to see what gets legs as far as new HTML elements. Toasts just seem like a positioned <dialog> to me, but I haven't participated in any research or anything. They are popular enough for Bootstrap to have 'em:

See the Pen
Bootstrap Toasts
by Chris Coyier (@chriscoyier)
on CodePen.

I would have guessed something like dropdown menus or tabs would have been the strongest contenders for "native" web components.

The post Toast appeared first on CSS-Tricks.

Restricting a (pseudo) element to its parent’s border-box

Css Tricks - Tue, 07/02/2019 - 4:19am

Have you ever wanted to ensure that nothing of a (pseudo) element gets displayed outside its parent's border-box? In case you're having trouble picturing what that looks like, let's say we wanted to get the following result with minimal markup and avoiding brittle CSS.

The desired result.

This means we cannot add any elements just for visual purposes and we cannot create shapes out of multiple pieces, whether that's directly or via masks. We also want to avoid long, long lists of anything (think something like tens of background layers or box shadows or points inside a polygon() function) in our generated code because, while the results can be fun, it's not really practical to do something like that!

How do you think we can achieve this, given the parts the arrows point towards? Fancy giving it a try before checking my solution below? It's one of those things that seems simple at first, but once you actually try it, you discover it's much trickier.

Markup

Each item is a paragraph (<p>) element. I was lazy and generated them with Pug out of an array of objects which hold the item's gradient stop list and its paragraph text:

- var data = [ - { - slist: ['#ebac79', '#d65b56'], - ptext: 'Pancake muffin chocolate syrup brownie.' - }, - { - slist: ['#90cbb7', '#2fb1a9'], - ptext: 'Cake lemon berry muffin plum macaron.' - }, - { - slist: ['#8a7876', '#32201c'], - ptext: 'Wafer apple tart pie muffin gingerbread.' - }, - { - slist: ['#a6c869', '#37a65a'], - ptext: 'Liquorice plum topping chocolate lemon.' - } - ].reverse(); - var n = data.length; while n-- p(style=`--slist: ${data[n].slist}`) #{data[n].ptext}

This generates the following unspectacular HTML:

<p style='--slist: #ebac79, #d65b56'>Pancake muffin chocolate syrup brownie.</p> <p style='--slist: #90cbb7, #2fb1a9'>Cake lemon berry muffin plum macaron.</p> <p style='--slist: #8a7876, #32201c'>Wafer apple tart pie muffin gingerbread.</p> <p style='--slist: #a6c869, #37a65a'>Liquorice plum topping chocolate lemon.</p> Basic styles

For the paragraph elements, we set a font, dimensions and a border-radius that's half the height value:

$w: 26em; $h: 5em; p { width: $w; height: $h; border-radius: .5*$h; background: silver; font: 1.5em/ 1.375 trebuchet ms, verdana, sans-serif; }

We've also set a dummy background so we can see their limits:

See the Pen by thebabydino (@thebabydino) on CodePen.

Paragraph background

We have three top-to-bottom gradients, which means we can place each of them within the limits of a different layout box: the top gradient layer is limited to the content-box, the middle one to the padding-box and the bottom one to the border-box. If you need an in-depth refresher on this technique, check out this article, but the basic idea is you picture these layout boxes as nested rectangles.

The layout boxes. (Demo)

This is pretty much how browser DevTools presents them.

The layout boxes as shown by Chrome (left) vs. Firefox (middle) vs. Edge (right).

You may be wondering why we wouldn't layer gradients with different sizes given by their background-size and that have background-repeat: no-repeat. Well, this is because we only get rectangles without rounded corners this way.

Using the background-clip method, if we have a border-radius, our background layers will follow that. Meanwhile, the actual border-radius we set is being used to round the corners of the border-box; that same radius minus the border-width rounding the corners of the padding-box. Then we're subtracting the padding as well to round the corners of the content-box.

See the Pen by thebabydino (@thebabydino) on CodePen.

So let's code this!

We set a transparent border and a padding. We make sure they get subtracted from the dimensions we've set by switching to box-sizing: border-box. Finally, we layer three gradients: the top one restricted to the content-box, the middle one to the padding-box and the bottom one to the border-box.

p { /* same styles as before */ display: flex; align-items: center; justify-content: space-between; box-sizing: border-box; border: solid $b transparent; padding: $p; background: linear-gradient(#dbdbdb, #fff) content-box, linear-gradient(var(--slist)) padding-box, linear-gradient(#fff, #dcdcdc) border-box; text-indent: 1em; }

We've also set a flex layout and a text-indent to move the text content away from the banner edges:

See the Pen by thebabydino (@thebabydino) on CodePen.

Numbering

Before we move on to the tricky part, let's get the paragraph numbers out of the way!

We add them using a counter we set as the content value on the :after pseudo-element. We first make this :after a square whose edge length equals the paragraph height (which is $h) minus the top and bottom border-width (both equal to $b). Then we turn this square into a circle by setting border-radius: 50% on it. We make it inherit its parent's box-sizing and border and we then set its background in a similar manner as we did for its parent.

$d: $h - 2*$b; p { /* same styles as before */ counter-increment: $d; &:after { box-sizing: inherit; border: inherit; width: $d; height: $d; border-radius: 50%; box-shadow: inset 0 0 1px 1px #efefef, inset 0 #{-$b} rgba(#000, .1); background: linear-gradient(var(--slist)) padding-box, linear-gradient(#d0d0d0, #e7e7e7) border-box; color: #fff; content: counter(c, decimal-leading-zero); } }

Alright, this is starting to look like something!

See the Pen by thebabydino (@thebabydino) on CodePen.

We still need to make a few tweaks to the CSS of this :after pseudo-element — a margin-right that's minus its parent's padding and adjustments to its inner layout so we have the number dead in the middle. That's pretty much it for the numbering part!

p { /* same styles as before */ &:after { /* same styles as before */ display: grid; place-content: center; margin-right: -$p; text-indent: 0; } }

We're getting closer!

See the Pen by thebabydino (@thebabydino) on CodePen.

The tricky part

And we're finally here!

We start off by using the :before pseudo-element, absolutely positioning it on the right side and making it a square whose edge length equals its parent's height:

p { /* same styles as before */ position: relative; outline: solid 2px orange; &:before { position: absolute; right: -$b; width: $h; height: $h; outline: solid 2px purple; content: ''; } }

We've also given both this pseudo-element and its parent some dummy outlines so that we can check the alignment:

See the Pen by thebabydino (@thebabydino) on CodePen.

Alright, we now give this :before a dummy background, rotate it, and then give it a border-radius and a nice box-shadow:

p { /* same styles as before */ &:before { /* same styles as before */ border-radius: $b; transform: rotate(45deg); box-shadow: 0 0 7px rgba(#000, .2); background: linear-gradient(-45deg, orange, purple); } }

And we get the following result!

See the Pen by thebabydino (@thebabydino) on CodePen.

We now have a small problem: the :before pseudo-element is absolutely positioned and is now on top of the :after pseudo-elements that holds the numbering! We can fix this by setting position: relative on the :after pseudo-element.

See the Pen by thebabydino (@thebabydino) on CodePen.

Here's where things start getting interesting!

Restricting the background gradient

First, we need to set the stop positions on the gradient of our :before pseudo-element such that they match the bottom and top edges of the parent. This is because we want to have a certain hex value along the top edge of the parent and a certain hex value along the bottom edge of the parent.

The stop positions we need to compute.

Since we've rotated our square :before by 45°, its top-left corner now points upward (and, conversely, its bottom-right corner points downward).

How rotation changes position of the square's corners.

A gradient to the top-left corner of a square is a gradient in the -45° direction (because the 0° angle is at 12 o'clock and the positive direction is, just as for transforms, the clockwise one). A gradient to a corner means the 100% point is located in that corner)

How rotation changes the gradient direction.

The 50% line of a gradient always passes through the midpoint (the point at the intersection of the diagonals) of the gradient box.

The gradient box is the box within which we paint the gradient and whose size is given by the background-size. Since we haven't set a background-size, the default for gradients is to use the entire box defined by background-origin, which is the padding-box by default. Since we don't have a border or a padding on our :before pseudo-element, it results that all three boxes (content-box, padding-box and border-box) are equal in space between them and equal in proportion to the gradient box.

In our case, we have the following lines perpendicular to the direction of the -45°-pointing gradient line:

Getting the relevant stop positions.
  • the 0% line, passing through the bottom right corner of the :before
  • the bottom edge of the pseudo-element's paragraph parent
  • the 50% line which splits our square diagonally into two mirrored right isosceles triangles; given the way we've aligned our paragraph and its pseudo-elements, this line is also a midline for the paragraph itself, splitting it into two halves, each with a height equal to half the paragraph's height ($h).
  • the top edge of the pseudo-element's paragraph parent
  • the 100% line, passing through the top left corner of the :before

This means we need to restrict the -45°-pointing gradient on our :before pseudo-element between calc(50% - #{.5*$h}) (corresponding to the paragraph's bottom edge) and calc(50% + #{.5*$h}) (corresponding to the paragraph's top edge).

Sure enough, this does it!

linear-gradient(-45deg, orange calc(50% - #{.5*$h}), purple calc(50% + #{.5*$h}))

See the Pen by thebabydino (@thebabydino) on CodePen.

Adding a sharp transition from and to transparent at these stop positions makes it a lot more obvious they're the correct ones:

linear-gradient(-45deg, transparent calc(50% - #{.5*$h}), orange 0, purple calc(50% + #{.5*$h}), transparent 0)

See the Pen by thebabydino (@thebabydino) on CodePen.

Restricting the pseudo-element itself

The next step is to prevent the :before pseudo-element from spilling outside the boundaries of its parent.

That's easy, right? Just set overflow: hidden on the paragraph!

Well, let's do that!

This is the result we get:

See the Pen by thebabydino (@thebabydino) on CodePen.

Oops, this is not what we were going for!

What we got with overflow: hidden (left) vs. what we want (right).

The problem is overflow: hidden cuts out everything outside an element's padding-box, but what we want here is to cut the parts of the :before pseudo-element that are outside the border-box, which is larger than the padding-box in our case because we have a non-zero border we cannot ditch (and solve the issue by making the border-box equal to the padding-box) because we need three background layers on our paragraph: the top one covering the content-box, the middle one covering the padding-box and the bottom one covering the border-box.

The solution? Well, if you've taken a peek at the tags, you've probably guessed by now: use clip-path instead!

Pretty much every article and demo using clip-path out there makes use of either an SVG reference or the polygon() shape function, but these are not the only options we have!

Another possible shape function (and the one we'll be using here) is inset(). This function specifies a clipping rectangle defined by the distances from the top, right, bottom and left edges. Edges of what? Well, by default1, that's the edges of the border-box, which is exactly what we need here!

How the inset() function works. (Demo)

So let's ditch overflow: hidden and use clip-path: inset(0) instead. This is the result we get:

See the Pen by thebabydino (@thebabydino) on CodePen.

This is better, but not quite what we want because it doesn't take into account the paragraph's border-radius. Fortunately, inset() also lets us specify a rounding that can take any border-radius value we want. No joke, any valid border-radius value works — for example, this:

clip-path: inset(0 round 15% 75px 35vh 13vw/ 3em 5rem 29vmin 12.5vmax)

We only need something much simpler though:

$r: .5*$h; p { /* same styles as before */ border-radius: $r; clip-path: inset(0 round $r) }

And now we finally get the result we wanted:

See the Pen by thebabydino (@thebabydino) on CodePen.

Final touches

Since we don't want a purple-orange gradient on the :before, we replace those with the actual values we need. We then place the paragraphs in the middle because that looks better. Finally, we give our paragraphs a shadow by setting a drop-shadow() on the body (we cannot use box-shadow on the paragraphs themselves because we've used clip-path, which clips out the box-shadow so we wouldn't see it anyway). And that's it!

See the Pen by thebabydino (@thebabydino) on CodePen.

  1. We should be able to change this <geometry-box> value, but Chrome does not implement this part of the spec. There is an issue open for this which you can star or where you can leave a comment with your use cases for being able to change the default value.

The post Restricting a (pseudo) element to its parent’s border-box appeared first on CSS-Tricks.

Tips for rolling your own lazy loading

Css Tricks - Mon, 07/01/2019 - 4:16am

You may have heard (or even issued the call) that “we can just use lazy loading!” when looking for a way to slim down a particularly heavy web page.

Lazy loading is a popular technique for gradually requesting images as they come into view, rather than all at once after the HTML of the page has been parsed. It can reduce the initial page weight, and help us hit our performance budgets by requesting images when they're needed.

It can be effective. But it also comes with some baggage of its own. We’ll get to that! In fact, Rahul Nanwani did an extensive write-up that hits several lazy-loading methods and illustrates just how complex some are.

In this post, we’ll look at an implementation that's already been covered in brief detail in this post by Preethi. We're going to expand on that so you can add your own implementation of lazy loading to your site as I’ve done on this little demo site.

We’ll cover these topics along the way:

Here’s what we’ll be building:

Demo Site

GitHub Repo Why not native lazy loading?

Currently, lazy loading is not something browsers can do for us natively. Although that looks set to change soon for some browsers with the launch of Chrome 75 which aims to bring lazy loading support for images and iframes. Until that time (and beyond, if we are to play nicely with other browsers - which we should) lazy loading is implemented using JavaScript. There are a number of libraries and frameworks out there to help.

Some static site generators, libraries, and frameworks include utilities to provide this capability “out of the box”, which proves popular as people look for built-in ways to include this feature in their sites. But I’ve also noticed a trend where some chose to adopt entire libraries or frameworks in order to gain access to just this feature. As a thrifty, performance and inclusivity blow-hard, I’m a bit cautious about this. So let’s look at how you could implement this yourself without the need for a specific framework or library.

The typical mechanics for lazy loading

Most approaches follow a pattern like this:

First, some HTML to define our lazily loaded images

<!-- Don't include a src attribute in images you wish to load lazily. Instead specify their src safely in a data attribute --> <img data-src="lighthouse.jpg" alt="A snazzy lighthouse" class="lazy" /> When should image loading take place?

Next, we use some sort of JavaScript magic to correctly set the src attribute when the image comes into view. This was once an expensive JavaScript operation, involving listening for window scroll and resize events, but IntersectionObserver has come to the rescue.

Creating an intersection observer looks like this:

// Set up an intersection observer with some options var observer = new IntersectionObserver(lazyLoad, { // where in relation to the edge of the viewport, we are observing rootMargin: "100px", // how much of the element needs to have intersected // in order to fire our loading function threshold: 1.0 });

We’ve told our new observer to call a function named lazyLoad when those observable conditions are met. The elements that satisfy those conditions will be passed to that function so that we can manipulate them... like actually load and display them.

function lazyLoad(elements) { elements.forEach(image => { if (image.intersectionRatio > 0) { // set the src attribute to trigger a load image.src = image.dataset.src; // stop observing this element. Our work here is done! observer.unobserve(item.target); }; }); };

Great. Our images will have the correct src assigned to them as they come into view, which will cause them to load. But which images? We need to tell the Intersection Observer API which elements we care about. Luckily, we assigned each one with a CSS class of .lazy for just this purpose.

// Tell our observer to observe all img elements with a "lazy" class var lazyImages = document.querySelectorAll('img.lazy'); lazyImages.forEach(img => { observer.observe(img); }); Nice. But perfect?

This seems to be working nicely, but there are some drawbacks to consider:

  1. Until (or unless) JavaScript comes along and successfully runs, we have a bunch of image elements on our page that will not work. We deliberately nixed them by removing the src attribute. That’s the result we wanted, but now we are dependent on JavaScript for these images to load. While it’s true that JavaScript is pretty well ubiquitous on the web theses days — with the web reaching such a broad spectrum of devices and network conditions — JavaScript can become an expensive addition to our performance budgets, particularly if it is involved in the delivery and rendering of content. As Jake Archibald once pointed out, all your users are non-JS while they're downloading your JS. In other words, this is not to be taken lightly.
  2. Even when this works successfully, we have empty elements on our page which might give a bit of a visual jolt when they load in. Perhaps we can hint at the image first and do something fancy. We’ll get to that shortly.

The planned native lazy loading implementation by Chrome should help to address our first point here. If the element has been given a loading attribute, Chrome can honor the src attribute specified at the right time, rather than requesting it eagerly the moment it sees it in the HTML.

The editor's draft of the specification> includes support for different loading behaviors:

  • <img loading="lazy" />: Tell the browser to load this image lazily when needed.
  • <img loading="eager" />: Tell the browser to load this image immediately.
  • <img loading="auto" />: Let the browser make its own assessment.

Browsers without this support would be able to load the image as normal thanks to the resilient nature of HTML and browsers ignoring HTML attributes that they don’t understand.

But... sound the loud caution klaxon! This feature has yet to land in Chrome, and there is also uncertainty about if and when other browsers might choose to implement it. We can use feature detection to decide which method we use, but this still doesn’t give a solid progressive enhancement approach where the images have no dependency on JavaScript.

<img data-src="lighthouse.jpg" alt="A snazzy lighthouse" loading="lazy" class="lazy" /> // If the browser supports lazy loading, we can safely assign the src // attributes without instantly triggering an eager image load. if ("loading" in HTMLImageElement.prototype) { const lazyImages = document.querySelectorAll("img.lazy"); lazyImages.forEach(img => { img.src = img.dataset.src; }); } else { // Use our own lazyLoading with Interection Observers and all that jazz } As a companion to responsive images

Assuming that we are comfortable with the fact that JavaScript is a dependency for the time being, let’s turn our attention to a related topic: responsive images.

If we’re going through the trouble of delivering images into the browser only when needed, it seems fair that we might also want to make sure that we are also delivering them in the best size for how they’ll be displayed. For example, there's no need to download the 1200px-wide version of an image if the device displaying it will only give it a width of 400px. Let's optimize!

HTML gives us a couple of ways to implement responsive images which associate different image sources to different viewport conditions. I like to use the picture element like this:

<picture> <source srcset="massive-lighthouse.jpg" media="(min-width: 1200px)"> <source srcset="medium-lighthouse.jpg" media="(min-width: 700px)"> <source srcset="small-lighthouse.jpg" media="(min-width: 300px)"> <img src="regular-lighthouse.jpg" alt="snazzy lighthouse" /> </picture>

You’ll notice that each source element has a srcset attribute which specifies an image URL, and a media attribute that defines the conditions under which this source should be used. The browser selects the most suitable source from the list according to the media conditions with a standard img element acting as a default/fallback.

Can we combine these two approaches to make lazy-loading responsive images?

Of course, we can! Let’s do it.

Instead of having an empty image until we do our lazy load, I like to load a placeholder image that has a tiny file size. This does incur the overhead of making more HTTP requests, but it also gives a nice effect of hinting at the image before it arrives. You might have seen this effect on Medium or as a result of a site using Gatsby’s lazy loading mechanics.

We can achieve that by initially defining the image sources in our picture element as tiny versions of the same asset and then using CSS to scale them to the same size as their higher-resolution brothers and sisters. Then, through our intersection observer, we can update each of the specified sources to point at the correct image sources.

Our picture element might look like this:

<picture> <source srcset="massive-lighthouse.jpg" media="(min-width: 1200px)"> <source srcset="medium-lighthouse.jpg" media="(min-width: 700px)"> <source srcset="small-lighthouse.jpg" media="(min-width: 300px)"> <img src="regular-lighthouse.jpg" alt="snazzy lighthouse" /> </picture>

No matter what viewport size is applied, we’ll display a tiny 20px image. We're going to blow it up with CSS next.

Previewing the image with style

The browser can scale up the tiny preview image for us with CSS so that it fits the entire picture element rather than a mere 20px of it. Things are going to get a little... pixelated, as you may imagine when a low-resolution image is blown up to larger dimensions.

picture { width: 100%; /* stretch to fit its containing element */ overflow: hidden; } picture img { width: 100%; /* stretch to fill the picture element */ }

For good measure, we can soften that pixelation introduced by scaling up the image by using a blur filter.

picture.lazy img { filter: blur(20px); } Switching sources with JavaScript

With a little adaptation, we can use the same technique as before to set the correct URLs for our srcset and src attributes.

function lazyLoad(elements) { elements.forEach(picture => { if (picture.intersectionRatio > 0) { // gather all the image and source elements in this picture var sources = picture.children; for (var s = 0; s < sources.length; s++) { var source = sources[s]; // set a new srcset on the source elements if (sources.hasAttribute("srcset")) { source.setAttribute("srcset", ONE_OF_OUR_BIGGER_IMAGES); } // or a new src on the img element else { source.setAttribute("src", ONE_OF_OUR_BIGGER_IMAGES); } } // stop observing this element. Our work here is done! observer.unobserve(item.target); }; }); };

One last step to complete the effect: remove that blur effect from the image once the new source has loaded. A JavaScript event listener waiting for the load event on each new image resource can do that for us.

// remove the lazy class when the full image is loaded to unblur source.addEventListener('load', image => { image.target.closest("picture").classList.remove("lazy") }, false);

We can make a nice transition that eases away the blur away, with a sprinkle of CSS.

picture img { ... transition: filter 0.5s, } A little helper from our friends

Great. With just a little JavaScript, a few lines of CSS and a very manageable dollop of HTML, we’ve created a lazy loading technique which also caters for responsive images. So, why aren’t we happy?

Well, we’ve created two bits of friction:

  1. Our markup for adding images is more complex than before. Life used to be simple when all we needed was a single img tag with a good old src attribute.
  2. We’ll also need to create multiple versions of each image assets to populate each viewport size and the pre-loaded state. That’s more work.

Never fear. We can streamline both of these things.

Generating the HTML elements

Let’s look first at generating that HTML rather than authoring it by hand each time.

Whatever tool you use to generate your HTML, chances are that it includes a facility to use includes, functions, shortcodes, or macros. I’m a big fan of using helpers like this. They keep more complex or nuanced code fragments consistent and save time from having to write lengthy code. Most static site generators have this sort of ability.

  • Jekyll lets you create custom Plugins
  • Hugo gives you custom shortcodes
  • Eleventy has shortcodes for all of the template engines it supports
  • There are many more...

As an example, I made a shortcode called lazypicture in my example project built with Eleventy. The shortcode gets used like this:

{% lazypicture lighthouse.jpg "A snazzy lighthouse" %}

To generate the HTML that we need at build time:

<picture class="lazy"> <source srcset="/images/tiny/lighthouse.jpg" media="(min-width: 1200px)"> <source srcset="/images/tiny/lighthouse.jpg" media="(min-width: 700px)"> <source srcset="/images/tiny/lighthouse.jpg" media="(min-width: 300px)"> <img src="/images/tiny/lighthouse.jpg" alt="A snazzy lighthouse" /> </picture> Generating the image assets

The other bit of work we have created for ourselves is generating differently sized image assets. We don’t want to manually create and optimize each and every size of every image. This task is crying out for some automation.

The way you choose to automate this should take into account the number of images assets you need and how regularly you might add more images to that set. You might chose to generate those images as part of each build. Or you could make use of some image transformation services at request time. Let’s look a little at both options.

Option 1: Generating images during your build

Popular utilities exist for this. Whether you run your builds with Grunt, Gulp, webpack, Make, or something else, chances are there is utility for you.

The example below is using gulp-image-resize in a Gulp task as part of a Gulp build process. It can chomp through a directory full of image assets and generate the variants you need. It has a bunch of options for you to control, and you can combine with other Gulp utilities to do things like name the different variants according to the conventions you choose.

var gulp = require('gulp'); var imageResize = require('gulp-image-resize'); gulp.task('default', function () { gulp.src('src/**/*.{jpg,png}') .pipe(imageResize({ width: 100, height: 100 })) .pipe(gulp.dest('dist')); });

The CSS-Tricks site uses a similar approach (thanks to the custom sizes feature in WordPress) to auto-generate all of its different image sizes. (Oh yeah! CSS-Tricks walks the walk!) ResponsiveBreakpoints.com provides a web UI to experiment with different settings and options for creating images sets and even generates the code for you.

Or, you can use it programmatically as Chris mentioned on Twitter.

I use this on @CSS, but programmatically!

Every image uploaded is ran through this to find perfect breakpoints, then uploaded to @cloudinary and served from there (originals on our server).https://t.co/Gt75vujTVL

— Chris Coyier (@chriscoyier) June 10, 2019

When you have as many image files as CSS-Tricks, though, doing this work as part of a build step can become cumbersome. Good caching in your build and other file management tasks can help, but it can be easy to end up with a lengthy build process that heats up your computer as it performs all of the work.

An alternative is to transform these resources at request time rather than during a build step. That's the second option.

Option 2: On-demand image transformations

I’m a loud advocate of pre-rendering content. I’ve shouted about this approach (often referred to as JAMstack) for quite some time, and I believe that it has numerous performance, security and simplicity benefits. (Chris summed this up nicely in a post about static hosting and JAMstack.)

That said, the idea of generating different image sizes at request time might seem to be contrary to my lazy loading objectives. In fact, there are a number of services and companies now, who specialize in this and they do it in a very powerful and convenient way.

Combining image transformations with powerful CDN and asset caching capabilities by companies like Netlify, Fastly, and Cloudinary can rapidly generate images with the dimensions you pass to them via a URL. Each service has significant processing power to perform these transformations on the fly, then cache the generated images for future use. This makes for seamless rendering for subsequent requests.

Since I work at Netlify, I’ll illustrate this with an example using Netlify’s service. But the others I mentioned work in similar ways.

Netlify’s Image Transformation service builds on top of something called Netlify Large Media. This is a feature created to help manage large assets in your version control. Git is not very good at this by default, but Git Large File Storage can extend Git to make it possible to include large assets in your repos without clogging them up and making them unmanageable.

You can read more on the background of that approach for managing large assets if you are interested.

Placing images under version control in our Git repositories is an added bonus, but for our purposes, we are more interested in enjoying the benefits of making on-the-fly transformations of those images.

Netlify looks for querystring parameters when transforming images. You can specify the height, width and the type of crop you’d like to perform. Like this:

  • A raw image with no transformations:
    /images/apple3.jpg
  • An image resized to be 300px wide:
    /images/apple3.jpg?nf_resize=fit&w=300
  • An image cropped to be 500px by 500px with automated focal point detection:
    /images/apple3.jpg?nf_resize= smartcrop&w=500&h=500

Knowing that we can create and deliver any image sizes from a single source image in our version control means that the JavaScript we use to update the image sources only need to include the size parameters we choose.

The approach can drastically speed up your site build processes because the work is now outsourced and not performed at build time.

Wrapping it all up

We’ve covered a lot of ground here. There are a lot of very achievable options for implementing responsive images with lazy loading. Hopefully, this will give enough info to make you think twice about reaching for the nearest available framework to gain access to this sort of functionality.

This demo site pulls together a number of these concepts and uses Netlify’s image transformation service.

Demo Site

GitHub Repo One last time, to summarize the flow

  • A static site generator with a shortcode eases the task of creating the picture elements
  • Netlify Large Media hosts and transforms the images, then serves them as tiny 20px-wide versions before the larger files are loaded as needed.
  • CSS scales up the tiny images and blurs them to create the preview placeholder images.
  • The Intersection Observer API detects when to swap the image assets for the appropriate larger versions.
  • JavaScript detects the load event for the larger images and removes out the blur effect to reveal the higher-resolution rendering.

The post Tips for rolling your own lazy loading appeared first on CSS-Tricks.

Making width and flexible items play nice together

Css Tricks - Mon, 07/01/2019 - 4:15am

The short answer: flex-shrink and flex-basis are probably what you’re lookin’ for.

The long answer

Let’s say you want to align an image and some text next to each other with like this:

Now let's say you reach for flexbox to make it happen. Setting the parent element to display: flex; is a good first start.

.container { display: flex; }

And this results in...

See the Pen
Flex-Shrink Example 1
by Robin Rendle (@robinrendle)
on CodePen.

Yikes! Well, that's kinda okay, I guess. It makes sense that the image would bump right up against the text like that because we haven’t set a width on the image. Ideally, though, we’d like that image to have a fixed width and then the text should take up whatever space is left over.

Okay, so let’s go do that!

.container { display: flex; } img { width: 50px; margin-right: 20px; }

See the Pen
Flex-Shrink Example 2
by Robin Rendle (@robinrendle)
on CodePen.

This looks great in Chrome. But wait, what? If we inspect the image tag in Firefox DevTools, we’ll find that it’s not the width value that we set at all:

We could use min-width to force the image to the 50px width we want:

img { min-width: 50px; margin-right: 20px; }

Buuuuuuut, that only sets helps with the width so we've got to put a margin in as well.

img { min-width: 50px; margin-right: 20px; }

There we go. That's better in Firefox and still works in Chrome.

The even longer answer

I realized the image is getting the squished treatment because we need to use the flex-shrink property to tell flex items not to decrease in size, regardless of whether or not they have a width.

All flex-items have a flex-shrink value of 1. We need to set the image element to 0:

.container { display: flex; } img { width: 50px; margin-right: 20px; flex-shrink: 0; }

See the Pen
Flex-Shrink Example 3
by Robin Rendle (@robinrendle)
on CodePen.

Getting better! But we can still do more to improve this.

The director's cut answer

We can tidy things up further because flex-shrink is included in the flex shorthand property.

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

If we set the flex-shrink value to 0 and the flex-basis value to the default width we want the image to be, then we can get rid of the width property altogether.

.container { display: flex; } img { flex: 0 0 50px; margin-right: 20px; }

Oh yeah:

See the Pen
Flex-Shrink Example 2
by Geoff Graham (@geoffgraham)
on CodePen.

Another example

That flex-shrink property solves a ton of other problems and is pretty dang important if you want to start using flexbox. Here’s another example why: I stumbled upon yet another problem like the one above and I mentioned it in a recent edition of the newsletter. I was building a navigation component that would let users scroll left and right through multiple items. I noticed the following problem when checking my work:

See the Pen
flex-shrink nav item 1
by Robin Rendle (@robinrendle)
on CodePen.

That longer navigation item shouldn’t break into multiple lines like that — but I finally understood why this was happening, thanks to the previous issue. If you set the flex-shrink property to 0 then it will tell each item in this navigation not to shrink and instead assume the width of the content instead, like this:

See the Pen
flex-shrink nav item
by Robin Rendle (@robinrendle)
on CodePen.

And, yes, we can go the extra step once again to use the flex property instead, this time using auto as the flex-basis since we want the maximum amount of space for all items to be considered when divvying up space in the navigation container.

See the Pen
Setting flex for flexible nav elements
by Geoff Graham (@geoffgraham)
on CodePen.

Huzzah! We figured it out. Even though the answer is a single line of code, it's is pretty essential one to making truly flexible elements.

The post Making width and flexible items play nice together appeared first on CSS-Tricks.

The (Developer’s) Growth Model

Css Tricks - Fri, 06/28/2019 - 1:25pm

I really like the post "The Designer’s Growth Model" by Dennis Hambeukers. Dennis just invented this model, but it's based on some existing ideas and it all rings true for me. Let me try to summarize the five stages as he lays them out for designers.

  1. Producers: You learn how to design. You learn fundamentals, you practice, you get good at doing design work and producing beautiful functional things. Then you have this "crisis" moment before the next stage where you find you can't do enough work on your own and that you need to be able to scale your efforts, with multiple human beings and working on systems — and that's an entirely new skill.
  2. Architects: Now that you've succeeded in scaling through team building and systems thinking, the next crisis moment is that that this the work still might be isolated, and too focused on internal thinking. To grow, you'll need to work with people outside the design bubble, and understand problems more holistically.
  3. Connectors: Now that you've succeeded in being more collaborative across an entire organization and being a real problem solver, the next crisis moment is when everything becomes organizationally complicated. Just delivering products isn't enough, because you're involved deeply across the organization and you're responsible for the success of what is delivered.
  4. Scientists: Now, you measure everything. You know what works and what doesn't because you test it and can prove it, along with using all the skills you've honed along the way. Your next crisis is figuring out how to translate your work into actual change.
  5. Visionaries: You're a leader now. You have an understanding of how the whole organization ticks, and you are a force for change.
From The Designer's Growth Model

I think this can applies just as well to web development, with very little change. I can relate in many ways. I started plucking away at building sites alone. I found more success and was able to build bigger things by working with other people. At some point, it was clear to me that things don't revolve around development. Development is merely one part of a car that doesn't drive at all without many other parts. Even today, it's clearer to me that I can be more effective and drive more positive change the more I know about all of the parts.

Not that I've completed my journey. If I had to map myself directly onto this model, I'm probably barely on step three — But a model is just a model. It's not meant to be a perfect roadmap for everybody. Your own career path will be twistier than this. You might even experience bits from all the levels in different doses along the way.

The post The (Developer’s) Growth Model appeared first on CSS-Tricks.

The (Developer’s) Growth Model

Css Tricks - Fri, 06/28/2019 - 1:25pm

I really like the post "The Designer’s Growth Model" by Dennis Hambeukers. Dennis just invented this model, but it's based on some existing ideas and it all rings true for me. Let me try to summarize the five stages as he lays them out for designers.

  1. Producers: You learn how to design. You learn fundamentals, you practice, you get good at doing design work and producing beautiful functional things. Then you have this "crisis" moment before the next stage where you find you can't do enough work on your own and that you need to be able to scale your efforts, with multiple human beings and working on systems — and that's an entirely new skill.
  2. Architects: Now that you've succeeded in scaling through team building and systems thinking, the next crisis moment is that that this the work still might be isolated, and too focused on internal thinking. To grow, you'll need to work with people outside the design bubble, and understand problems more holistically.
  3. Connectors: Now that you've succeeded in being more collaborative across an entire organization and being a real problem solver, the next crisis moment is when everything becomes organizationally complicated. Just delivering products isn't enough, because you're involved deeply across the organization and you're responsible for the success of what is delivered.
  4. Scientists: Now, you measure everything. You know what works and what doesn't because you test it and can prove it, along with using all the skills you've honed along the way. Your next crisis is figuring out how to translate your work into actual change.
  5. Visionaries: You're a leader now. You have an understanding of how the whole organization ticks, and you are a force for change.
From The Designer's Growth Model

I think this can applies just as well to web development, with very little change. I can relate in many ways. I started plucking away at building sites alone. I found more success and was able to build bigger things by working with other people. At some point, it was clear to me that things don't revolve around development. Development is merely one part of a car that doesn't drive at all without many other parts. Even today, it's clearer to me that I can be more effective and drive more positive change the more I know about all of the parts.

Not that I've completed my journey. If I had to map myself directly onto this model, I'm probably barely on step three — But a model is just a model. It's not meant to be a perfect roadmap for everybody. Your own career path will be twistier than this. You might even experience bits from all the levels in different doses along the way.

The post The (Developer’s) Growth Model appeared first on CSS-Tricks.

Weekly Platform News: Event Timing, Google Earth for Web, undead session cookies

Css Tricks - Fri, 06/28/2019 - 7:33am

Šime posts regular content for web developers on webplatform.news.

In this week's news, Wikipedia helps identify three slow click handlers, Google Earth comes to the web, SVG properties in CSS get more support, and what to do in the event of zombie cookies.

Tracking down slow event handlers with Event Timing

Event Timing is experimentally available in Chrome (as an Origin Trial) and Wikipedia is taking part in the trial. This API can be used to accurately determine the duration of event handlers with the goal of surfacing slow events.

We quickly identified 3 very frequent slow click handlers experienced frequently by real users on Wikipedia. [...] Two of those issues are caused by expensive JavaScript calls causing style recalculation and layout.

(via Gilles Dubuc)

Google Earth for Web beta available

The preview version of Google Earth for Web (powered by WebAssembly) is now available. You can try it out in Chromium-based browsers and Firefox?—?it runs single-threaded in browsers that don’t yet have (re-)enabled SharedArrayBuffer?—?but not in Safari because of its lack of full support for WebGL2.

(via Jordon Mears)

SVG geometry properties in CSS

Firefox Nightly has implemented SVG geometry properties (x, y, r, etc.) in CSS. This feature is already supported in Chrome and Safari and is expected to ship in Firefox 69 in September.

See the Pen
Animating SVG geometry properties with CSS
by Šime Vidas (@simevidas)
on CodePen.

(via Jérémie Patonnier)

Browsers can keep session cookies alive

Chrome and Firefox allow users to restore the previous browser session on startup. With this option enabled, closing the browser will not delete the user’s session cookies, nor empty the sessionStorage of web pages.

Given this session resumption behavior, it’s more important than ever to ensure that your site behaves reasonably upon receipt of an outdated session cookie (e.g. redirect the user to the login page instead of showing an error).

(via Eric Lawrence)

The post Weekly Platform News: Event Timing, Google Earth for Web, undead session cookies appeared first on CSS-Tricks.

Weekly Platform News: Event Timing, Google Earth for Web, undead session cookies

Css Tricks - Fri, 06/28/2019 - 7:33am

Šime posts regular content for web developers on webplatform.news.

In this week's news, Wikipedia helps identify three slow click handlers, Google Earth comes to the web, SVG properties in CSS get more support, and what to do in the event of zombie cookies.

Tracking down slow event handlers with Event Timing

Event Timing is experimentally available in Chrome (as an Origin Trial) and Wikipedia is taking part in the trial. This API can be used to accurately determine the duration of event handlers with the goal of surfacing slow events.

We quickly identified 3 very frequent slow click handlers experienced frequently by real users on Wikipedia. [...] Two of those issues are caused by expensive JavaScript calls causing style recalculation and layout.

(via Gilles Dubuc)

Google Earth for Web beta available

The preview version of Google Earth for Web (powered by WebAssembly) is now available. You can try it out in Chromium-based browsers and Firefox?—?it runs single-threaded in browsers that don’t yet have (re-)enabled SharedArrayBuffer?—?but not in Safari because of its lack of full support for WebGL2.

(via Jordon Mears)

SVG geometry properties in CSS

Firefox Nightly has implemented SVG geometry properties (x, y, r, etc.) in CSS. This feature is already supported in Chrome and Safari and is expected to ship in Firefox 69 in September.

See the Pen
Animating SVG geometry properties with CSS
by Šime Vidas (@simevidas)
on CodePen.

(via Jérémie Patonnier)

Browsers can keep session cookies alive

Chrome and Firefox allow users to restore the previous browser session on startup. With this option enabled, closing the browser will not delete the user’s session cookies, nor empty the sessionStorage of web pages.

Given this session resumption behavior, it’s more important than ever to ensure that your site behaves reasonably upon receipt of an outdated session cookie (e.g. redirect the user to the login page instead of showing an error).

(via Eric Lawrence)

The post Weekly Platform News: Event Timing, Google Earth for Web, undead session cookies appeared first on CSS-Tricks.

Nownownow

Css Tricks - Fri, 06/28/2019 - 7:32am

Matthias Ott, relaying an idea he heard from Derek Sivers:

Many personal websites, including this one here, have an “about” page. It’s a page that tells you something about the background of a person or about the services provided. But what this page often doesn’t answer – and neither do Twitter or Facebook pages – is what this person really is up to at the moment. A page that answers questions like: What are you focused on at this point in your life? What have you just started working on that excites you like nothing else? Did you just move to a new town? Did you start a new career as a Jengascript wrangler? To answer all those questions, Derek suggests to create a “now page”. A page that tells visitors of your site “what you’d tell a friend you hadn’t seen in a year.”

Very cool idea! Derek has a directory page of people who have done this.

I have more scattered thoughts:

  • It's funny how social media sites aren't very helpful with this. You'd think looking at someone's social media profile would be the quickest and easiest way to catch up with what they are doing right now, but it just ain't. That's true for me, too. Random statements of what you're working on don't make very good social media posts. Maybe a pinned tweet could be like a "now" page, though.
  • I wonder if more homepages on people's personal sites should be this. As I browse around some of the sites, I like a lot of the "now" pages more than I like the homepage.
  • I went with a "what I want you to do" section on my personal site. It's a different vibe, but it almost doubles as a "now" page, as the things I want you to do are fairly related to the things I'm doing. Maybe the idea of a do page has some legs.

Direct Link to ArticlePermalink

Nownownow

Css Tricks - Fri, 06/28/2019 - 7:32am

Matthias Ott, relaying an idea he heard from Derek Sivers:

Many personal websites, including this one here, have an “about” page. It’s a page that tells you something about the background of a person or about the services provided. But what this page often doesn’t answer – and neither do Twitter or Facebook pages – is what this person really is up to at the moment. A page that answers questions like: What are you focused on at this point in your life? What have you just started working on that excites you like nothing else? Did you just move to a new town? Did you start a new career as a Jengascript wrangler? To answer all those questions, Derek suggests to create a “now page”. A page that tells visitors of your site “what you’d tell a friend you hadn’t seen in a year.”

Very cool idea! Derek has a directory page of people who have done this.

I have more scattered thoughts:

  • It's funny how social media sites aren't very helpful with this. You'd think looking at someone's social media profile would be the quickest and easiest way to catch up with what they are doing right now, but it just ain't. That's true for me, too. Random statements of what you're working on don't make very good social media posts. Maybe a pinned tweet could be like a "now" page, though.
  • I wonder if more homepages on people's personal sites should be this. As I browse around some of the sites, I like a lot of the "now" pages more than I like the homepage.
  • I went with a "what I want you to do" section on my personal site. It's a different vibe, but it almost doubles as a "now" page, as the things I want you to do are fairly related to the things I'm doing. Maybe the idea of a do page has some legs.

Direct Link to ArticlePermalink

The post Nownownow appeared first on CSS-Tricks.

Which CSS IS AWESOME makes the most sense if you don’t know CSS well?

Css Tricks - Thu, 06/27/2019 - 11:29am

Peter-Paul posted this question:

Which of the examples in the image do you consider correct?

If you know CSS well, don't reply, just retweet.

If you don't know CSS too well, please reply to the poll in the next tweet. pic.twitter.com/4bgnf9Wdkc

— ppk &#x1f1ea;&#x1f1fa; (@ppk) June 17, 2019

Note the interesting caveat: only vote in the poll if you don't know CSS well.

The winning answer was D! You gotta wonder if the result would have been different if the request for non-CSS experts wasn't there.

I like to think I know CSS OK, so I didn't vote. My brain goes like this:

  1. I think he's asking "by default," so the answer may assume there's no other CSS doing anything to that text.
  2. I wish I knew why the box was that particular width, but I guess I'll just assume it's a set width.
  3. It's not B because ellipsis stuff requires extra stuff, and doesn't work on multiple lines like that — unless we're talking line clamping, which is even weirder.
  4. It's not C because that requires hiding overflow which is never really a default — that is, except off the top and left of the browser window, I guess. Or in an iframe.
  5. It's not D because words just don't break like that unless you do pretty specific stuff.
  6. A actually makes decent sense. It's weird to look at, but I've been dealing with stuff busting out of containers my whole career. C'est la vie.

Remember, we've done a deep dive into CSS IS AWESOME before and how it interestingly captures the weirdness of CSS.

Which CSS IS AWESOME makes the most sense if you don’t know CSS well?

Css Tricks - Thu, 06/27/2019 - 11:29am

Peter-Paul posted this question:

Which of the examples in the image do you consider correct?

If you know CSS well, don't reply, just retweet.

If you don't know CSS too well, please reply to the poll in the next tweet. pic.twitter.com/4bgnf9Wdkc

— ppk &#x1f1ea;&#x1f1fa; (@ppk) June 17, 2019

Note the interesting caveat: only vote in the poll if you don't know CSS well.

The winning answer was D! You gotta wonder if the result would have been different if the request for non-CSS experts wasn't there.

I like to think I know CSS OK, so I didn't vote. My brain goes like this:

  1. I think he's asking "by default," so the answer may assume there's no other CSS doing anything to that text.
  2. I wish I knew why the box was that particular width, but I guess I'll just assume it's a set width.
  3. It's not B because ellipsis stuff requires extra stuff, and doesn't work on multiple lines like that — unless we're talking line clamping, which is even weirder.
  4. It's not C because that requires hiding overflow which is never really a default — that is, except off the top and left of the browser window, I guess. Or in an iframe.
  5. It's not D because words just don't break like that unless you do pretty specific stuff.
  6. A actually makes decent sense. It's weird to look at, but I've been dealing with stuff busting out of containers my whole career. C'est la vie.

Remember, we've done a deep dive into CSS IS AWESOME before and how it interestingly captures the weirdness of CSS.

The post Which CSS IS AWESOME makes the most sense if you don’t know CSS well? appeared first on CSS-Tricks.

Different Approaches for Creating a Staggered Animation

Css Tricks - Thu, 06/27/2019 - 5:00am

Animating elements, at its most basic, is fairly straightforward. Define the keyframes. Name the animation. Call it on an element.

But sometimes we need something a little more complex to get the right “feel" for the way things move. For example, a sound equalizer might use the same animation on each bar, but they are staggered to give the illusion of being animated independently.

See the Pen
Apple Music Sound Equilizer in SVG
by Geoff Graham (@geoffgraham)
on CodePen.

I was recently building a dashboard and wanted the items in one of the widgets to flow into view with a staggered animation.


Just like the sound equalizer above, I started going down the :nth-child route. I used the unordered list (<ul>) as the parent container, gave it a class and employed the :nth-child pseudo selector to offset each list item with animaton-delay.

.my-list li { animation: my-animation 300ms ease-out; } .my-list li:nth-child(1) { animation-delay: 100ms; } .my-list li:nth-child(2) { animation-delay: 200ms; } .my-list li:nth-child(3) { animation-delay: 300ms; } /* and so on */

This technique does indeed stagger items well, particularly if you know how many items are going to be in the list at any given time. Where things fall apart, however, is when the number of items is unpredictable, which was the case for the widget I was building for the dashboard. I really didn’t want to come back to this piece of code every time the number of items in the list changed, so I knocked out a quick Sass loop that accounts for up to 50 items and increments the animation delay with each item:

.my-list { li { animation: my-animation 300ms ease-out; @for $i from 1 through 50 { &:nth-child(#{$i}) { animation-delay: 100ms * $i; } } } }

That should do it! Yet, it feels way too hacky. Sure, it doesn’t add that much weight to the file, but you know the compiled CSS will include a bunch of unused selectors, like nth-child(45).

There must be a better way. This is where I would normally reach for JavaScript to find all of the items and add a delay but… this time I spent a little time exploring to see if there is a way to do it with CSS alone.

How about CSS counters?

The first thing I thought of was using a CSS counter in combination with the calc() function:

.my-list { counter-reset: my-counter; } .my-list li { counter-increment: my-counter; animation-delay: calc(counter(my-counter) * 100ms); }

Unfortunately, that won’t work because the spec says counters cannot be used in calc()):

Components of a calc() expression can be literal values or attr() or calc() expressions.

Turns out a few people like this idea, but it hasn’t gone further than the draft stage.

How about a data attribute?

Having read that excerpt from the spec, I learned that calc() can use attr(). And, according to the CSS Values and Units specification):

In CSS3, the attr() expression can return many different types

This made me think; perhaps a data attribute could do the trick.

<ul class="my-list"> <li data-count="1"></li> <li data-count="2"></li> <li data-count="3"></li> <li data-count="4"></li> </ul> .my-list li { animation-delay: calc(attr(data-count) * 150ms); }

But my hopes were dashed as the browser support for this is diabolical!

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

DesktopChromeOperaFirefoxIEEdgeSafariNoNoNoNoNoNoMobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid FirefoxNoNoNoNoNoNo

So, back to the drawing board.

How about custom properties?

The next idea I had was using CSS custom properties. It’s not pretty, but it worked &#x1f642;

See the Pen
CSS variables animation order
by Dan Benmore (@dbenmore)
on CodePen.

Turns out it’s pretty flexible too. For example, the animation can be reversed:

See the Pen
CSS variables reverse animation order
by Dan Benmore (@dbenmore)
on CodePen.

It can also do something completely random and animate elements at the same time:

See the Pen
CSS variables random animation order
by Dan Benmore (@dbenmore)
on CodePen.

We can even push it a bit further and do a diagonal swoosh:

See the Pen
Set animation stagger with CSS properties / variables
by Dan Benmore (@dbenmore)
on CodePen.

The browser support isn’t all that bad (pokes stick at Internet Explorer).

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

DesktopChromeOperaFirefoxIEEdgeSafari493631No169.1Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox9.346No677567

One of the great features of CSS is that it will ignore things it doesn’t understand, thanks to the cascade. That means everything will animate in into view together. If that’s not your bag, you can add a feature query to override a default animation:

.my-list li { animation: fallback-animation; } @supports (--variables) { .my-list li { animation: fancy-animation; animation-delay: calc(var(--animation-order) * 100ms); } } Vanilla CSS FTW

The more I stop and ask myself whether I need JavaScript, the more I’m amazed what CSS can do on its own. Sure, it would be nice if CSS counters could be used in a calc() function and it would be a pretty elegant solution. But for now, inline custom properties provide both a powerful and flexible way to solve this problem.

Different Approaches for Creating a Staggered Animation

Css Tricks - Thu, 06/27/2019 - 5:00am

Animating elements, at its most basic, is fairly straightforward. Define the keyframes. Name the animation. Call it on an element.

But sometimes we need something a little more complex to get the right “feel" for the way things move. For example, a sound equalizer might use the same animation on each bar, but they are staggered to give the illusion of being animated independently.

See the Pen
Apple Music Sound Equilizer in SVG
by Geoff Graham (@geoffgraham)
on CodePen.

I was recently building a dashboard and wanted the items in one of the widgets to flow into view with a staggered animation.


Just like the sound equalizer above, I started going down the :nth-child route. I used the unordered list (<ul>) as the parent container, gave it a class and employed the :nth-child pseudo selector to offset each list item with animaton-delay.

.my-list li { animation: my-animation 300ms ease-out; } .my-list li:nth-child(1) { animation-delay: 100ms; } .my-list li:nth-child(2) { animation-delay: 200ms; } .my-list li:nth-child(3) { animation-delay: 300ms; } /* and so on */

This technique does indeed stagger items well, particularly if you know how many items are going to be in the list at any given time. Where things fall apart, however, is when the number of items is unpredictable, which was the case for the widget I was building for the dashboard. I really didn’t want to come back to this piece of code every time the number of items in the list changed, so I knocked out a quick Sass loop that accounts for up to 50 items and increments the animation delay with each item:

.my-list { li { animation: my-animation 300ms ease-out; @for $i from 1 through 50 { &:nth-child(#{$i}) { animation-delay: 100ms * $i; } } } }

That should do it! Yet, it feels way too hacky. Sure, it doesn’t add that much weight to the file, but you know the compiled CSS will include a bunch of unused selectors, like nth-child(45).

There must be a better way. This is where I would normally reach for JavaScript to find all of the items and add a delay but… this time I spent a little time exploring to see if there is a way to do it with CSS alone.

How about CSS counters?

The first thing I thought of was using a CSS counter in combination with the calc() function:

.my-list { counter-reset: my-counter; } .my-list li { counter-increment: my-counter; animation-delay: calc(counter(my-counter) * 100ms); }

Unfortunately, that won’t work because the spec says counters cannot be used in calc()):

Components of a calc() expression can be literal values or attr() or calc() expressions.

Turns out a few people like this idea, but it hasn’t gone further than the draft stage.

How about a data attribute?

Having read that excerpt from the spec, I learned that calc() can use attr(). And, according to the CSS Values and Units specification):

In CSS3, the attr() expression can return many different types

This made me think; perhaps a data attribute could do the trick.

<ul class="my-list"> <li data-count="1"></li> <li data-count="2"></li> <li data-count="3"></li> <li data-count="4"></li> </ul> .my-list li { animation-delay: calc(attr(data-count) * 150ms); }

But my hopes were dashed as the browser support for this is diabolical!

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

DesktopChromeOperaFirefoxIEEdgeSafariNoNoNoNoNoNoMobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid FirefoxNoNoNoNoNoNo

So, back to the drawing board.

How about custom properties?

The next idea I had was using CSS custom properties. It’s not pretty, but it worked &#x1f642;

See the Pen
CSS variables animation order
by Dan Benmore (@dbenmore)
on CodePen.

Turns out it’s pretty flexible too. For example, the animation can be reversed:

See the Pen
CSS variables reverse animation order
by Dan Benmore (@dbenmore)
on CodePen.

It can also do something completely random and animate elements at the same time:

See the Pen
CSS variables random animation order
by Dan Benmore (@dbenmore)
on CodePen.

We can even push it a bit further and do a diagonal swoosh:

See the Pen
Set animation stagger with CSS properties / variables
by Dan Benmore (@dbenmore)
on CodePen.

The browser support isn’t all that bad (pokes stick at Internet Explorer).

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

DesktopChromeOperaFirefoxIEEdgeSafari493631No169.1Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox9.346No677567

One of the great features of CSS is that it will ignore things it doesn’t understand, thanks to the cascade. That means everything will animate in into view together. If that’s not your bag, you can add a feature query to override a default animation:

.my-list li { animation: fallback-animation; } @supports (--variables) { .my-list li { animation: fancy-animation; animation-delay: calc(var(--animation-order) * 100ms); } } Vanilla CSS FTW

The more I stop and ask myself whether I need JavaScript, the more I’m amazed what CSS can do on its own. Sure, it would be nice if CSS counters could be used in a calc() function and it would be a pretty elegant solution. But for now, inline custom properties provide both a powerful and flexible way to solve this problem.

The post Different Approaches for Creating a Staggered Animation appeared first on CSS-Tricks.

Using Percy to add visual testing to a Jekyll site

Css Tricks - Thu, 06/27/2019 - 4:57am

Visual testing is the automated process of reviewing software from a purely visual standpoint. Instead of testing the code underneath, visual testing is all about what end users actually see and interact with.

Similar to functional testing, however, visual testing fits directly into your stack and workflow. And with Percy, it’s easy to add snapshots to and run visual reviews for anything that runs in a browser.

Let’s set up an app to test

In this tutorial, we’re going to clone an example Jekyll site, add Percy snapshots, make some visual changes, and review them in Percy.

Before we add Percy, let’s set up our example app:

git clone https://github.com/percy/example-percy-jekyll.git

Navigate to your local app, install dependencies, then build and run the site:

cd example-percy-jekyll/ bundle install bundle exec jekyll build bundle exec jekyll serve

Note: Ruby >= 2.3 is required

Open and click around the site locally to see what we’ll be taking Percy snapshots of.

Shoutout to CloudCannon for the Hydra theme.

Next, if you haven’t already, sign up for a free Percy account and create an organization and a new project:

Percy projects correspond to the web application, component library, or static site you’re testing. In this case, we’ll be connecting our Percy project to our Jekyll site.

Generating Percy snapshots

To authenticate your local environment with your new Percy project, copy the PERCY_TOKEN environment variable from the new project screen or your project settings, then run:

$ export PERCY_TOKEN=aaabbbcccdddeee $ npx percy snapshot _site/

Note: Be sure to replace the token with your project-specific token.

You’ll see output like this:

$ npx percy snapshot _site/ Downloading Chromium r662092 - 88.3 Mb [====================] 100% 0.0s [percy] created build #1: https://percy.io/jekyll-test-site/hydra-theme/builds/2048096 [percy] percy has started. [percy] serving static site at http://localhost:5339/ [percy] snapshot taken: '/404.html' [percy] snapshot taken: '/index.html' [percy] snapshot taken: '/about/index.html' [percy] snapshot taken: '/blog/index.html' [percy] snapshot taken: '/contact/index.html' [percy] snapshot taken: '/contact-success/index.html' [percy] snapshot taken: '/pricing/index.html' [percy] snapshot taken: '/category/marketing/index.html' [percy] snapshot taken: '/category/sales/index.html' [percy] snapshot taken: '/category/tips/index.html' [percy] snapshot taken: '/sales/2016/07/20/the-process-for-direct-sales/index.html' [percy] snapshot taken: '/marketing/2016/08/12/the-history-of-marketing/index.html' [percy] snapshot taken: '/sales/2016/08/06/definition-of-sales/index.html' [percy] snapshot taken: '/sales/tips/2016/07/28/effective-upselling-techniques/index.html' [percy] snapshot taken: '/sales/tips/2016/08/02/sales-effectiveness/index.html' [percy] shutting down static site at http://localhost:5339/ [percy] stopping percy... [percy] waiting for 15 snapshots to complete... [percy] done. [percy] finalized build #1: https://percy.io/jekyll-test-site/hydra-theme/builds/2048096

Click the build link or head over to your Percy project to check out your first build.

What’s going on behind the scenes?

Once npx percy snapshot _site/ was called, Percy captured the DOM snapshots for each page of your Jekyll site. Percy then recreated the snapshots to compare against baseline snapshots and determine which pixels have changed.

Since this is the first build, there isn’t anything to compare it to. It has also been auto-approved because the commit was on master and we assume that master builds are production-ready.

Making and reviewing visual changes

Now that you’ve pushed your first build and established a baseline to compare your next snapshots to, let’s make a visual change to review.

Let’s make a wide sweeping CSS change. Head over to the cloudcannon.scss file and change the brand colors:

$brand-color: #ff8a00; $secondary-brand-color: #da1b60;

Since we’re pushing these changes directly to master, be sure to disable auto-approve on master branches from your Percy project settings.

Once those changes are saved, build your site and run Percy again:

$ bundle exec jekyll build $ npx percy snapshot _site/

Head back to Percy or click the Percy build link to see the visual changes!

If you haven’t been following along, you can check out the build.

What’s going on in the Percy UI?

The red areas in the right panel represent pixels that have changed—the visual diffs. Clicking that area (or pressing "d") will toggle between the underlying snapshot and the overlaid diff so you can easily see what exactly has changed. You’ll also notice that the first several diffs have been matched and grouped to make it easier and faster to review.

Each snapshot has been rendered across both Chrome and Firefox, and at mobile and desktop widths. Rendering your site across these variations helps you detect subtle differences caused by browser rendering or responsive bugs.

Now that we’re happy with our fresh new look, hit "Approve All." ✅

You’ve done your first visual review! Visual testing is great not only for catching visual bugs, but also for knowing the exact impact of any given code change. Seeing your UI visualized during code reviews is invaluable, helping you fix regressions before they make their way to production, or to deploy with complete confidence.

Configuring your snapshots

You can configure how and where Percy runs for each build by creating a global .percy.yml file in the root of your project.

You can customize the responsive widths at which your snapshots are rendered. For example, if you want to add a super wide snapshot in addition to our mobile and desktop widths:

version: 1 snapshot: widths: [375, 1280, 1920]

You can also ignore certain pages. For example, if you’d like to ignore multiple pages with the same layout like blog categories posts:

version: 1 static-snapshots: ignore-files: "/blog/category/*"

Learn more about Percy SDK configuration in our docs).

Adding Percy to your workflow

What we’ve done so far demonstrates how Percy generates snapshots and detects visual changes locally, but to get the most value out of automated visual testing, we recommend integrating Percy with your CI service.

For instructions and to see all of our supported CI services, check out our CI setup documentation. Here are a few of our most popular supported services:

Visual testing is best when done alongside code reviews. We support integrations with GitHub, GitLab, and Bitbucket (coming soon)! With an integration enabled, Percy will show up in your checks commit and pull request checks, notifying you if visual changes are detected:

Clicking "Details" will take you right to the Percy build where you can review visual changes.
After snapshots are approved, your commit status will change to green and the pull request can be merged.

With continuous visual reviews on every feature branch, it’s easy to have 100% confidence the visual changes you’ll be deploying.

We hope this tutorial has helped you get acquainted with Percy’s visual review platform and workflow. To learn more about how Percy works, feel free to check out these docs:

Happy testing! &#x1f49c;

Using Percy to add visual testing to a Jekyll site

Css Tricks - Thu, 06/27/2019 - 4:57am

Visual testing is the automated process of reviewing software from a purely visual standpoint. Instead of testing the code underneath, visual testing is all about what end users actually see and interact with.

Similar to functional testing, however, visual testing fits directly into your stack and workflow. And with Percy, it’s easy to add snapshots to and run visual reviews for anything that runs in a browser.

Let’s set up an app to test

In this tutorial, we’re going to clone an example Jekyll site, add Percy snapshots, make some visual changes, and review them in Percy.

Before we add Percy, let’s set up our example app:

git clone https://github.com/percy/example-percy-jekyll.git

Navigate to your local app, install dependencies, then build and run the site:

cd example-percy-jekyll/ bundle install bundle exec jekyll build bundle exec jekyll serve

Note: Ruby >= 2.3 is required

Open and click around the site locally to see what we’ll be taking Percy snapshots of.

Shoutout to CloudCannon for the Hydra theme.

Next, if you haven’t already, sign up for a free Percy account and create an organization and a new project:

Percy projects correspond to the web application, component library, or static site you’re testing. In this case, we’ll be connecting our Percy project to our Jekyll site.

Generating Percy snapshots

To authenticate your local environment with your new Percy project, copy the PERCY_TOKEN environment variable from the new project screen or your project settings, then run:

$ export PERCY_TOKEN=aaabbbcccdddeee $ npx percy snapshot _site/

Note: Be sure to replace the token with your project-specific token.

You’ll see output like this:

$ npx percy snapshot _site/ Downloading Chromium r662092 - 88.3 Mb [====================] 100% 0.0s [percy] created build #1: https://percy.io/jekyll-test-site/hydra-theme/builds/2048096 [percy] percy has started. [percy] serving static site at http://localhost:5339/ [percy] snapshot taken: '/404.html' [percy] snapshot taken: '/index.html' [percy] snapshot taken: '/about/index.html' [percy] snapshot taken: '/blog/index.html' [percy] snapshot taken: '/contact/index.html' [percy] snapshot taken: '/contact-success/index.html' [percy] snapshot taken: '/pricing/index.html' [percy] snapshot taken: '/category/marketing/index.html' [percy] snapshot taken: '/category/sales/index.html' [percy] snapshot taken: '/category/tips/index.html' [percy] snapshot taken: '/sales/2016/07/20/the-process-for-direct-sales/index.html' [percy] snapshot taken: '/marketing/2016/08/12/the-history-of-marketing/index.html' [percy] snapshot taken: '/sales/2016/08/06/definition-of-sales/index.html' [percy] snapshot taken: '/sales/tips/2016/07/28/effective-upselling-techniques/index.html' [percy] snapshot taken: '/sales/tips/2016/08/02/sales-effectiveness/index.html' [percy] shutting down static site at http://localhost:5339/ [percy] stopping percy... [percy] waiting for 15 snapshots to complete... [percy] done. [percy] finalized build #1: https://percy.io/jekyll-test-site/hydra-theme/builds/2048096

Click the build link or head over to your Percy project to check out your first build.

What’s going on behind the scenes?

Once npx percy snapshot _site/ was called, Percy captured the DOM snapshots for each page of your Jekyll site. Percy then recreated the snapshots to compare against baseline snapshots and determine which pixels have changed.

Since this is the first build, there isn’t anything to compare it to. It has also been auto-approved because the commit was on master and we assume that master builds are production-ready.

Making and reviewing visual changes

Now that you’ve pushed your first build and established a baseline to compare your next snapshots to, let’s make a visual change to review.

Let’s make a wide sweeping CSS change. Head over to the cloudcannon.scss file and change the brand colors:

$brand-color: #ff8a00; $secondary-brand-color: #da1b60;

Since we’re pushing these changes directly to master, be sure to disable auto-approve on master branches from your Percy project settings.

Once those changes are saved, build your site and run Percy again:

$ bundle exec jekyll build $ npx percy snapshot _site/

Head back to Percy or click the Percy build link to see the visual changes!

If you haven’t been following along, you can check out the build.

What’s going on in the Percy UI?

The red areas in the right panel represent pixels that have changed—the visual diffs. Clicking that area (or pressing "d") will toggle between the underlying snapshot and the overlaid diff so you can easily see what exactly has changed. You’ll also notice that the first several diffs have been matched and grouped to make it easier and faster to review.

Each snapshot has been rendered across both Chrome and Firefox, and at mobile and desktop widths. Rendering your site across these variations helps you detect subtle differences caused by browser rendering or responsive bugs.

Now that we’re happy with our fresh new look, hit "Approve All." ✅

You’ve done your first visual review! Visual testing is great not only for catching visual bugs, but also for knowing the exact impact of any given code change. Seeing your UI visualized during code reviews is invaluable, helping you fix regressions before they make their way to production, or to deploy with complete confidence.

Configuring your snapshots

You can configure how and where Percy runs for each build by creating a global .percy.yml file in the root of your project.

You can customize the responsive widths at which your snapshots are rendered. For example, if you want to add a super wide snapshot in addition to our mobile and desktop widths:

version: 1 snapshot: widths: [375, 1280, 1920]

You can also ignore certain pages. For example, if you’d like to ignore multiple pages with the same layout like blog categories posts:

version: 1 static-snapshots: ignore-files: "/blog/category/*"

Learn more about Percy SDK configuration in our docs).

Adding Percy to your workflow

What we’ve done so far demonstrates how Percy generates snapshots and detects visual changes locally, but to get the most value out of automated visual testing, we recommend integrating Percy with your CI service.

For instructions and to see all of our supported CI services, check out our CI setup documentation. Here are a few of our most popular supported services:

Visual testing is best when done alongside code reviews. We support integrations with GitHub, GitLab, and Bitbucket (coming soon)! With an integration enabled, Percy will show up in your checks commit and pull request checks, notifying you if visual changes are detected:

Clicking "Details" will take you right to the Percy build where you can review visual changes.
After snapshots are approved, your commit status will change to green and the pull request can be merged.

With continuous visual reviews on every feature branch, it’s easy to have 100% confidence the visual changes you’ll be deploying.

We hope this tutorial has helped you get acquainted with Percy’s visual review platform and workflow. To learn more about how Percy works, feel free to check out these docs:

Happy testing! &#x1f49c;

The post Using Percy to add visual testing to a Jekyll site appeared first on CSS-Tricks.

Three Predictions From the State of CSS 2019 Survey

Css Tricks - Wed, 06/26/2019 - 2:31pm

Running a developer survey like the State of CSS is a multi-stage process. First, you need to collect the data. Then, you process it into a usable shape. Finally, you come up with nifty ways to visualize it and release it to the world.

But then, once the dust settles and the traffic dies down comes my favorite part: actually thinking about the data. By taking a deeper look at our data, as well as observing how the community discussed our findings, three unexpected trends ended up coming into focus.

But first, some background for those not already familiar with the project.

I first started the State of JavaScript survey three years ago in 2016 as a way to answer my own uncertainties about the future of web development. At the time, JavaScript fatigue was running wild and I thought a comprehensive developer survey could prove itself the antidote.

The original State of JavaScript 2016 edition

Turns out I hit a nerve: that first survey turned out to be very popular, and our audience has grown each year since, along with the scope of the survey. (I was also joined by Raphael Benitte, creator of the Nivo.js dataviz library, to help me with data processing and visualization.) This year marks the first time we're pivoting out into a new dimension, namely the not-so-simple world of CSS.

Taking on CSS Prediction 1: CSS still has a lot of unexplored territory

One of the things we wanted to quantify with the survey was how much of CSS was still left "unexplored." In other words, what CSS features are developers either unfamiliar with, or else hadn't yet used. For that reason we decided early-on to focus our Features section on new CSS properties, like shapes, masking, or scroll-snap rather than “boring” floats or tables.

The resulting data paints an interesting picture: it turns out that when you look at it this way, CSS morphs from a familiar landscape to a wild, unexplored jungle.

A look at comparing Flexbox vs. CSS Grid provides a good illustration of this trend. While nearly everybody who's heard of Flexbox has also used it, only 55% of developers who are aware of CSS Grid have actually tried it. That's a big gap, especially for a technology as important as CSS Grid!

Layout Features

Or take CSS Shapes: 68% of developers are aware of them, only 31% of that group has actually used the feature.

CSS Shapes

This all points at a big gap between what we collectively want to learn and what we actually know. It's that potential for growth that is exactly what makes CSS so exciting in 2019.

Prediction 2: Functional CSS will keep rising

If you're old enough to remember the CSS Zen Garden — or to have actually learned CSS through it (in which case I know how you feel, my back hurts when I get up in the morning as well) — then this next trend might seem weird, or even downright wrong.

CSS Zen Garden: one page, many themes.

Functional CSS rejects the platonic ideal of pure, untainted markup free from any styling concerns and embraces "functional" (aka "atomic" or "utility") classes. Think <div class="text-red text-medium border-1">...</div>.

Adopting this approach means you can't magically update your stylesheet and change your entire design without modifying a single line of markup. But be honest, how often does this happen anyway? Compared to the often theoretical elegance of the Zen Garden philosophy, libraries like Tailwind and Tachyons provide tangible, real-world benefits, which explains why they're so highly regarded. In fact, those take the #1 and #4 spots, respectively, in terms of satisfaction ratio in the CSS Framework category.

Awareness, interest, and satisfaction ratio rankings for CSS frameworks.

Tailwind especially seems to be picking up speed, at least judging by the Twitter engagement from its community in response to the survey results. Having just hit version 1.0, it's definitely a project to keep an eye on!

Prediction 3: The battle for CSS has just begun

Looking at our data, I can't help but wonder if "JavaScript fatigue" will soon be replaced by "CSS fatigue."

When evaluating technologies, it's important to look not just at raw usage numbers, but also at user satisfaction. After all, you don't want to jump on the latest bandwagon just to find out its current occupants can't wait to hop off it.

This scatterplot chart that's divided into quadrants is perfect for this. It plots usage against satisfaction, making it easy to isolate popular, high-satisfaction tools into their own quadrant.

Usage vs. Satisfaction

What's apparent in this chart is that the most densely populated area is the "Assess" quadrant. In other words, the low-usage, high-satisfaction technologies that are still battling it out for supremacy. This is exactly the state that the JavaScript ecosystem finds itself in as well. Many contenders, but few decisive winners as of today.

This is not necessarily a bad thing: yes, it does make the average developer's life harder when it comes to picking the right tool, but hey, this is why we do what we do! Additionally, competition can only be good for the ecosystem as a whole. Once the dust settles, we'll hopefully end up with the best possible options having survived!

CSS in 2019

Overall, the State of CSS survey shows that this is not your grandpa's CSS anymore. For years, we developers have loved to complain about the inadequacies of CSS and its lack of powerful features. But in 2019, CSS is challenging us to put our money where our mouthes are: here's all the features you've always wanted. Now what are you going to do about it?

I, for one, am very excited to dive even deeper into this new world of styling. And, of course, to tune back in 2020 to see what new trends we find then!

Three Predictions From the State of CSS 2019 Survey

Css Tricks - Wed, 06/26/2019 - 2:31pm

Running a developer survey like the State of CSS is a multi-stage process. First, you need to collect the data. Then, you process it into a usable shape. Finally, you come up with nifty ways to visualize it and release it to the world.

But then, once the dust settles and the traffic dies down comes my favorite part: actually thinking about the data. By taking a deeper look at our data, as well as observing how the community discussed our findings, three unexpected trends ended up coming into focus.

But first, some background for those not already familiar with the project.

I first started the State of JavaScript survey three years ago in 2016 as a way to answer my own uncertainties about the future of web development. At the time, JavaScript fatigue was running wild and I thought a comprehensive developer survey could prove itself the antidote.

The original State of JavaScript 2016 edition

Turns out I hit a nerve: that first survey turned out to be very popular, and our audience has grown each year since, along with the scope of the survey. (I was also joined by Raphael Benitte, creator of the Nivo.js dataviz library, to help me with data processing and visualization.) This year marks the first time we're pivoting out into a new dimension, namely the not-so-simple world of CSS.

Taking on CSS Prediction 1: CSS still has a lot of unexplored territory

One of the things we wanted to quantify with the survey was how much of CSS was still left "unexplored." In other words, what CSS features are developers either unfamiliar with, or else hadn't yet used. For that reason we decided early-on to focus our Features section on new CSS properties, like shapes, masking, or scroll-snap rather than “boring” floats or tables.

The resulting data paints an interesting picture: it turns out that when you look at it this way, CSS morphs from a familiar landscape to a wild, unexplored jungle.

A look at comparing Flexbox vs. CSS Grid provides a good illustration of this trend. While nearly everybody who's heard of Flexbox has also used it, only 55% of developers who are aware of CSS Grid have actually tried it. That's a big gap, especially for a technology as important as CSS Grid!

Layout Features

Or take CSS Shapes: 68% of developers are aware of them, only 31% of that group has actually used the feature.

CSS Shapes

This all points at a big gap between what we collectively want to learn and what we actually know. It's that potential for growth that is exactly what makes CSS so exciting in 2019.

Prediction 2: Functional CSS will keep rising

If you're old enough to remember the CSS Zen Garden — or to have actually learned CSS through it (in which case I know how you feel, my back hurts when I get up in the morning as well) — then this next trend might seem weird, or even downright wrong.

CSS Zen Garden: one page, many themes.

Functional CSS rejects the platonic ideal of pure, untainted markup free from any styling concerns and embraces "functional" (aka "atomic" or "utility") classes. Think <div class="text-red text-medium border-1">...</div>.

Adopting this approach means you can't magically update your stylesheet and change your entire design without modifying a single line of markup. But be honest, how often does this happen anyway? Compared to the often theoretical elegance of the Zen Garden philosophy, libraries like Tailwind and Tachyons provide tangible, real-world benefits, which explains why they're so highly regarded. In fact, those take the #1 and #4 spots, respectively, in terms of satisfaction ratio in the CSS Framework category.

Awareness, interest, and satisfaction ratio rankings for CSS frameworks.

Tailwind especially seems to be picking up speed, at least judging by the Twitter engagement from its community in response to the survey results. Having just hit version 1.0, it's definitely a project to keep an eye on!

Prediction 3: The battle for CSS has just begun

Looking at our data, I can't help but wonder if "JavaScript fatigue" will soon be replaced by "CSS fatigue."

When evaluating technologies, it's important to look not just at raw usage numbers, but also at user satisfaction. After all, you don't want to jump on the latest bandwagon just to find out its current occupants can't wait to hop off it.

This scatterplot chart that's divided into quadrants is perfect for this. It plots usage against satisfaction, making it easy to isolate popular, high-satisfaction tools into their own quadrant.

Usage vs. Satisfaction

What's apparent in this chart is that the most densely populated area is the "Assess" quadrant. In other words, the low-usage, high-satisfaction technologies that are still battling it out for supremacy. This is exactly the state that the JavaScript ecosystem finds itself in as well. Many contenders, but few decisive winners as of today.

This is not necessarily a bad thing: yes, it does make the average developer's life harder when it comes to picking the right tool, but hey, this is why we do what we do! Additionally, competition can only be good for the ecosystem as a whole. Once the dust settles, we'll hopefully end up with the best possible options having survived!

CSS in 2019

Overall, the State of CSS survey shows that this is not your grandpa's CSS anymore. For years, we developers have loved to complain about the inadequacies of CSS and its lack of powerful features. But in 2019, CSS is challenging us to put our money where our mouthes are: here's all the features you've always wanted. Now what are you going to do about it?

I, for one, am very excited to dive even deeper into this new world of styling. And, of course, to tune back in 2020 to see what new trends we find then!

The post Three Predictions From the State of CSS 2019 Survey appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.