Developer News

Animating Border

Css Tricks - Tue, 12/05/2017 - 4:26am

Transitioning border for a hover state. Simple, right? You might be unpleasantly surprised.

The Challenge

The challenge is simple: building a button with an expanding border on hover.

This article will focus on genuine CSS tricks that would be easy to drop into any project without having to touch the DOM or use JavaScript. The methods covered here will follow these rules

  • Single element (no helper divs, but psuedo-elements are allowed)
  • CSS only (no JavaScript)
  • Works for any size (not restricted to a specific width, height, or aspect ratio)
  • Supports transparent backgrounds
  • Smooth and performant transition

I proposed this challenge in the Animation at Work Slack and again on Twitter. Though there was no consensus on the best approach, I did receive some really clever ideas by some phenomenal developers.

Method 1: Animating border

The most straightforward way to animate a border is… well, by animating border.

.border-button { border: solid 5px #FC5185; transition: border-width 0.6s linear; } .border-button:hover { border-width: 10px; }

See the Pen by Shaw (@shshaw) on CodePen.

Nice and simple, but there are some big performance issues.

Since border takes up space in the document’s layout, changing the border-width will trigger layout. Nearby elements will shift around because of the new border size, making browser reposition those elements every frame of the animation unless you set an explicit size on the button.

As if triggering layout wasn’t bad enough, the transition itself feels “stepped”. I’ll show why in the next example.

Method 2: Better border with outline

How can we change the border without triggering layout? By using outline instead! You’re probably most familiar with outline from removing it on :focus styles (though you shouldn’t), but outline is an outer line that doesn’t change an element’s size or position in the layout.

.border-button { outline: solid 5px #FC5185; transition: outline 0.6s linear; margin: 0.5em; /* Increased margin since the outline expands outside the element */ } .border-button:hover { outline-width: 10px; }

See the Pen by Shaw (@shshaw) on CodePen.

A quick check in Dev Tools’ Performance tab shows the outline transition does not trigger layout. Regardless, the movement still seems stepped because browsers are rounding the border-width and outline-width values so you don’t get sub-pixel rendering between 5 and 6 or smooth transitions from 5.4 to 5.5.

See the Pen by Shaw (@shshaw) on CodePen.

Strangely, Safari often doesn't render the outline transition and occasionally leaves crazy artifacts.

Method 3: Cut it with clip-path

First implemented by Steve Gardner, this method uses clip-path with calc to trim the border down so on hover we can transition to reveal the full border.

.border-button { /* Full width border and a clip-path visually cutting it down to the starting size */ border: solid 10px #FC5185; clip-path: polygon( calc(0% + 5px) calc(0% + 5px), /* top left */ calc(100% - 5px) calc(0% + 5px), /* top right */ calc(100% - 5px) calc(100% - 5px), /* bottom right */ calc(0% + 5px) calc(100% - 5px) /* bottom left */ ); transition: clip-path 0.6s linear; } .border-button:hover { /* Clip-path spanning the entire box so it's no longer hiding the full-width border. */ clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); }

See the Pen by Shaw (@shshaw) on CodePen.

clip-path technique is the smoothest and most performant method so far, but does come with a few caveats. Rounding errors may cause a little unevenness, depending on the exact size. The border also has to be full size from the start, which may make exact positioning tricky.

Unfortunately there’s no IE/Edge support yet, though it seems to be in development. You can and should encourage Microsoft’s team to implement those features by voting for masks/clip-path to be added.

Method 4: linear-gradient background

We can simulate a border using a clever combination of multiple linear-gradient backgrounds properly sized. In total we have four separate gradients, one for each side. The background-position and background-size properties get each gradient in the right spot and the right size, which can then be transitioned to make the border expand.

.border-button { background-repeat: no-repeat; /* background-size values will repeat so we only need to declare them once */ background-size: calc(100% - 10px) 5px, /* top & bottom */ 5px calc(100% - 10px); /* right & left */ background-position: 5px 5px, /* top */ calc(100% - 5px) 5px, /* right */ 5px calc(100% - 5px), /* bottom */ 5px 5px; /* left */ /* Since we're sizing and positioning with the above properties, we only need to set up a simple solid-color gradients for each side */ background-image: linear-gradient(0deg, #FC5185, #FC5185), linear-gradient(0deg, #FC5185, #FC5185), linear-gradient(0deg, #FC5185, #FC5185), linear-gradient(0deg, #FC5185, #FC5185); transition: all 0.6s linear; transition-property: background-size, background-position; } .border-button:hover { background-position: 0 0, 100% 0, 0 100%, 0 0; background-size: 100% 10px, 10px 100%, 100% 10px, 10px 100%; }

See the Pen by Shaw (@shshaw) on CodePen.

This method is quite difficult to set up and has quite a few cross-browser differences. Firefox and Safari animate the faux-border smoothly, exactly the effect we’re looking for. Chrome’s animation is jerky and even more stepped than the outline and border transitions. IE and Edge refuse to animate the background at all, but they do give the proper border expansion effect.

Method 5: Fake it with box-shadow

Hidden within box-shadow's spec is a fourth value for spread-radius. Set all the other length values to 0px and use the spread-radius to build your border alternative that, like outline, won’t affect layout.

.border-button { box-shadow: 0px 0px 0px 5px #FC5185; transition: box-shadow 0.6s linear; margin: 0.5em; /* Increased margin since the box-shado expands outside the element, like outline */ } .border-button:hover { box-shadow: 0px 0px 0px 10px #FC5185; }

See the Pen by Shaw (@shshaw) on CodePen.

The transition with box-shadow is adequately performant and feels much smoother, except in Safari where it’s snapping to whole-values during the transition like border and outline.

Pseudo-Elements

Several of these techniques can be modified to use a pseudo-element instead, but pseudo-elements ended up causing some additional performance issues in my tests.

For the box-shadow method, the transition occasionally triggered paint in a much larger area than necessary. Reinier Kaper pointed out that a pseudo-element can help isolate the paint to a more specific area. As I ran further tests, box-shadow was no longer causing paint in large areas of the document and the complication of the pseudo-element ended up being less performant. The change in paint and performance may have been due to a Chrome update, so feel free to test for yourself.

I also could not find a way to utilize pseudo-elements in a way that would allow for transform based animation.

Why not transform: scale?

You may be firing up Twitter to helpfully suggest using transform: scale for this. Since transform and opacity are the best style properties to animate for performance, why not use a pseudo-element and have the border scale up & down?

.border-button { position: relative; margin: 0.5em; border: solid 5px transparent; background: #3E4377; } .border-button:after { content: ''; display: block; position: absolute; top: 0; right: 0; bottom: 0; left: 0; border: solid 10px #FC5185; margin: -15px; z-index: -1; transition: transform 0.6s linear; transform: scale(0.97, 0.93); } .border-button:hover::after { transform: scale(1,1); }

See the Pen by Shaw (@shshaw) on CodePen.

There are a few issues:

  1. The border will show through a transparent button. I forced a background on the button to show how the border is hiding behind the button. If your design calls for buttons with a full background, then this could work.
  2. You can’t scale the border to specific sizes. Since the button’s dimensions vary with the text, there’s no way to animate the border from exactly 5px to 10px using only CSS. In this example I’ve done some magic-numbers on the scale to get it to appear right, but that won’t be universal.
  3. The border animates unevenly because the button’s aspect ratio isn’t 1:1. This usually means the left/right will appear larger than the top/bottom until the animation completes. This may not be an issue depending on how fast your transition is, the button’s aspect ratio, and how big your border is.

If your button has set dimensions, Cher pointed out a clever way to calculate the exact scales needed, though it may be subject to some rounding errors.

Beyond CSS

If we loosen our rules a bit, there are many interesting ways you can animate borders. Codrops consistently does outstanding work in this area, usually utilizing SVGs and JavaScript. The end results are very satisfying, though they can be a bit complex to implement. Here are a few worth checking out:

Conclusion

There’s more to borders than simply border, but if you want to animate a border you may have some trouble. The methods covered here will help, though none of them are a perfect solution. Which you choose will depend on your project’s requirements, so I’ve laid out a comparison table to help you decide.

See the Pen by Shaw (@shshaw) on CodePen.

My recommendation would be to use box-shadow, which has the best overall balance of ease-of-implementation, animation effect, performance and browser support.

Do you have another way of creating an animated border? Perhaps a clever way to utilize transforms for moving a border? Comment below or reach me on Twitter to share your solution to the challenge.

Special thanks to Martin Pitt, Steve Gardner, Cher, Reinier Kaper, Joseph Rex, David Khourshid, and the Animation at Work community.

Animating Border is a post from CSS-Tricks

A Front End Developer’s Guide to GraphQL

Css Tricks - Mon, 12/04/2017 - 4:21am

No matter how large or small your application is, you’ll have to deal with fetching data from a remote server at some point. On the front end, this usually involves hitting a REST endpoint, transforming the response, caching it, and updating your UI. For years, REST has been the status quo for APIs, but over the past year, a new API technology called GraphQL has exploded in popularity due to its excellent developer experience and declarative approach to data fetching.

In this post, we’ll walk through a couple of hands-on examples to show you how integrating GraphQL into your application will solve many pain points working with remote data. If you’re new to GraphQL, don’t panic! I’ll also highlight some resources to help you learn GraphQL using the Apollo stack, so you can start off 2018 ahead of the curve.

GraphQL 101

Before we dive into how GraphQL makes your life as a front end developer easier, we should first clarify what it is. When we talk about GraphQL, we're either referring to the language itself or its rich ecosystem of tools. At its core, GraphQL is a typed query language developed by Facebook that allows you to describe your data requirements in a declarative way. The shape of your result matches the shape of your query: in the example below, we can expect to receive back an object with a currency property and a rates property containing an array of objects with both currency and rate keys.

{ rates(currency: "USD") { currency rates { currency rate } } }

When we talk about GraphQL in a broader sense, we’re often referring to the ecosystem of tools that help you implement GraphQL in your application. On the backend, you’ll use Apollo Server to create a GraphQL server, which is a single endpoint that parses a GraphQL request and returns data. How does the server know which data to return? You’ll use GraphQL Tools to build a schema (like a blueprint for your data) and a resolver map (just a series of functions that retrieve your data from a REST endpoint, database, or wherever else you choose).

This all sounds more complicated than it actually is?—?with Apollo Launchpad, a GraphQL server playground, you can create a working GraphQL server in your browser in less than 60 lines of code! 😮 We’ll reference this Launchpad I created that wraps the Coinbase API throughout this post.

You’ll connect your GraphQL server to your application with Apollo Client, a fast and flexible client that fetches, caches, and updates your data for you. Since Apollo Client isn’t coupled to your view layer, you can use it with React, Angular, Vue, or plain JavaScript. Not only is Apollo cross-framework, it’s also cross-platform, with React Native & Ionic supported out of the box.

Let’s give it a try! 🚀

Now that you’re well-versed in what GraphQL is, let’s get our hands dirty with a couple of practical examples that illustrate what it’s like to develop your front end with Apollo. By the end, I think you’ll be convinced that a GraphQL-based architecture with Apollo can help you ship features faster than before.

1. Add new data requirements without adding a new endpoint

We’ve all been here before: You spend hours building a perfect UI component when suddenly, product requirements change. You quickly realize that the data you need to fulfill these new requirements would either require a complicated waterfall of API requests or worse, a new REST endpoint. Now blocked on your work, you ask the backend team to build you a new endpoint just to satisfy the data needs for one component.

This common frustration no longer exists with GraphQL because the data you consume on the client is no longer coupled to an endpoint’s resource. Instead, you always hit the same endpoint for your GraphQL server. Your server specifies all of the resources it has available via your schema and lets your query determine the shape of the result. Let’s illustrate these concepts using our Launchpad from before:

In our schema, look at lines 22–26 where we define our ExchangeRate type. These fields list out all the available resources we can query in our application.

type ExchangeRate { currency: String rate: String name: String }

With REST, you’re limited to the data your resource provides. If your /exchange-rates endpoint doesn’t include name, then you’ll need to either hit a different endpoint like /currency for the data or create it if it doesn’t exist.

With GraphQL, we know that name is already available to us by inspecting our schema, so we can query for it in our application. Try running this example in Launchpad by adding the name field on the right side panel!

{ rates(currency: "USD") { currency rates { currency rate name } } }

Now, remove the name field and run the same query. See how the shape of our result changes?

Your GraphQL server always gives you back exactly the data you ask for. Nothing more. This differs significantly from REST, where you often have to filter and transform the data you get back from the server into the shape your UI components need. Not only does this save you time, it also results in smaller network payloads and CPU savings from loading and parsing the response.

2. Reduce your state management boilerplate

Fetching data almost always involves updating your application’s state. Typically, you’ll write code to track at least three actions: one for when the data is loading, one if the data successfully arrives, and one if the data errors out. Once the data arrives, you have to transform it into the shape your UI components expect, normalize it, cache it, and update your UI. This process can be repetitive, requiring countless lines of boilerplate to execute one request.

Let’s see how Apollo Client eliminates this tiresome process altogether by looking at an example React app in CodeSandbox. Navigate to `list.js` and scroll to the bottom.

export default graphql(ExchangeRateQuery, { props: ({ data }) => { if (data.loading) { return { loading: data.loading }; } if (data.error) { return { error: data.error }; } return { loading: false, rates: data.rates.rates }; } })(ExchangeRateList);

In this example, React Apollo, Apollo Client’s React integration, is binding our exchange rate query to our ExchangeRateList component. Once Apollo Client executes that query, it tracks loading and error state automatically and adds it to the data prop. When Apollo Client receives the result, it will update the data prop with the result of the query, which will update your UI with the rates it needs to render.

Under the hood, Apollo Client normalizes and caches your data for you. Try clicking some of the currencies in the panel on the right to watch the data refresh. Now, select a currency a second time. Notice how the data appears instantaneously? That’s the Apollo cache at work! You get all of this for free just by setting up Apollo Client with no additional configuration. 😍 To see the code where we initialize Apollo Client, check out `index.js`.

3. Debug quickly & painlessly with Apollo DevTools & GraphiQL

It looks like Apollo Client does a lot for you! How do we peek inside to understand what’s going on? With features like store inspection and full visibility into your queries & mutations, Apollo DevTools not only answers that question, but also makes debugging painless and, dare I say it, fun! 🎉 It’s available as an extension for both Chrome and Firefox, with React Native coming soon.

If you want to follow along, install Apollo DevTools for your preferred browser and navigate to our CodeSandbox from the previous example. You’ll need to run the example locally by clicking Download in the top nav bar, unzipping the file, running npm install, and finally npm start. Once you open up your browser’s dev tools panel, you should see a tab that says Apollo.

First, let’s check out our store inspector. This tab mirrors what’s currently in your Apollo Client cache, making it easy to confirm your data is stored on the client properly.

Apollo DevTools also enables you to test your queries & mutations in GraphiQL, an interactive query editor and documentation explorer. In fact, you already used GraphiQL in the first example where we experimented with adding fields to our query. To recap, GraphiQL features auto-complete as you type your query into the editor and automatically generated documentation based on GraphQL’s type system. It’s extremely useful for exploring your schema, with zero maintenance burden for developers.

Try executing queries with GraphiQL in the right side panel of our Launchpad. To show the documentation explorer, you can hover over fields in the query editor and click on the tooltip. If your query runs successfully in GraphiQL, you can be 100% positive that the same query will run successfully in your application.

Level up your GraphQL skills

If you made it to this point, awesome job! 👏 I hope you enjoyed the exercises and got a taste of what it would be like to work with GraphQL on the front end.

Hungry for more? 🌮 Make it your 2018 New Year’s resolution to learn more about GraphQL, as I expect its popularity to grow even more in the upcoming year. Here’s an example app to get you started featuring the concepts we learned today:

Go forth and GraphQL (and be sure to tag us on Twitter @apollographql along the way)! 🚀

A Front End Developer’s Guide to GraphQL is a post from CSS-Tricks

The Three Developers and the Insightful User Tester

Css Tricks - Sun, 12/03/2017 - 11:17am

A story by Scott O'Hara:

The first of the developers, why he thought he knew best.
“I’ll get this done ever so quick!” he said, puffing out his chest.

“While the others review wikis, knowledge bases, and specifications,
I’ll lean on my deep knowledge of CSS to circumvent such onerous proclamations.

Specificity will be lax, and BEM classes will be king!
Everyone will marvel at the CSS of this thing.

Direct Link to ArticlePermalink

The Three Developers and the Insightful User Tester is a post from CSS-Tricks

A Big List of Typography Books

Css Tricks - Sat, 12/02/2017 - 2:56pm

For your holiday gift shopping needs! These my picks for some of the most popular books out there on typography, with a tilt toward web typography. Plus a couple of bonus picks by our own Robin Rendle.

Direct Link to ArticlePermalink

A Big List of Typography Books is a post from CSS-Tricks

24 Ways

Css Tricks - Fri, 12/01/2017 - 6:02pm

24 Ways, the advent calendar for web geeks, started up again this week. Throughout December they’ll be publishing a wide range of posts all about web design, CSS, and front-end development.

Chen Hui Jing has already written a great post about feature queries and Stephanie Drescher published a post today about a tool called sonarwhal which identifies accessibility, performance and security issues, just to name a few.

And if you're into advent calendars, here's another 16 web development related ones.

Direct Link to ArticlePermalink

24 Ways is a post from CSS-Tricks

How the Roman Empire Made Pure CSS Connect 4 Possible

Css Tricks - Fri, 12/01/2017 - 10:09am

Experiments are a fun excuse to learn the latest tricks, think of new ideas, and push your limits. "Pure CSS" demos have been a thing for a while, but new opportunities open up as browsers and CSS itself evolves. CSS and HTML preprocessors also helped the scene move forward. Sometimes preprocessors are used for hardcoding every possible scenario, for example, long strings of :checked and adjacent sibling selectors.

In this article, I will walk through the key ideas of a Pure CSS Connect 4 game I built. I tried to avoid hardcoding as much as I could in my experiment and worked without preprocessors to focus on keeping the resulting code short. You can see all the code and the game right here:

See the Pen Pure CSS Connect 4 by Bence Szabó (@finnhvman) on CodePen.

Essential concepts

I think there are some concepts that are considered essential in the "pure CSS" genre. Typically form elements are used for managing state and capturing user actions. I was excited when I found people use <button type="reset"> to reset or start a new game. All you have to do is wrap your elements in a <form> tag and add the button. In my opinion this is a much cleaner solution than having to refresh the page.

My first step was to create a form element then throw a bunch of inputs into it for the slots and add the reset button. Here is a very basic demonstration of <button type="reset"> in action:

See the Pen Pure HTML Form Reset by Bence Szabó (@finnhvman) on CodePen.

I wanted to have nice visual for this demo to provide a full experience. Instead of pulling in an external image for the board or the discs, I used a radial-gradient(). A nice resource I often use is Lea Verou's CSS3 Patterns Gallery. It is a collection of patterns made by gradients, and they're editable too! I used currentcolor, which came pretty handy for the disc pattern. I added a header and reused my Pure CSS Ripple Button.

At this point the layout and disc design was already final, only the game didn't work at all Dropping discs onto the board

Next I enabled users to take their turns dropping discs onto the Connect 4 board. In Connect 4, players (one red and one yellow) drop discs into columns in alternating turns. There are 7 columns and 6 rows (42 slots). Each slot can be empty or occupied by a red or yellow disc. So, a slot can have three states (empty, red, or yellow). Discs dropped in the same column are stacked onto each other.

I started out by placing two checkboxes for each slot. When they're both unchecked the slot is considered empty, and when one of them is checked the corresponding player has its disc in it.

The possible state of having them both checked should be avoided by hiding them once either of them is checked. These checkboxes are immediate siblings, so when the first of a pair is checked you can hide both by using :checked pseudo-class and the adjacent sibling combinator (+). What if the second is checked? You can hide the second one, but how to affect the first one? Well, there is no previous sibling selector, that's just not how CSS selectors work. I had to reject this idea.

Actually, a checkbox can have three states by itself, it can be in the indeterminate state. The problem is that you can't put it into indeterminate state with HTML alone. Even if you could, the next click on the checkbox would always make it transform into checked state. Forcing the second player to double-click when they make their move is unreliable and unacceptable.

I was stuck on the MDN doc of :indeterminate and noticed that radio inputs also have indeterminate state. Radio buttons with the same name are in this state when they're all unchecked. Wow, that's an actual initial state! What's really beneficial is that checking the latter sibling also has an effect on the former one! Thus I filled the board with 42 pairs of radio inputs.

In retrospect, clever ordering and usage of labels with either checkboxes or radio buttons would have made the trick, but I didn't consider labels to be an option to keep the code simpler and shorter.

I wanted to have large areas for interaction to have nice UX, so I thought it's reasonable to let players make a move by clicking on a column. I stacked controls of the same column on each other by adding absolute and relative positioning to the appropriate elements. This way only the lowest empty slot could be selected within a column. I meticulously set the time of transition of disc fall per row and their timing function is approximating a quadratic curve to resemble realistic free fall. So far the pieces of the puzzle came well together, though the animation below clearly shows that only the red player could make their moves.

Even though all the controls are there, only red discs can be dropped on the board

The clickable areas of radio inputs are visualized with colored but semi-transparent rectangles. The yellow and red inputs are stacked over each other six times(=six rows) per column, leaving the red input of the lowest row on top of the stack. The mixture of red and yellow creates the orangish color which can be seen on the board at start. The less empty slots are available in a column, the less intense this orangish color gets since the radio inputs are not displayed once they are not :indeterminate. Due to the red input always being precisely over the yellow input in every slot, only the red player is able to make moves.

Tracking turns

I only had a faint idea and a lot of hope that I can somehow solve switching turns between the two players with the general sibling selector. The concept was to let the red player take turn when the number of checked inputs was even (0, 2, 4, etc.) and let the yellow player take turn when that number was odd. Soon I realized that the general sibling selector does not (and should not!) work the way I wanted.

Then a very obvious choice was to experiment with the nth selectors. However attracting it was to use the even and odd keywords, I ran into a dead end. The :nth-child selector "counts" the children within a parent, regardless of type, class, pseudo-class, whatever. The :nth-of-type selector "counts" children of a type within a parent, regardless of class or pseudo-class. So the problem is that they cannot count based on the :checked state.

Well CSS counters count too, so why not give them a try? A common usage of counters is to number headings (even in multiple levels) in a document. They are controlled by CSS rules, can be arbitrarily reset at any point and their increment (or decrement!) values can be any integer. The counters are displayed by the counter() function in the content property.

The easiest step was to set up a counter and count the :checked inputs in the Connect 4 grid. There are only two difficulties with this approach. The first is you cannot perform arithmetics on a counter to detect if its is even or odd. The second is that you cannot apply CSS rules to elements based on the counter value.

I managed to overcome the first issue by making the counter binary. The value of the counter is initially zero. When the red player checks their radio button the counter is incremented by one. When the yellow player checks their radio button the counter is decremented by one, and so on. Therefore the counter value will be either zero or one, even or odd.

Solving the second problem required much more creativity (read: hack). As mentioned counters can be displayed, but only in the ::before and ::after pseudo-elements. That is a no-brainer, but how can they affect other elements? At the very least the counter value can change the width of the pseudo-element. Different numbers have different widths. Character 1 is typically thinner than 0, but that is something very hard to control. If the number of characters change rather than the character itself the resulting width change is more controllable. It is not uncommon to use Roman numerals with CSS counters. One and two represented in Roman numerals are the same character once and twice and so are their widths in pixels.

My idea was to attach the radio buttons of one player (yellow) to the left, and attach the radio buttons of the other player (red) to the right of their shared parent container. Initially, the red buttons are overlaid on the yellow buttons, then the width change of the container would cause the red buttons to "go away" and reveal the yellow buttons. A similar real-world concept is the sliding window with two panes, one pane is fixed (yellow buttons), the other is slidable (red buttons) over the other. The difference is that in the game only half of the window is visible.

So far, so good, but I still wasn't satisfied with font-size (and the other font properties) indirectly controlling the width. I thought letter-spacing would fit nicely here, since it only increases the size in one dimension. Unexpectedly, even one letter has letter spacing (which is rendered after the letter), and two letters render the letter spacing twice. Predictable widths are crucial to make this reliable. Zero width characters along with single and double letter spacing would work, but it is dangerous to set the font-size to zero. Defining large letter-spacing (in pixels) and tiny (1px) font-size made it almost consistent across all browsers, yes I'm talking about sub-pixels.

I needed the container width to alternate between initial size (=w) and at least double the initial size (>=2w) to be able to fully hide and show the yellow buttons. Let's say v is the rendered width of the 'i' character (lower roman representation, varies across browsers), and c is the rendered width (constant) of the letter-spacing. I needed v + c = w to be true but it couldn't be, because c and w are integers but v is non-integer. I ended up using min-width and max-width properties to constrain the possible width values, so I also changed the possible counter values to 'i' and 'iii' to make sure the text widths underflow and overflow the constraints. In equations this looked like v + c < w, 3v + 3c > 2w, and v << c, which gives 2/3w < c < w. The conclusion is that the letter-spacing has to be somewhat smaller than the initial width.

I have been reasoning so far as if the pseudo element displaying the counter value was the parent of the radio buttons, it is not. However, I noticed that the width of the pseudo-element changes the width of its parent element, and in this case the parent is the container of the radio buttons.

If you are thinking couldn't this be solved with Arabic numerals? You are right, alternating the counter value between something like '1' and '111' would also work. Nevertheless, Roman numerals gave me the idea in the first place, and they were also a good excuse for the clickbaity title so I kept them.

The players take alternating turns starting with the red player

Applying the technique discussed makes the parent container of the radio inputs double in width when a red input is checked and makes it original width when a yellow input is checked. In the original width container the red inputs are over the yellow ones, but in the double width container, the red inputs are moved away.

Recognizing patterns

In real life, the Connect 4 board does not tell you if you have won or lost, but providing proper feedback is part of good user experience in any software. The next objective is to detect whether a player has won the game. To win the game a player has to have four of their discs in a column, row or diagonal line. This is a very simple task to solve in many programming languages, but in pure CSS world, this is a huge challenge. Breaking it down to subtasks is the way to approach this systematically.

I used a flex container as the parent of the radio buttons and discs. A yellow radio button, a red radio button and a div for the disc belong to a slot. Such a slot is repeated 42 times and arranged in columns that wrap. Consequently, the slots in a column are adjacent, which makes recognizing four in a column the easiest part using the adjacent selector:

<div class="grid"> <input type="radio" name="slot11"> <input type="radio" name="slot11"> <div class="disc"></div> <input type="radio" name="slot12"> <input type="radio" name="slot12"> <div class="disc"></div> ... <input type="radio" name="slot16"> <input type="radio" name="slot16"> <div class="disc"></div> <input type="radio" name="slot21"> <input type="radio" name="slot21"> <div class="disc"></div> ... </div> /* Red four in a column selector */ input:checked + .disc + input + input:checked + .disc + input + input:checked + .disc + input + input:checked ~ .outcome /* Yellow four in a column selector */ input:checked + input + .disc + input:checked + input + .disc + input:checked + input + .disc + input:checked ~ .outcome

This is a simple but ugly solution. There are 11 type and class selectors chained together per player to cover the case of four in a column. Adding a div with class of .outcome after the elements of the slots makes it possible to conditionally display the outcome message. There is also a problem with falsely detecting four in a column where the column is wrapped, but let's just put this issue aside.

A similar approach for detecting four in a row would be truly a terrible idea. There would be 56 selectors chained together per player (if I did the math right), not to mention that they would have a similar flaw of false detection. This is a situation where the :nth-child(An+B [of S]) or the column combinators will come handy in the future.

For better semantics one could add a new div for each column and arrange the slot elements in them. This modification would also eliminate the possibility of false detection mentioned above. Then detecting four in a row could go like: select a column where the first red radio input is checked, and select the adjacent sibling column where the first red radio input is checked, and so on two more times. This sounds very cumbersome and would require the "parent" selector.

Selecting the parent is not feasible, but selecting the child is. How would detecting four in a row go with available combinators and selectors? Select a column, then select its first red radio input if checked, and select the adjacent column, then select its first red radio input if checked, and so on two more times. It still sounds cumbersome, yet possible. The trick is not only in the CSS but also in the HTML, the next column has to be the sibling of the radio buttons in the previous column creating a nested structure.

<div class="grid column"> <input type="radio" name="slot11"> <input type="radio" name="slot11"> <div class="disc"></div> ... <input type="radio" name="slot16"> <input type="radio" name="slot16"> <div class="disc"></div> <div class="column"> <input type="radio" name="slot21"> <input type="radio" name="slot21"> <div class="disc"></div> ... <input type="radio" name="slot26"> <input type="radio" name="slot26"> <div class="disc"></div> <div class="column"> ... </div> </div> </div> /* Red four in a row selectors */ input:nth-of-type(2):checked ~ .column > input:nth-of-type(2):checked ~ .column > input:nth-of-type(2):checked ~ .column > input:nth-of-type(2):checked ~ .column::after, input:nth-of-type(4):checked ~ .column > input:nth-of-type(4):checked ~ .column > input:nth-of-type(4):checked ~ .column > input:nth-of-type(4):checked ~ .column::after, ... input:nth-of-type(12):checked ~ .column > input:nth-of-type(12):checked ~ .column > input:nth-of-type(12):checked ~ .column > input:nth-of-type(12):checked ~ .column::after

Well the semantics are messed up and these selectors are only for the red player (another round goes for the yellow player), on the other hand it does work. A little benefit is that there will be no falsely detected columns or rows. The display mechanism of the outcome also had to be modified, using the ::after pseudo element of any matching column is a consistent solution when proper styling is applied. As a result of this, a fake eighth column has to be added after the last slot.

As seen in the code snippet above, specific positions within a column are matched to detect four in a row. The very same technique can be used for detecting four in a diagonal by adjusting these positions. Note that the diagonals can are in two directions.

input:nth-of-type(2):checked ~ .column > input:nth-of-type(4):checked ~ .column > input:nth-of-type(6):checked ~ .column > input:nth-of-type(8):checked ~ .column::after, input:nth-of-type(4):checked ~ .column > input:nth-of-type(6):checked ~ .column > input:nth-of-type(8):checked ~ .column > input:nth-of-type(10):checked ~ .column::after, ... input:nth-of-type(12):checked ~ .column > input:nth-of-type(10):checked ~ .column > input:nth-of-type(8):checked ~ .column > input:nth-of-type(6):checked ~ .column::after

The number of selectors have increased vastly in the final run, and this is definitely a place where CSS preprocessors could reduce the length of the declaration. Still, I think the demo is moderately short. It should be somewhere around the middle on the scale from hardcoding a selector for every possible winning pattern to using 4 magical selectors (column, row, two diagonals).

A message is shown when a player wins Closing loopholes

Any software has edge cases and they need to be handled. The possible outcomes of a Connect 4 game are not only the red, or yellow player winning, but neither player winning filling the board known as draw. Technically this case doesn't break the game or produce any errors, what's missing is the feedback to the players.

The goal is to detect when there are 42 :checked radio buttons on the board. This also means that none of them are in the :indeterminate state. That is requiring a selection to be made for each radio group. Radio buttons are invalid, when they are :indeterminate, otherwise they are valid. So I added the required attribute for each input, then used the :valid pseudo-class on the form to detect draw.

The draw outcome message is shown when the board is filled

Covering the draw outcome introduced a bug. In the very rare case of the yellow player winning on last turn, both the win and draw messages are displayed. This is because the detection and display method of these outcomes are orthogonal. I worked around the issue by making sure that the win message has a white background and is over the draw message. I also had to delay the fade in transition of the draw message, so it would not get blended with the win message transition.

The yellow wins message is over the draw outcome preventing it to be displayed

While a lot of radio buttons are hid behind each other by absolute positioning, all of those in indeterminate state can still be accessed by tabbing through the controls. This enables players to drop theirs discs into arbitrary slots. A way to handle this is to simply forbid keyboard interactions by the tabindex attribute: setting it to -1 means that it should not be reachable via sequential keyboard navigation. I had to augment every radio input with this attribute to eliminate this loophole.

<input type="radio" name="slot11" tabindex="-1" required> <input type="radio" name="slot11" tabindex="-1" required> <div class="disc"></div> ... Limitations

The most substantial drawback is that the board isn't responsive and it might malfunction on small viewports due to the unreliable solution of tracking turns. I didn't dare to take the risk of refactoring to a responsive solution, due to the nature of the implementation it feels much safer with hardcoded dimensions.

Another issue is the sticky hover on touch devices. Adding some interaction media queries to the right places is the easiest way to cure this, though it would eliminate the free fall animation.

One might think that the :indeterminate pseudo-class is already widely supported, and it is. The problem is that it is only partially supported in some browsers. Observe Note 1 in the compatibility table: MS IE and Edge do not support it on radio buttons. If you view the demo in those browsers your cursor will turn into the not-allowed cursor on the board, this is an unintentional but somewhat graceful degradation.

Not all browsers support :indeterminate on radio buttons Conclusion

Thanks for making it to the last section! Let's see some numbers:

  • 140 HTML elements
  • 350 (reasonable) lines of CSS
  • 0 JavaScript
  • 0 external resources

Overall, I'm satisfied with the result and the feedback was great. I sure learned a lot making this demo and I hope I could share a lot writing this article!

How the Roman Empire Made Pure CSS Connect 4 Possible is a post from CSS-Tricks

Font of the Month Club

Css Tricks - Thu, 11/30/2017 - 1:02pm

Every month for the past year, David Jonathan Ross has been publishing a new font to his Font of the Month Club. It’s only $6 for a monthly subscription and it provides early access to some of his work. I’d highly recommend signing up because each design is weird and intriguing in a very good way:

Join the Font of the Month Club and get a fresh new font delivered to your inbox every single month! Each font is lovingly designed and produced by me, David Jonathan Ross.

Fonts of the month are not available anywhere else, and will include my distinctive display faces, experimental designs, and exclusive previews of upcoming retail typeface families.

Direct Link to ArticlePermalink

Font of the Month Club is a post from CSS-Tricks

The Front-End Checklist is just a tool… everything depends on you.

Css Tricks - Thu, 11/30/2017 - 11:41am

One month ago, I launched the Front-End Checklist on GitHub. In less than 2 weeks, more than 10,000 people around the world starred the repository. That was completely unexpected and incredible!

I've been working as a front-end developer since 2011, but I started to build websites in 2000. Since then, like us all, I've been trying to improve the quality of my code and deliver websites faster. Along the way, I've been managing developers from two different countries. That has helped me to produce a checklist a little different than what I've found on around the web over the years.

While I was creating the checklist, I continuously had the book "The Checklist Manifesto: How to Get Things Right" by Atul Gawade in mind. That book has helped me build checklists for my work and personal life, and simplify things that sometimes seem too complex.

amzn_assoc_tracking_id = "csstricks-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_design = "enhanced_links"; amzn_assoc_asins = "0312430000"; amzn_assoc_placement = "adunit"; amzn_assoc_linkid = "bc96260be7adede1459bf758a120d189";

If you are working alone or in a team, individually, remotely, or on-site, I wanted to share some advice on using the Front-End Checklist and the web application that goes with it. Perhaps I can convince you to integrate it into your development cycle.

#1 Decide which rules your project and team need to follow

Every project is different. Before starting a new project, the whole team (i.e. the project managers, designers, developers, QA, etc.) need to agree on what the deliverables will be.

To help you to decide, I created 3 different levels of priority: high, medium, and low. You don't necessarily need to agree with those distinctions, but they may help order your tasks.

The Front-End Checklist app was done to facilitate the creation of personalized checklists. Change some JSON files to your liking and you are ready to start!

#2 Define the rules to check at beginning, during, and at the end of your project

You shouldn't check all these rules only at the end of a project. You know as well as I do how projects are at the very end! Too hectic. Most of the items of the Front-End Checklist can be considered at the beginning of your development. It's up to you to decide. Make it clear to your team upfront what happens when.

#3 Learn a little more about each rules

Who loves reading the docs? Not most of us, but it's essential. If you want to understand the reasons for the rule, you can't avoid reading up about them. The more you understand the why of each rule, the better developer you become.

#4 Start to check!

The Front-End Checklist app can facilitate your life as a developer. It's a live checklist, so as you complete items your progress and grade are updated live. Everything is saved in localStorage so you can leave and come back as needed.

The project is open source, so feel free to fork it and use it however you like. I'm working on making sure all the files are commented. I especially invite those interested in Pug to take a look at the views folder.

#5 Integrate automated testing in your workflow

We all dream of automation (or is it just me?). For now, the Front-End Checklist is just an interactive list, but some of the tasks can be automated in your workflow.

Take a look at the gulpfile used to generate the project. All tasks are packages you can use with npm, webpack, etc.

#6 Validate every pages before sending to QA team and to production

If you're passionate about generating clean code and care about your code quality, you should be regularly testing your pages. It's so easy to make mistakes and remove some essential code. Or, someone else on your team might have done it, but it's your shared responsibilty to be catching things like that.

The Front-End Checklist can generate beautiful reports you can send to a project manager or Quality Assurance team.

#7 Enjoy your work above all

Some people might look at such a long checklist and feel sick to their stomach. Going through such a list might cause anxiety and really not be any fun.

But the Front-End Checklist is just a tool to help you deliver higher quality code. Code that affects all aspects of a project: the SEO, the user experience, the ROI, and ultimately the success of the project. A tool that can help across all those things might actually help reduce your anxiety and improve your health!

Conclusion

The success the Front-End Checklist received in such a short time reminded me that a lot of people are really interested in finding ways to improve their work. But just because the tool exists doesn't directly help with that. You also need to commit to using it.

In a time where AI is taking over many manual tasks, quality is a must-have. Even if automation takes over a lot of our tasks, some level of quality will remain impossible to automate, and us front-end developers still have many long days to enjoy our jobs.

The Front-End Checklist is just a tool… everything depends on you. is a post from CSS-Tricks

?7 Days of Free Stock Images

Css Tricks - Thu, 11/30/2017 - 8:12am

(This is a sponsored post.)

Storyblocks is exploding with over 400,000 stock photos, vectors, backgrounds and more! With its user friendly site, massive library to choose from, and fresh new content, there’s no stopping what you can do. All of the content is 100% free from any royalties. Anything you download is yours to keep and use forever! Right now you can get 7 days of free downloads. Get up to 20 photos, icons, and vectors everyday for 7 days. That's 140 downloads free over the course of the 7 days. Click on over and see where your imagination takes you! Start downloading now.

Direct Link to ArticlePermalink

?7 Days of Free Stock Images is a post from CSS-Tricks

Localisation and Translation on the Web

Css Tricks - Wed, 11/29/2017 - 5:56pm

The other day Chris wrote about how the CodePen team added lang='en' to the html element in all pens for accessibility reasons and I thought it was pretty interesting but I suddenly wanted to learn more about that attribute because I’ve never designed a website in any other language besides English and it might be useful for the future.

As if by magic Ire Aderinokun published this piece on Localisation and Translation on the Web just a couple of days later and thankfully it answers all those questions I had:

Coming from the English-speaking world, it can be easy to maintain the bubble that is the English-speaking World Wide Web. But in fact, more than half of web pages are written in languages other than English.

Since starting work at eyeo, I’ve had to think a lot more about localisation and translations because most of our websites are translated into several languages, something I previously didn’t have to really consider before. Once you decide to translate a web page, there are many things to take into account, and a lot of them I've found are useful even if your website is written in only one language.

I had no idea about the experimental, and currently unsupported, translate attribute or the mysterious margin-inline-start CSS property. Handy stuff!

Direct Link to ArticlePermalink

Localisation and Translation on the Web is a post from CSS-Tricks

Fontastic Web Performance

Css Tricks - Wed, 11/29/2017 - 5:54pm

In this talk Monica Dinculescu takes a deep dive into webfonts and how the font-display CSS property lets us control the way those fonts are rendered. She argues that there’s all sorts of huge performance gains to be had if we just spend a little bit of time thinking about the total number of fonts we load and how they’re loaded.

Also, Monica made a handy demo that gives an even more detailed series of examples of how the font-display property works:

This depends a lot on how you are using your webfont, and whether rendering the text in a fallback font makes sense. For example, if you're rendering the main body text on a site, you should use font-display:optional. On browsers that implement it, like Chrome, the experience will be much nicer: your users will get fast content, and if the web font download takes too long, they won't get a page relayout halfway through reading your article.

If you're using a web font for icons, there is no acceptable fallback font you can render these icons in (unless you're using emoji or something), so your only option is to completely block until the font is ready, with font-display:block.

Direct Link to ArticlePermalink

Fontastic Web Performance is a post from CSS-Tricks

WordPress + React

Css Tricks - Wed, 11/29/2017 - 9:58am

I posted just 2 months ago about Foxhound and how I found it pretty cool, but also curious that it was one of very few themes around that combine the WordPress JSON API and React, even though they seem like a perfect natural fit. Like a headless CMS, almost.

Since then, a few more things have crossed my desk of people doing more with this idea and combination.

Maxime Laboissonniere wrote Strapping React.js on a WordPress Backend: WP REST API Example:

I'll use WordPress as a backend, and WordPress REST API to feed data into a simple React e-commerce SPA:

  • Creating products with the WP Advanced Custom Fields plugin
  • Mapping custom fields to JSON payload
  • Consuming the JSON REST API with React
  • Rendering products in our store

Perhaps more directly usable, Postlight have put out a Starter Kit. Gina Trapani:

People who publish on the web love WordPress. Engineers love React. With some research, configuration, and trial and error, you can have both?—?but we’d like to save you the work.

Here's that repo.

Direct Link to ArticlePermalink

WordPress + React is a post from CSS-Tricks

V6: Typography and Proportions

Css Tricks - Tue, 11/28/2017 - 12:56pm

Here’s a good ol’ fashion blog post by Rob Weychert where he looks into the new design system that he implemented on his personal website and specifically the typographic system that ties everything together:

According to the OED, a scale is “a graduated range of values forming a standard system for measuring or grading something.” A piece of music using a particular scale—a limited selection of notes with a shared mathematic relationship—can effect a certain emotional tenor. Want to write a sad song? Use a minor scale. Changed your mind? Switch to a major scale and suddenly that same song is in a much better mood.

Spatial relationships can likewise achieve a certain visual harmony using similar principles, and the constraints a scale provides take a lot of the arbitrary guesswork out of the process of arranging elements in space. Most of what I design that incorporates type has a typographic scale as its foundation, which informs the typeface choices and layout proportions. The process of creating that scale begins by asking what the type needs to do, and what role contrasting sizes will play in that.

Direct Link to ArticlePermalink

V6: Typography and Proportions is a post from CSS-Tricks

An Idea for a Simple Responsive Spreadsheet

Css Tricks - Tue, 11/28/2017 - 9:02am

How do you make a spreadsheet-like interface responsive without the use of any JavaScript? This is the question I've been asking myself all week as I've been working on a new project and trying to figure out how to make the simplest spreadsheet possible. I wanted to avoid using a framework and instead, I decided to experiment with some new properties in order to use nothing but a light touch of CSS.

Spoilers! This is what I've come up with so far (oh and please note that this demo currently works in the latest version of Chrome). Try scrolling around a little bit:

See the Pen A Simple Responsive Spreadsheet – Final by Robin Rendle (@robinrendle) on CodePen.

Notice how the first column sticks to the left and the heading sticks to the top of the spreadsheet? This lets us scan lots of data without having to keep scrolling to figure out which column or row we're in — in a lot of interfaces like this it's pretty easy to get lost.

So how did I go about making this thing? Let's jump in!

Adding the markup

First we need to add our markup for the table and, just to make sure that this example is as realistic as possible, we're going to add a lot of rows and columns here:

See the Pen A Simple Responsive Spreadsheet – 1st by Robin Rendle (@robinrendle) on CodePen.

There's nothing really complex going on. We just have a regular ol' table with a <thead> and a <tbody>, but we do wrap the whole table in the table-wrapper div which I'll explain in just a little bit.

Next, we'll add basic styling to that wrapper element to move it into the center of the page and also give it a max-width. We also need to make sure that the .table-wrapper has overflow set to scroll, although at larger screen sizes we won't need that just yet:

body { display: flex; font-family: -apple-system; font-size: 90%; color: #333; justify-content: center; } .table-wrapper { max-width: 700px; overflow: scroll; }

See the Pen A Simple Responsive Spreadsheet – 2nd by Robin Rendle (@robinrendle) on CodePen.

Nifty! Now we can add styles for the first column of our table and the thead element as well as basic styling for each of the table cells:

table { border: 1px solid #ddd; border-collapse: collapse; } td, th { white-space: nowrap; border: 1px solid #ddd; padding: 20px; }

See the Pen A Simple Responsive Spreadsheet – 3 by Robin Rendle (@robinrendle) on CodePen.

The problem here is that we've now made a pretty inaccessible table; although we can scroll around in the spreadsheet we can't read which column or row is associated to which bit of data. This can lead to a table that is almost completely illegible and if we were to populate this with real data then it would be even worse:

position: sticky to the rescue!

position: sticky is a wonderfully handy CSS trick that I've started experimenting with a great deal lately. It lets you stick child elements to their parent containers so that as you scroll around the child element is always visible. And this is exactly what we need here for the first column and the heading of our table element.

We can use this relatively new feature with CSS like this:

// The heading of our table th { background-color: #eee; position: sticky; top: -1px; z-index: 2; // The first cell that lives in the top left of our spreadsheet &:first-of-type { left: 0; z-index: 3; } } // The first column that we want to stick to the left tbody tr td:first-of-type { background-color: #eee; position: sticky; left: -1px; z-index: 1; }

This z-index values are important here because we want the header to overlap the first left hand column that will also be sticky. However! We also want that empty cell at the top left to overlap both our header and our left hand column, like this:

See the Pen A Simple Responsive Spreadsheet – Final by Robin Rendle (@robinrendle) on CodePen.

But there we have it! A simple responsive spreadsheet where you can view both the heading and the first column no matter where you are in the table. Although, it's worth noting that your mileage may vary. position: sticky has relatively patchy support right now and so it's worth thoroughly testing before you start using it. Or you could use something like Stickybits that would act as a lightweight polyfill.

Also, if you need to dig into tables in more depth then we've made a rather handy Complete Guide to the Table Element.

An Idea for a Simple Responsive Spreadsheet is a post from CSS-Tricks

Introducing minmax()

Css Tricks - Tue, 11/28/2017 - 9:00am

It’s relatively easy to get lost in all the new features of CSS Grid because there’s just so much to learn and familiarize ourselves with; it’s much easier to learn it chunk by chunk in my opinion.

And so you might already be familiar with Rachel Andrew’s Grid By Example which contains a whole bunch of tutorials with new layout tips and tricks about CSS Grid. But the minmax() tutorial is one small chunk of Grid that you can learn today and thankfully Rachel has made a rather handy two minute long video that dives straight into it.

In fact, it’s pretty darn impressive how many opportunities just one new CSS feature can give us.

Direct Link to ArticlePermalink

Introducing minmax() is a post from CSS-Tricks

Animating Layouts with the FLIP Technique

Css Tricks - Mon, 11/27/2017 - 1:41pm

User interfaces are most effective when they are intuitive and easily understandable to the user. Animation plays a major role in this - as Nick Babich said, animation brings user interfaces to life. However, adding meaningful transitions and micro-interactions is often an afterthought, or something that is "nice to have" if time permits. All too often, we experience web apps that simply "jump" from view to view without giving the user time to process what just happened in the current context.

This leads to unintuitive user experiences, but we can do better, by avoiding "jump cuts" and "teleportation" in creating UIs. After all, what's more natural than real life, where nothing teleports (except maybe car keys), and everything you interact with moves with natural motion?

In this article, we'll explore a technique called "FLIP" that can be used to animate the positions and dimensions of any DOM element in a performant manner, regardless of how their layout is calculated or rendered (e.g., height, width, floats, absolute positioning, transform, flexbox, grid, etc.)

Why the FLIP technique?

Have you ever tried to animate height, width, top, left, or any other properties besides transform and opacity? You might have noticed that the animations look a bit janky, and there's a reason for that. When any property that triggers layout changes (such as `height`), the browser has to recursively check if any other element's layout has changed as a result, and that can be expensive. If that calculation takes longer than one animation frame (around 16.7 milliseconds), then the animation frame will be skipped, resulting in "jank" since that frame wasn't rendered in time. In Paul Lewis' article "Pixels are Expensive", he goes further in depth at how pixels are rendered and the various performance expenses.

In short, our goal is to be short - we want to calculate the least amount of style changes necessary, as quickly as possible. The key to this is only animating transform and opacity, and FLIP explains how we can simulate layout changes using only transform.

What is FLIP?

FLIP is a mnemonic device and technique first coined by Paul Lewis, which stands for First, Last, Invert, Play. His article contains an excellent explanation of the technique, but I'll outline it here:

  • First: before anything happens, record the current (i.e., first) position and dimensions of the element that will transition. You can use element.getBoundingClientRect() for this, as will be shown below.
  • Last: execute the code that causes the transition to instantaneously happen, and record the final (i.e., last) position and dimensions of the element.*
  • Invert: since the element is in the last position, we want to create the illusion that it's in the first position, by using transform to modify its position and dimensions. This takes a little math, but it's not too difficult.
  • Play: with the element inverted (and pretending to be in the first position), we can move it back to its last position by setting its transform to none.

Below is how these steps can be implemented with the Web Animations API:

const elm = document.querySelector('.some-element'); // First: get the current bounds const first = elm.getBoundingClientRect(); // execute the script that causes layout change doSomething(); // Last: get the final bounds const last = elm.getBoundingClientRect(); // Invert: determine the delta between the // first and last bounds to invert the element const deltaX = first.left - last.left; const deltaY = first.top - last.top; const deltaW = first.width / last.width; const deltaH = first.height / last.height; // Play: animate the final element from its first bounds // to its last bounds (which is no transform) elm.animate([{ transformOrigin: 'top left', transform: ` translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH}) ` }, { transformOrigin: 'top left', transform: 'none' }], { duration: 300, easing: 'ease-in-out', fill: 'both' });

Note: At the time of writing, the Web Animations API is not yet supported in all browsers. However, you can use a polyfill.

See the Pen How the FLIP technique works by David Khourshid (@davidkpiano) on CodePen.

There are two important things to note:

  1. If the element's size changed, you can transform scale in order to "resize" it with no performance penalty; however, make sure to set transformOrigin to 'top left' since that's where we based our delta calculations.
  2. We're using the Web Animations API to animate the element here, but you're free to use any other animation engine, such as GSAP, Anime, Velocity, Just-Animate, Mo.js and more.
Shared Element Transitions

One common use-case for transitioning an element between app views and states is that the final element might not be the same DOM element as the initial element. In Android, this is similar to a shared element transition, except that the element isn't "recycled" from view to view in the DOM as it is on Android.
Nevertheless, we can still achieve the FLIP transition with a little magic illusion:

const firstElm = document.querySelector('.first-element'); // First: get the bounds and then hide the element (if necessary) const first = firstElm.getBoundingClientRect(); firstElm.style.setProperty('visibility', 'hidden'); // execute the script that causes view change doSomething(); // Last: get the bounds of the element that just appeared const lastElm = document.querySelector('.last-element'); const last = lastElm.getBoundingClientRect(); // continue with the other steps, just as before. // remember: you're animating the lastElm, not the firstElm.

Below is an example of how two completely disparate elements can appear to be the same element using shared element transitions. Click one of the pictures to see the effect.

See the Pen FLIP example with WAAPI by David Khourshid (@davidkpiano) on CodePen.

Parent-Child Transitions

With the previous implementations, the element bounds are based on the window. For most use cases, this is fine, but consider this scenario:

  • An element changes position and needs to transition.
  • That element contains a child element, which itself needs to transition to a different position inside the parent.

Since the previously calculated bounds are relative to the window, our calculations for the child element are going to be off. To solve this, we need to ensure that the bounds are calculated relative to the parent element instead:

const parentElm = document.querySelector('.parent'); const childElm = document.querySelector('.parent > .child'); // First: parent and child const parentFirst = parentElm.getBoundingClientRect(); const childFirst = childElm.getBoundingClientRect(); doSomething(); // Last: parent and child const parentLast = parentElm.getBoundingClientRect(); const childLast = childElm.getBoundingClientRect(); // Invert: parent const parentDeltaX = parentFirst.left - parentLast.left; const parentDeltaY = parentFirst.top - parentLast.top; // Invert: child relative to parent const childDeltaX = (childFirst.left - parentFirst.left) - (childLast.left - parentLast.left); const childDeltaY = (childFirst.top - parentFirst.top) - (childLast.top - parentLast.top); // Play: using the WAAPI parentElm.animate([ { transform: `translate(${parentDeltaX}px, ${parentDeltaY}px)` }, { transform: 'none' } ], { duration: 300, easing: 'ease-in-out' }); childElm.animate([ { transform: `translate(${childDeltaX}px, ${childDeltaY}px)` }, { transform: 'none' } ], { duration: 300, easing: 'ease-in-out' });

A few things to note here, as well:

  1. The timing options for the parent and child (duration, easing, etc.) do not necessarily need to match with this technique. Feel free to be creative!
  2. Changing dimensions in parent and/or child (width, height) was purposefully omitted in this example, since it is an advanced and complex topic. Let's save that for another tutorial.
  3. You can combine the shared element and parent-child techniques for greater flexibility.
Using Flipping.js for Full Flexibility

The above techniques might seem straightforward, but they can get quite tedious to code once you have to keep track of multiple elements transitioning. Android eases this burden by:

  • baking shared element transitions into the core SDK
  • allowing developers to identify which elements are shared by using a common android:transitionName XML attribute

I've created a small library called Flipping.js with the same idea in mind. By adding a data-flip-key="..." attribute to HTML elements, it's possible to predictably and efficiently keep track of elements that might change position and dimensions from state to state.

For example, consider this initial view:

<section class="gallery"> <div class="photo-1" data-flip-key="photo-1"> <img src="/photo-1"/> </div> <div class="photo-2" data-flip-key="photo-2"> <img src="/photo-2"/> </div> <div class="photo-3" data-flip-key="photo-3"> <img src="/photo-3"/> </div> </section>

And this separate detail view:

<section class="details"> <div class="photo" data-flip-key="photo-1"> <img src="/photo-1"/> </div> <p class="description"> Lorem ipsum dolor sit amet... </section>

Notice in the above example that there are 2 elements with the same data-flip-key="photo-1". Flipping.js tracks the "active" element by choosing the first element that meet these criteria:

  • The element exists in the DOM (i.e., it hasn't been removed or detached)
  • The element is not hidden (hint: elm.getBoundingClientRect() will have { width: 0, height: 0 } for hidden elements)
  • Any custom logic specified in the selectActive option.
Getting Started with Flipping.js

There's a few different packages for Flipping, depending on your needs:

  • flipping.js: tiny and low-level; only emits events when element bounds change
  • flipping.web.js: uses WAAPI to animate transitions
  • flipping.gsap.js: uses GSAP to animate transitions
  • More adapters coming soon!

You can grab the minified code directly from unpkg:

Or you can npm install flipping --save and import it into your projects:

// import not necessary when including the unpkg scripts in a <script src="..."> tag import Flipping from 'flipping/adapters/web'; const flipping = new Flipping(); // First: let Flipping read all initial bounds flipping.read(); // execute the change that causes any elements to change bounds doSomething(); // Last, Invert, Play: the flip() method does it all flipping.flip();

Handling FLIP transitions as a result of a function call is such a common pattern, that the .wrap(fn) method transparently wraps (or "decorates") the given function by first calling .read(), then getting the return value of the function, then calling .flip(), then returning the return value. This leads to much less code:

const flipping = new Flipping(); const flippingDoSomething = flipping.wrap(doSomething); // anytime this is called, FLIP will animate changed elements flippingDoSomething();

Here is an example of using flipping.wrap() to easily achieve the shifting letters effect. Click anywhere to see the effect.

See the Pen Flipping Birthstones #Codevember by David Khourshid (@davidkpiano) on CodePen.

Adding Flipping.js to Existing Projects

In another article, we created a simple React gallery app using finite state machines. It works just as expected, but the UI could use some smooth transitions between states to prevent "jumping" and improve the user experience. Let's add Flipping.js into our React app to accomplish this. (Keep in mind, Flipping.js is framework-agnostic.)

Step 1: Initialize Flipping.js

The Flipping instance will live on the React component itself, so that it's isolated to only changes that occur within that component. Initialize Flipping.js by setting it up in the componentDidMount lifecycle hook:

componentDidMount() { const { node } = this; if (!node) return; this.flipping = new Flipping({ parentElement: node }); // initialize flipping with the initial bounds this.flipping.read(); }

By specifying parentElement: node, we're telling Flipping to only look for elements with a data-flip-key in the rendered App, instead of the entire document.
Then, modify the HTML elements with the data-flip-key attribute (similar to React's key prop) to identify unique and "shared" elements:

renderGallery(state) { return ( <section className="ui-items" data-state={state}> {this.state.items.map((item, i) => <img src={item.media.m} className="ui-item" style={{'--i': i}} key={item.link} onClick={() => this.transition({ type: 'SELECT_PHOTO', item })} data-flip-key={item.link} /> )} </section> ); } renderPhoto(state) { if (state !== 'photo') return; return ( <section className="ui-photo-detail" onClick={() => this.transition({ type: 'EXIT_PHOTO' })}> <img src={this.state.photo.media.m} className="ui-photo" data-flip-key={this.state.photo.link} /> </section> ) }

Notice how the img.ui-item and img.ui-photo are represented by data-flip-key={item.link} and data-flip-key={this.state.photo.link} respectively: when the user clicks on an img.ui-item, that item is set to this.state.photo, so the .link values will be equal.

And since they are equal, Flipping will smoothly transition from the img.ui-item thumbnail to the larger img.ui-photo.

Now we need to do two more things:

  1. call this.flipping.read() whenever the component will update
  2. call this.flipping.flip() whenever the component did update

Some of you might have already guessed where these method calls are going to occur: componentWillUpdate and componentDidUpdate, respectively:

componentWillUpdate() { this.flipping.read(); } componentDidUpdate() { this.flipping.flip(); }

And, just like that, if you're using a Flipping adapter (such as flipping.web.js or flipping.gsap.js), Flipping will keep track of all elements with a [data-flip-key] and smoothly transition them to their new bounds whenever they change. Here is the final result:

See the Pen FLIPping Gallery App by David Khourshid (@davidkpiano) on CodePen.

If you would rather implement custom animations yourself, you can use flipping.js as a simple event emitter. Read the documentation for more advanced use-cases.

Flipping.js and its adapters handle the shared element and parent-child transitions by default, as well as:

  • interrupted transitions (in adapters)
  • enter/move/leave states
  • plugin support for plugins such as mirror, which allows newly entered elements to "mirror" another element's movement
  • and more planned in the future!
Resources

Similar libraries include:

  • FlipJS by Paul Lewis himself, which handles simple single-element FLIP transitions
  • React-Flip-Move, a useful React library by Josh Comeau
  • BarbaJS, not necessarily a FLIP library, but one that allows you to add smooth transitions between different URLs, without page jumps.

Further resources:

Animating Layouts with the FLIP Technique is a post from CSS-Tricks

Netflix functions without client-side React, and it’s a good thing

Css Tricks - Mon, 11/27/2017 - 10:18am

Recently Netflix removed client-side React from their landing page which caused a bit of a stir. So Jake Archibald investigated why the team did that and how it’s actually a good thing for the React community in the long term:

When the PS4 was released in 2013, one of its advertised features was progressive downloading – allowing gamers to start playing a game while it's downloading. Although this was a breakthrough for consoles, the web has been doing this for 20 years. The HTML spec (warning: 8mb document), despite its size, starts rendering once ~20k is fetched.

Unfortunately, it's a feature we often engineer-away with single page apps, by channelling everything through a medium that isn't streaming-friendly, such as a large JS bundle.

I like the whole vibe of this post because it suggests that we should be careful when we pick our tools; we only should pick the right tool for the right job, instead of treating every issue as if it needs a giant hammer made of JavaScript. Also! Burke Holland wrote a funny piece last week on this topic with some of his thoughts.

Direct Link to ArticlePermalink

Netflix functions without client-side React, and it’s a good thing is a post from CSS-Tricks

Apps Have Command Prompts Now

Css Tricks - Mon, 11/27/2017 - 8:43am

Command lines were an early innovation in computers, and were the dominant way to interact with them in the 1960's - 80's. That gave way to GUIs for most users after that. I don't think we need to launch a scientific study to figure out why. Most users find it more comfortable and intuitive to accomplish things with interactive moments and visual feedback.

But command lines never went away. GUI's are generally a limited abstraction of what you could do through a command line anyway, so power users gravitate toward the closer-to-the-metal nature of the command line.

But we might be in the middle of a return to a happy medium.

Finder-ing

We know Apple is quite fond of cutting features. Particularly little-used features or power-user-only features. Curiously, this one has stuck around:

The "Go To Folder" dialog, via Command-Shift-G

William Pearson wrote:

If there’s only one keyboard shortcut you should remember in Mac OS X it’s this: Go To Folder. ... Is there a keyboard shortcut that is more useful than “Go To Folder”? I don’t think so.

I'm not sure about that, but it's clear some people take this shortcut pretty seriously! And yes, a keyboard shortcut, but one that essentially opens a command line prompt that can do one thing.

I guess that isn't terribly surprising, considering the success of apps like Alfred, which perhaps it's fair to say is a command line for finding, opening and doing things.

The Finder also has Spotlight (since OS X 10.4 Tiger anyway, 2005) which is largely a thing for search (especially these days, as it returns results the web as well).

Spotlight has a keyboard command (Command-Space) and then you just type to do stuff, so it's very much a command prompt. Just one that's pretty decked out in user-friendliness.

And while we're on this bend, we can't forget about Quicksilver. Interestingly, both Alfred and Quicksilver postdate Spotlight. I guess that speaks to Spotlight kind of sucking in the early days, and leaving people wanting more.

Code Editors

Most developers, I'm sure, are quite aware of the literal command line. Almost all the big development tools are command line based tools. Everything from Git to Gulp, image optimizers to package managers, Capistrano to webpack... they are all tools you use from the command line. If you have a GUI for any of them, it's probably a light abstraction over command line methods.

But, aside from the most hardcore of all Vim users who do all their code editing from a terminal window, we don't actually write code on the command line, but in an editor with a GUI.

Code Editors are a perfect breeding ground for ideas that combine the best of GUI's and command lines.

Let's look at Sublime Text. When creating a new folder, I might want to do that with the GUI. There I can see the existing folder structure and see exactly what I'm doing.

But say I want to jump to a file I know exists. Say it's buried a number of directories deep, and I'm glad that it is because it adheres to the structure of the current project. I might have to click - click - scroll - click - scroll - click to get there with a GUI, which isn't the greatest interaction.

Instead, I can fire up a command prompt in Sublime Text, in this case it's iconic Goto Anything command, type in something close to the file name, and find it.

Perhaps even more command-prompt-like is the literal Command Palette which is an extensible command-running menu triggered by a keyboard shortcut. Perhaps I want to run a specific Emmet command, correct syntax highlighting, or trigger an a find/replace extension to do its thing.

These things are in a similar boat as finding a file-in-a-haystack. There could be hundreds or thousands of commands. Your brain and typing fingers can find them quicker than your hand on a mouse in a UI can.

Sketch Runner

Sketch Runner is a popular plugin for Sketch that adds a command prompt to Sketch. Here's their product video:

If you think of elements and groups in a design document just like files in a code project, the "Jump anywhere" feature makes sense. It's just like "Goto Anything".

Perhaps your design document has hundreds of symbols. Your brain probably has a mental map of that that is quicker to navigate than moving your mouse through nested menus. Thus, a command prompt to type in the name (fuzzy search) and insert it.

Slack

Too many Slacks, amiright?

I don't think it would be terrible uncommon to have a dozen Slack teams, hundreds of channels, and thousands of people. Particularly if you're fond of joining "Public Slacks", like say the A11Y Slack.

Say I want to shoot a message to Sarah. I can open the Quick Switcher and just start typing her name and get there.

You have to be in the right Slack for names (or channels) to work, but you can get to the right slack via Quick Switcher and then do a new search.

Notion

Notion has a pretty awesome take on the command prompt. It's available everywhere you are in a document just by pressing the slash / key.

There are probably ~30 things you can do. The menu is nice, but being able to type what you mean quickly is even better.

In addition to searching the menu, you can just complete the word after the slash (a slash command) to do the thing.

Chrome DevTools

David Khourshid:

I've been using the command prompt in Chrome Dev Tools _so much more_ because opening the Animate tab takes like 17 clicks.

Yet another good use case!

So

There is a lot of apps doing interesting things here. I'm a fan of all of it!

Even more could probably benefit from it. Photoshop is notoriously complex, but a lot of us have familiarity with the things it can do. Seems like a perfect canidate for a fuzzy-search enabled command prompt!

Users might be able to take things into their own hands a bit here too. Alfred users could use the Menu Bar Search plugin which allows you to:

Search for and activate application menu items for the frontmost application. The workflow lists the menu items for the current application, filtering them by whatever is entered into Alfred.

Apps can easily have dozens of menu items, and this would make them all command prompt-able.

Standardization is also an interesting thing to consider. It seems some apps have followed each other. Command-Shift-P is the Sublime Text command runner, which was used by Chrome DevTools, and also by VS Code. I kinda like the Command-Space of Spotlight, but that doesn't mean web-based apps should copy it. In fact, it means they can't, because the OS would override it.

TL;DR

When UI is cumbersome or impractical, a command line makes good sense. Many apps benefit from offering both a UI and a command line, in various forms.

Apps Have Command Prompts Now is a post from CSS-Tricks

Editing the W3C HTML5 spec

Css Tricks - Fri, 11/24/2017 - 4:53am

Bruce Lawson has been tapped to co-edit the W3C HTML5 spec and, in his announcement post, clarified the difference between that and the WHATWG spec:

The WHATWG spec is a future-facing document; lots of ideas are incubated there. The W3C spec is a snapshot of what works interoperably – authors who don’t care much about what may or may not be round the corner, but who need solid advice on what works now may find this spec easier to use.

I was honestly unfamiliar with the WHATWG spec and now I find it super interesting to know there are two working groups pushing HTML forward in distinct but (somewhat) cooperative ways.

Kudos to you, Bruce! And, yes, Vive open standards!

Direct Link to ArticlePermalink

Editing the W3C HTML5 spec is a post from CSS-Tricks

On the Growing Popularity of Atomic CSS

Css Tricks - Fri, 11/24/2017 - 4:43am

Even if you consider yourself a CSS expert, chances are that at some point on a large project you've had to deal with a convoluted, labyrinthine stylesheet that never stops growing. Some stylesheets can feel like a messy entangled web of inheritance.

Spaghetti Monster

The cascade is incredibly powerful. Small changes can have large effects, making it harder to know what the immediate consequences will be. Refactoring, changing, and removing CSS is seen as risky and approached with trepidation as it's difficult to know all the places it's being used.

One thing that is often hard to articulate with new tooling is when, exactly do you start to reach for this? The answer is rarely (if ever) immediately and in all situations.

One of those situations, in my limited experience, is on large teams with large codebases. The feeling is that the CSS can get far too large and team members essentially become afraid of it, and the CSS becomes jokingly-but-accurately “append-only”.

Along comes a tool that delivers on a promise of shipping far less CSS and in a way that (after a learning curve) nobody is ever afraid of again… I can see the appeal.

- Chris Coyier

Atomic CSS keeps things simple

I no longer had to think about how to organise my CSS. I didn't have to think about what to name my 'components', where to draw the line between one component and another, what should live where, and crucially, how to refactor things when new requirements came in.

- Callum Jefferies, Takeaways from trying out Tachyons CSS after ages using BEM

Atomic CSS offers a straightforward, obvious, and simple methodology. Classes are immutable - they don't change. This makes the application of CSS predictable and reliable as classes will always do exactly the same thing. The scope of adding or removing a utility class in an HTML file is unambiguous, giving you the confidence that you aren't breaking anything else. This can reduce cognitive load and mental-overhead.

Naming components is notoriously difficult. Deciding on a class name that is both meaningful but also vague enough to be reusable is time-consuming and mentally taxing.

There are only two hard things in Computer Science: cache invalidation and naming things.

– Phil Karlton

Coming up with the appropriate abstractions is hard. Naming utility classes, by contrast, is completely straightforward.

/* naming utility classes */ .relative { position: relative; } .mt10 { margin-top: 10px; } .pb10 { padding-bottom: 10px; }

Atomic classes speak for themselves. Their intent and effect are immediately obvious. While littering HTML with countless classes may look cluttered, HTML is much easier to reason about than an impenetrably gargantuan and incomprehensible wall of tangled styles.

In a mixed-ability team, perhaps involving backend developers with limited interest and knowledge of CSS, there's less chance of people messing up the stylesheet.

Taken from ryanair.com - a whole load of CSS all doing one thing. Dealing with stylistic variation

Utility classes are perfect for dealing with small stylistic variations. While design systems and pattern libraries may be all the rage these days, what this approach recognizes is that there will continuously be new requirements and variations. All the talk about component reusability often isn't reflected in the design mocks that get passed your way. While visual and brand consistency is good, the wide variety of contexts on a large website make some variation inevitable and justified.

The Medium development team moved away from BEM modifiers, as documented on their blog.

What if we want a component to differ from another in only one single small way. If you've adopted a BEM naming convention, the modifier classes may well get out of hand - countless modifiers that often do only a single thing. Lets take margins as an example. The margins of a component are unlikely to remain universally consistent for a component. The desired spacing depends not only on the component but also its position on a page and its relation to its surrounding elements. Much of the time designs will contain similar but non-identical UI elements, which are arduous to deal with using traditional CSS.

A lot of people dislike it Aaron Gustafson, chief editor of A List Apart, former manager of the Web Standards Project, Microsoft employee. Mozilla Engineer Soledad Penades From the creator of CSS Zen Garden How is Atomic CSS different from inline styles?

This is the question always asked of atomic CSS by its critics. Inline styles have long been deemed a bad practice, rarely used since the early days of the web. Critics aren't completely wrong to equate atomic CSS to inline styles because they both suffer from the same major pain point. Here's an example: What if we want to change everything with a .black class to be navy instead? We could do this:

.black { color: navy; }

That's obviously a terrible idea.

Text editors are sophisticated things these days. It feels somewhat hazardous, but it would be simple enough to use find and replace to change all instances of the .black class with a new .navy class. The real problem is when you want to change only certain instances of .black to be .navy.

In traditional approaches to CSS, adjusting the styling of a component is as easy as updating a single value in a single class in a CSS file. With atomic CSS this becomes the tedious task of searching through every piece of HTML to update every instance of said component. However advanced code editors become, there's no getting around this. Even if you're separating your markup into reusable templates, this is still a major drawback. Perhaps this manual labour is worth it for the simplicity of this approach. Updating HTML files with different classes may be tedious but its not difficult. (Although there have been times when I have temporarily introduced stylistic inconsistency by missing certain instances of the relevant component when manually updating.) If a design changes, chances are you'll need to hand-edit classes from all over your HTML.

While atomic CSS shares inline styles big drawback, they aren't a retrograde step into the past. Utility classes are better than inline styles in all kinds of ways.

Atomic CSS vs. Inline Styles Atomic classes allow abstraction, inline styles don't

With atomic classes, it is possible to create abstractions that would be impossible with inline styles.

<p style="font-family: helvetica; color: rgb(20, 20, 20)"> Inline styles suck. </p> <p class="helvetica rgb202020"> Badly written CSS isn't very different. </p> <p class="sans-serif color-dark"> Utility classes allow for abstraction. </p>

The first two examples shown above would require a manual find-and-replace in order to update styling were the design to change. The styles in the third example can be adjusted in a single place within a stylesheet.

Tooling

Sass, Less, PostCSS, Autoprefixer… The CSS community has created a lot of useful tools that weren't available for inline styles.

Brevity

Rather than writing out verbose inline styles, atomic classes can be terse abbreviations of declarations. It's less typing: mt0 vs margin-top: 0, flex vs display: flex, etc.

Specificity

This is a contentious point. If a class or inline style only does one single thing, chances are you want it to do that thing. Some people have even advocated using !important on all utility classes to ensure they override everything else. Similarly, proponents of inline styles see its inability to be overridden (by anything other than !important) as a selling point - it means you can be sure the style will be applied. However, a class alone is specific enough to override any base style. The lower specificity of atomic classes compared to inline styles is a good thing. It allows more versatility. Were all used to changing classes on JavaScript to change styles. Inline styles make this harder.

Classes in stylesheets can do things inline styles can't

Inline styles do not support media queries, pseudo selectors, @supports, or CSS animations. Perhaps you have a single hover effect you want to apply to disparate elements rather than to only one component.

.circle { border-radius: 50%; } .hover-radius0:hover { border-radius: 0; }

Simple reusable media query rules can also be turned into a utility class. Its common to use a classname prefix for small, medium and large screen sizes. Here is an example of a flexbox class that will only apply on medium and large screen sizes:

@media (min-width: 600px) { .md-flex { display: flex; } }

This wouldn't be possible with an inline style.

Perhaps you want a reusable pseudo-content icon or label?

.with-icon::after { content: 'some icon goes here!'; } Limiting choice can be a good thing

Inline styles can be anything. This freedom could easily lead to design anarchy and inconsistency. By predefining classes for everything, atomic CSS can ensure a certain amount of stylistic consistency. Rather than ad libbing colours and values from an infinite amount of options, utility classes offer a curated set of predefined options. Developers choose from this limited set of single-purpose utility classes. This constraint can both eliminate the problem of an ever-growing stylesheet and maintain visual consistency.

Take the box-shadow as an example. An inline style will have an almost limitless amount of options for offset, spread, color, opacity and blur radius.

<div style="box-shadow: 2px 2px 2px rgba(10, 10, 250, .4)">stuff</div>

With an atomic approach, CSS authors can define the preferred style, which is then simply applied, without the possibility of stylistic inconsistency.

<div class="box-shadow">stuff</div> Atomic CSS is not all or nothing

There's no doubt that utility class frameworks like Tachyons have grown in popularity. However, CSS approaches are not mutually exclusive. There are plenty of cases where utility classes aren't the best option:

  • If you need to change a lot of styles for a particular component inside of a media query.
  • If you want to change multiple styles with JavaScript, it's easier to abstract that into a single class.

Utility classes can coexist with other approaches. Its probably a good idea to define base styles and sane defaults globally. If you keep duplicating the same long string of utility classes, chances are the styles should be abstracted into a single class. You can mix in component classes, but do so only when you know they will be reused.

Taking a component-first approach to CSS means you create components for things even if they will never get reused. This premature abstraction is the source of a lot of bloat and complexity in stylesheets.

- Adam Wathan

The smaller the unit, the more reusable it is.

- Thierry Koblentz

Looking at the newest release of Bootstrap, a whole host of utility classes is now offered, while still including its traditional components. Increasingly, popular frameworks are taking this mixed approach.

On the Growing Popularity of Atomic CSS is a post from CSS-Tricks

Syndicate content
©2003 - Present Akamai Design & Development.