Developer News

Keep Pixelated Images Pixelated as They Scale

Css Tricks - Sat, 04/07/2018 - 6:20am

This is a little reminder that there is a CSS property for helping control what happens to images as they scale up: image-rendering.

We're quite used to the idea that scaling an image larger than its natural size (upscaling) causes it to be blurry. As awful as that is, it's the browser doing the best it can to algorithmically smooth out an image over more pixels than it has data. But let's say you'd really rather not it do that. Say the image is already pixel-y (pixel art), or you prefer the look of a pixelated upscaling.

You can do it!

img { image-rendering: pixelated; image-rendering: -moz-crisp-edges; image-rendering: crisp-edges; }

It's a bit awkward in that the spec offers three values: auto, pixelated, and crisp-edges. Both pixelated and crisp-edges, for pixel art, appear to do the same thing to me, although the spec talks about them slightly differently (pixelated recommends the "nearest neighbor" or similar algorithm while crisp-edges isn't as specific).

Adding to the awkwardness, Chrome only supports pixelated and Firefox only supports crisp-edges, and for the deepest browser support, you gotta prefix it to -moz-crisp-edges. Fortunately, you can smash them all together and it seems fine.

Here's an example with and without, using an image from James T. I found on Tumblr:

See the Pen pixelated images by Chris Coyier (@chriscoyier) on CodePen.

The post Keep Pixelated Images Pixelated as They Scale appeared first on CSS-Tricks.


Css Tricks - Fri, 04/06/2018 - 8:17am

Brad Frost's "Just" article from a few years ago has struck a fresh nerve with folks. It's a simple word that can slip out easily, that might be invoked to keep text casual-feeling, but the result can be damaging. Brad:

The amount of available knowledge in our field (or any field really) is growing larger, more complex, and more segmented all the time. That everyone has downloaded the same fundamental knowledge on any topic is becoming less and less probable. Because of this, we have to be careful not to make too many assumptions in our documentation, blog posts, tutorials, wikis, and communications.

Imagine yourself explaining a particular task to an earlier version of yourself. Once upon a time, you didn’t know what you know now. Provide context. The beauty of hypertext is that we’re able to quickly add much-needed context helpful for n00bs but easy enough for those already in-the-know to scan over. And making documentation more human-readable benefits everyone.

Ethan Marcotte takes this one step further:

I’ve noticed a rhetorical trope in our industry. It’s not, like, widespread, but I see it in enough blog entries and conference talks that I think it’s a pretty common pattern: namely, the author’s sharing some advice with the reader and, if the reader’s boss or stakeholders won’t support a given course of action, suggests the reader “just do the thing anyway.”

I think this is a bad, harmful trope. And I also think we should avoid using it.

"Just" is more insidious than the more overtly painful "Obviously" or "Simply". In fact, there is a whole list of words that could go. The result of not using words like this? Cleaner sentences and more inclusive writing. Wanna make a difference? Be like Jeremy Keith and submit Pull Requests when you see the opportunity.

The best teachers I’ve had were ones that were cautious not to make me feel dumb.

Direct Link to ArticlePermalink

The post “Just” appeared first on CSS-Tricks.

Methods, Computed, and Watchers in Vue.js

Css Tricks - Fri, 04/06/2018 - 4:11am

One of the reasons I love working with Vue is because of how useful methods, computed, and watchers are, and the legibility of their distinction. Until understanding all three, it’s difficult to leverage the functionality of Vue to its full potential. Still, the majority of people I see confused about this framework tend to also be confused about the differences here, so let’s dig in.

In case you need a quick answer and don’t have time to read through the entire article, here’s a small TL;DR:

  • Methods: These are exactly what they sound like they might be (yay, naming!). They’re functions that hang off of an object—typically the Vue instance itself or a Vue component.
  • Computed: These properties may at first look like they'd be used like a method, but are not. In Vue, we use data to track changes to a particular property that we’d like to be reactive. Computed properties allow us to define a property that is used the same way as data, but can also have some custom logic that is cached based on its dependencies. You can consider computed properties another view into your data.
  • Watchers: These are allowing you a peek into the reactivity system. We’re offered some hooks with which to observe any properties that are stored by Vue. If we want to add a bit of functionality each time something changes, or respond to a particular change, we could watch a property and apply some logic. This means that the name of the watcher has to match what we’re trying to observe.

If any of this sounds confusing, don’t worry! We’ll dive in further below and hopefully address any confusion. If you’re familiar with vanilla JavaScript already, methods may be pretty obvious to you, aside from one or two caveats. It might then behoove you (I love that phrase) to skip to the Computed and Watchers sections.


Methods are likely something you’re going to use a lot while working with Vue. They’re aptly named as, in essence, we’re hanging a function off of an object. They’re incredibly useful for connecting functionality to directives for events, or even just creating a small bit of logic to be reused like any other function. You can call a method within another method, for example. You can also call a method inside a lifecycle hook. They’re very versatile.

Here's a simple demo to demonstrate:

See the Pen Slim example of methods by Sarah Drasner (@sdras) on CodePen.

<code class="language-css"><div id="app"> <button @click="tryme">Try Me</button> <p>{{ message }}</p> </div> new Vue({ el: '#app', data() { return { message: null } }, methods: { tryme() { this.message = Date() } } })

We could have also executed the logic in the directive itself like <button @click="message = Date()">Try Me</button>, which works very well for this small example. However, as the complexity of our application grows, it's more common to do as we see above to break it out to keep it legible. There's also a limit to the logic that Vue will allow you to express in a directive—for instance, expressions are allowed but statements are not.

You may notice that we’re be able to access this method within that component or Vue instance, and we can call any piece of our data here, in this case, this.message. You don’t have to call a method like you'd call a function within a directive. For example, @click=”methodName()” is unnecessary. You can reference it with @click=”methodName”, unless you need to pass a parameter, such as @click=”methodName(param)”.

Using directives to call methods is also nice because we have some existing modifiers. One such example that's very useful is .prevent, which will keep a submit event from reloading the page, used like this:

<form v-on:submit.prevent="onSubmit"></form>

There are many more, here are just a few.


Computed properties are very valuable for manipulating data that already exists. Anytime you're building something where you need to sort through a large group of data and you don't want to rerun those calculations on every keystroke, think about using a computed value.

Some good candidates include, but are not limited to:

  • Updating a large amount of information while a user is typing, such as filtering a list
  • Gathering information from your Vuex store
  • Form validation
  • Data visualizations that change depending on what the user needs to see

Computed properties are a vital part of Vue to understand. They are calculations that will be cached based on their dependencies and will only update when needed. They're extremely performant when used well and extraordinarily useful. There are many large libraries that handle this kind of logic that you can now eliminate with only a few lines of code.

Computed properties aren't used like methods, though at first, they might look similar- you're stating some logic in a function and returning- but the name of that function becomes a property that you'd then use in your application like data.

If we needed to filter this big list of names of heroes based on what the user was typing, here’s how we would do it. We're keeping this really simple so you can get the base concepts down. Originally our list would output in our template using names, which we store in data:

new Vue({ el: '#app', data() { return { names: [ 'Evan You', 'John Lindquist', 'Jen Looper', 'Miriam Suzanne', ... ] } } }) <div id="app"> <h1>Heroes</h1> <ul> <li v-for="name in names"> {{ name }} </li> </ul> </div>

See the Pen Filter a list with Computed- start by Sarah Drasner (@sdras) on CodePen.

Now let's create a filter for those names. We'll start by creating an input with v-model that will originally be an empty string, but we'll eventually use to match and filter through our list. We'll call this property findName and you can see it referenced both on the input and in the data.

<label for="filtername">Find your hero:</label> <input v-model="findName" id="filtername" type="text" /> data() { return { findName: '', names: [ 'Evan You', 'John Lindquist', ... ] } }

Now, we can create the computed property that will filter all of the names based on what the user has typed into the input, so anything in our findName property. You'll note that I'm using regex here to make sure that mismatched capitalization doesn't matter, as users will typically not capitalize as they type.

computed: { filteredNames() { let filter = new RegExp(this.findName, 'i') return this.names.filter(el => el.match(filter)) } }

And now we'll update what we're using in the template to output from this:

<ul> <li v-for="name in names"> {{ name }} </li> </ul> this:

<ul> <li v-for="name in filteredNames"> {{ name }} </li> </ul>

And it filters for us on every keystroke! We only had to add a couple of lines of code to make this work, and didn't have to load any additional libraries.

See the Pen Filter a list with Computed- end by Sarah Drasner (@sdras) on CodePen.

I can't tell you how much time I save by using them. If you're using Vue and haven't explored them yet, please do, you'll thank yourself.


Vue has nice abstractions, and anyone who has been a programmer for a while will usually tell you that abstractions can be a pain because you'll eventually get to a use case they can't solve. However, this situation is accounted for, because Vue grants us some deeper access to into the reactivity system, which we can leverage as hooks to observe anything that’s changing. This can be incredibly useful because, as application developers, most of what we’re responsible for are things that change.

Watchers also allow us to write much more declarative code. You’re no longer tracking everything yourself. Vue is already doing it under the hood, so you can also have access to changes made to any properties it's tracking, in data, computed, or props, for example.

Watchers are incredibly good for executing logic that applies to something else when a change on a property occurs (I first heard this way of putting it from Chris Fritz, but he says he might have also heard it from someone else ☺️). This isn't a hard rule- you can absolutely use watchers for logic that refers to the property itself, but it's a nice way of looking at how watchers are immediately different from computed properties, where the change will be in reference to the property we intend to use.

Let’s run through the most simple example possible so you get a taste of what’s happening here.

Your browser does not support the video tag.

new Vue({ el: '#app', data() { return { counter: 0 } }, watch: { counter() { console.log('The counter has changed!') } } })

As you can see in the code above, we're storing counter in data, and by using the name of the property as the function name, we're able to watch it. When we reference that counter in watch, we can observe any change to that property.

Transitioning State With Watchers

If the state is similar enough, you can even simply transition the state with watchers. Here's an example I built from scratch of a chart with Vue. As the data changes, the watchers will update it and simply transition between them.

SVG is also good for a task like this because it's built with math.

See the Pen Chart made with Vue, Transitioning State by Sarah Drasner (@sdras) on CodePen.

watch: { selected: function(newValue, oldValue) { var tweenedData = {} var update = function () { let obj = Object.values(tweenedData); obj.pop(); this.targetVal = obj; } var tweenSourceData = { onUpdate: update, onUpdateScope: this } for (let i = 0; i < oldValue.length; i++) { let key = i.toString() tweenedData[key] = oldValue[i] tweenSourceData[key] = newValue[i] }, 1, tweenSourceData) } }

What happened here?

  • First we created a dummy object that will get updated by our animation library.
  • Then we have an update function that is invoked on each tween step. We use this to push the data.
  • Then we create an object to hold the source data to be tweened and the function pointer for update events.
  • We create a for loop, and turn the current index into a string
  • Then we can tween over the our target dummy object, but we'll only do this for the specific key

We could also use animation in watchers to create something like this time difference dial. I travel a bit and all my coworkers are in different areas, so I wanted a way to track what local time we were all in, as well as some signification of the change from daytime/nighttime as well.

See the Pen Vue Time Comparison by Sarah Drasner (@sdras) on CodePen.

Here we're watching the checked property, and we'll fire different methods that contain timeline animations that change the hue and saturation and some other elements based on the relative association to the current time. As mentioned earlier- the change occurs on the dropdown, but what we're executing is logic that's applied elsewhere.

watch: { checked() { let period = this.timeVal.slice(-2), hr = this.timeVal.slice(0, this.timeVal.indexOf(':')); const dayhr = 12, rpos = 115, rneg = -118; if ((period === 'AM' && hr != 12) || (period === 'PM' && hr == 12)) { this.spin(`${rneg - (rneg / dayhr) * hr}`) this.animTime(1 - hr / dayhr, period) } else { this.spin(`${(rpos / dayhr) * hr}`) this.animTime(hr / dayhr, period) } } },

There are also a number of other interesting things about watchers, for instance: we're given access to both the new and old versions of the property as parameters, we can specify deep if we'd like to watch a nested object. For more detailed information, there's a lot of good information in the guide.

You can see how watchers can be incredibly useful for anything that’s updating—be it form inputs, asynchronous updates, or animations. If you’re curious how reactivity in Vue works, this part of the guide is really helpful. If you’d like to know more about reactivity in general, I really enjoyed Andre Staltz' post and the Reactivity section of Mike Bostock’s A Better Way to Code.

Wrapping Up

I hope this was a helpful breakdown on how to use each, and speeds up your application development process by using Vue efficiently. There's a stat out there that we spend 70% of our time as programmers reading code and 30% writing it. Personally, I love that, as a maintainer, I can look at a codebase I've never seen before and know immediately what the author has intended by the distinction made from methods, computed, and watchers.

The post Methods, Computed, and Watchers in Vue.js appeared first on CSS-Tricks.

Designing Button States

Css Tricks - Thu, 04/05/2018 - 12:44pm

Tyler Sticka on the complexity of designing buttons and making sure that we’ve taken into consideration focus, hover and active states during the design process:

In truth, mouse effects are probably the least important state to design for. By accounting for more functional states early, you can lower the need for costly redesigns as your pattern library matures. Here are the fundamental states you should address early on, in approximate order of importance.

I’ve been spending a lot more time lately thinking about focus styles as being a crucial challenge when building for the web and so I particularly take Tyler’s advice to heart. He argues that we should repeat this maxim throughout the button design process:

"I do solemnly swear never to disable browser focus styles without including a thoughtfully designed replacement."

The first step: focusing on focus styles.

On a related note, we recently did a series on CSS Basics that included a post dedicated to link styling for various link states. Also, there’s a pretty good post that’s related to this topic called Buttons in Design Systems that tackles a bunch of UX considerations for buttons, like how to write a good label.

Direct Link to ArticlePermalink

The post Designing Button States appeared first on CSS-Tricks.

Static File Hosting Doesn’t Have To Be So… Static

Css Tricks - Thu, 04/05/2018 - 12:42pm

A huge high-five and welcome to Netlify for the sponsorship this week.

If you haven't heard of Netlify, the big thing you should know is that it's web hosting, but more than that. It's web hosting with the developer workflow squarely at heart. You can spin up a site on Netlify in literally seconds. One way is through their robust CLI. Another way, that I find very comfortable (and just did the other day), is to log into the Netlify web interface, create a new site, and connect a Git repo to it. Plus I can give it a command that will run my site's build process when I push to master. Now anything I push up goes live on my website, which is HTTPS and on a CDN. Uh, wow. Of course, I can also point a custom domain name at Netlify and now we're cooking with gas.

The JAMstack is at the heart of Netlify. It's static file hosting, because static file hosting is super fast and secure. It means you can build your site with all kinds of fun, powerful, modern site generators like Hugo, Gatsby, Metalsmith, or 11ty. The site I spun up myself was my own custom thing with a Gulp build process that ran Sass and Nunjucks.

Try spinning up a Gatsby site right now!

Static sites aren't just HTML-only zero-interactivity stone statues.

In fact, I think static sites are one of the ingredients to the larger world of serverless technology, in which functionality is handled by services that are perfect for the job.

Netlify knows this, of course, so they've released has some brand spanking new features that allow you to add interactivity and functionality to your site:

Form Handling

Just add a netlify attribute to the <form>, configure where you want the redirection and email notifications to go, and you're set. You don't have to write any server-side code or JavaScript. Even blast that data over to Zapier to integrate with a million other web services. They don't inject JavaScript to make this work - it's handled at the CDN level.

You can also receive and manage submissions in your Netlify dashboard, so this can be yet another thing that brings together site management under one roof.

Built-in AWS Lambda Functions

JavaScript functions are designed to handle requests. Does your site need to trigger a Slack message? Send an SMS through Twilio? Process data? Now you can host your cloud functions right in the same repo as your site and Netlify will handle pushing them over to AWS Lambda for you. You don't have to configure anything or even bother setting up your own AWS account.

Plus, your functions benefit from the power of Deploy Previews and rollbacks. As in, your functions live in your version control along with the rest of your site, so they are easy to manage and come with all the comfort and advantages of working with Netlify. Wanna dig in? Here's a tutorial by Alex MacArthur that goes deep.


Do you need to log in to your website for admin purposes? Or have users log in? With Identity, Netlify gives you a really easy way to make that happen. Imagine a feature like a gym website offering a food log for members. The member could log in with Google/Twitter/etc and save/view/edit their food data (via cloud functions of course!).

Social login is a handy feature, but it's not required. You can manage and authenticate users that aren't Netlify users or users of any other service. You'll be able to handle log in, sign up, password recovery and all that. Very useful for gated content, site administration, and integrating with any service that understands JSON Web Tokens.

All on Netlify

All those things without having to go out, evaluate and purchase tools or customize open source tools, integrate them into your project, and then manage multiple disparate accounts/services.

How much does it all cost? There's a good chance it doesn't cost you anything. Small projects probably fit within Netlify's free tier. If you grow up and build something big, they you might get into a paid tier, but still good news, you only pay for what you use.

Go check out Netlify right now.

The post Static File Hosting Doesn’t Have To Be So… Static appeared first on CSS-Tricks.

Creating Themeable Design Systems

Css Tricks - Thu, 04/05/2018 - 12:41pm

Brad frost picks up the ongoing conversation about design systems. Where many posts seem to center on how to create one and how to enforce it, the big takeaway here is that design systems are not synonymous with constraints. They're only as strict as we make them and new CSS features like custom properties actually open up new creative possibilities—something Andres Galante and Cliff Pyles recently pitched right here on CSS-Tricks.


The aesthetic layer is often the most malleable layer of the frontend stack, which means that we can create systems that allow for a lot of aesthetic flexibility while still retaining a solid underlying structural foundation.

This not only sounds right, but puts a strong punctuation on why we love CSS: it's a set of styles that can be applied an infinite number of ways to the same HTML markup. A new layer of paint can be slapped on at any time, but the beams, walls and ceiling of the building can remain constant. Dave Rupert's personal site is a prime example of this and he details his approach to theming.

Ah, CSS Zen Garden...

Direct Link to ArticlePermalink

The post Creating Themeable Design Systems appeared first on CSS-Tricks.

A Quick Way to Remember the Difference Between `justify-content` and `align-items`

Css Tricks - Thu, 04/05/2018 - 3:58am

I was talking with a pal the other day and moaning about flexbox for the millionth time because I had momentarily forgotten the difference between the justify-content and align-items properties.

"How do I center an element horizontally with flex again?” I wondered. Well, that was when she gave me what I think is the best shorthand way of remembering how the two work together.

She said that justify-content positions elements across the horizontal axis because the word itself is longer than align-items. At first I thought this was a really silly idea but now this is how I remember it. I even used it five minutes ago when I needed to make these two quick demos:

See the Pen justify-content: center by Robin Rendle (@robinrendle) on CodePen.

See the Pen align-items: center by Robin Rendle (@robinrendle) on CodePen.

So, to summarize:

  • justify-content: longer word: horizontal alignment
  • align-items: shorter word: vertical alignment

This had me thinking if there are there any other mnemonic devices or ways that to remember complex things in CSS? Are there any other tricks you’d recommend? It sort of reminds me of the way kids are taught to remember the names of planets with things like, “My Very Educated Mother Just Showed Us Nine” where the first letter in each word represents the first letter of each planet: Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus and Neptune.

The post A Quick Way to Remember the Difference Between `justify-content` and `align-items` appeared first on CSS-Tricks.

?The future of data collection is here

Css Tricks - Thu, 04/05/2018 - 3:57am

(This is a sponsored post.)

Who said collecting data was easy? JotForm did. In today’s world, getting relevant data has never been more important for making informed business decisions. The thing is, companies still struggle with it because the forms they use for gathering information don’t typically resonate with their customers. Until now that is. With JotForm’s newest format, JotForm Cards, your online forms have all the same power of traditional forms, but with added benefits: they’re friendlier, sleeker, and not boring. Better yet, companies that use JotForm Cards see 36% higher conversions, which means more leads, more payments, more registrations, and more feedback. So, what are you waiting for? Get the data your company needs, and try out JotForm Cards for yourself today.

Direct Link to ArticlePermalink

The post ?The future of data collection is here appeared first on CSS-Tricks.

How to Write a Git Commit Message

Css Tricks - Wed, 04/04/2018 - 11:04am

An oldie but goodie, Chris Beams writes about the secret art of writing helpful Git commit messages. Here’s why he thinks it’s so important:

If you haven’t given much thought to what makes a great Git commit message, it may be the case that you haven’t spent much time using git log and related tools. There is a vicious cycle here: because the commit history is unstructured and inconsistent, one doesn’t spend much time using or taking care of it. And because it doesn’t get used or taken care of, it remains unstructured and inconsistent.

But a well-cared for log is a beautiful and useful thing. git blame, revert, rebase, log, shortlog and other subcommands come to life. Reviewing others’ commits and pull requests becomes something worth doing, and suddenly can be done independently. Understanding why something happened months or years ago becomes not only possible but efficient.

A project’s long-term success rests (among other things) on its maintainability, and a maintainer has few tools more powerful than his project’s log. It’s worth taking the time to learn how to care for one properly. What may be a hassle at first soon becomes habit, and eventually a source of pride and productivity for all involved.

This post pairs well with a more recent post on the topic. Where Chris provides a format for consistency, Stephen Amaza takes that same idea and expands it with suggestions for how to provide a commit message with better context.

I’ve always been pretty lazy with commit messages and there’s certainly been a few times when that’s come back to bite me in some terrible and unexpected way. One trick I’ll certainly be using from now on: using the first line of the message as a title and then having a much longer paragraph that follows it if the code doesn’t make sense at a quick glance.

Direct Link to ArticlePermalink

The post How to Write a Git Commit Message appeared first on CSS-Tricks.

Why would you do that in CSS?

Css Tricks - Wed, 04/04/2018 - 3:37am

And by that, it's usually some kind of CSS experiment, often an elaborate drawing or interaction.

For example, have you seen Lynn Fisher's extraordinary A Single Div project? Not only are all these graphics drawn in just HTML and CSS, they are all created with (you guessed it) a single <div></div>.

Why would she do that? Here's one pertinent possibility: it's none of our business. We're free to wonder, or even ask if it's done respectfully enough. But does it really matter? Let's stop short of assuming she doesn't know what's she's doing, assuming it's a twisted form of pain, or that she's unaware of other technologies. Check out the example where she drew the official SVG logo with CSS and a single div. Woke.

I even kinda get it. I wrote a whole book about SVG because I think it's underused. Are there "CSS drawings" that I think would be better as SVG for a production site meant to last? Sure.

How about this one?

See the Pen Pure CSS Biker by Julia Muzafarova (@miocene) on CodePen.

Jeepers creepers that's something else. I would have guessed GreenSock was behind this at a quick glance. Speaking of, GreenSock has advocated right here on CSS-Tricks some techniques for smart animations. Part of that is breaking animations into parts and stitching them together into larger timelines for maintenance ease and "without getting bogged down by the process."

So, did Julia Muzafarova do it wrong? Of course not. If there is a wrong way to animate a cartoon hipster on a bike in this world, I don't wanna live here anymore. It's 2,100 lines of meticulous positioning, coloring, and animating. Heck, it'll work in some email clients if you really need to latch onto something "practical."

Sasha Tran, a UI Developer at Level Studios, shared her story of creating drawings in CSS last year. She drew something new every day for 20 days during Codevember.

Even if I am not talented in hand illustrations, there is a way to express myself through other mediums. I found that medium to be in HTML and CSS. To level up and get to a point where I could create cute artwork, I focused on two things: the basics, and consistency. Working with basic CSS shapes like rectangles and basic properties like border-radius overtime gave me the muscle memory to progress into more intricate illustrations.

Significantly leveled up in a month and developed better CSS muscle memory. Huh. Speaking of shapes, there are plenty of ways to get tricky with those in CSS!

You could argue that pushing boundaries toward the impractical is what hones our skills for all that other work we have to do.

See the Pen CSS3 Thermostat by Daniel Stancu (@birkof) on CodePen.

You could argue that forcing yourself into restrictions is fuel for creativity.

See the Pen Pixel Hellboy by Servin (@servinnissen) on CodePen.

You could argue that stretching your brain creatively in these forced conditions helps build your confidence and widens your toolbox.

See the Pen Simple CSS Anchor by Joni Trythall (@jonitrythall) on CodePen.

You could argue that it's just kinda fun.

See the Pen CSS Cheese (or sponge) by Hugo Giraudel (@HugoGiraudel) on CodePen.

The post Why would you do that in CSS? appeared first on CSS-Tricks.

Animated SVG Radial Progress Bars

Css Tricks - Tue, 04/03/2018 - 11:20am

Dave Rupert shows us all how to animate radial progress bars in SVG with a tiny script alongside the stroke-dasharray and stroke-dashoffset properties:

For a client project we tasked ourselves with building out one of those cool radial progress bars. In the past, we’ve used entire Canvas-based charting libraries (156k/44k gzip), but that seemed like overkill. I looked at Airbnb’s Lottie project where you export After Effects animations as JSON. This is cool for complex animations, but the dependencies seemed heavy (248k/56k gzip) for one micro-animation.

Per the usual, I tried my hand at a minimal custom SVG with CSS animation and a small bit of JavaScript (~223b gzip). I’m pleased with the results.

Here's another example Jeremias Menichelli posted here on CSS-Tricks with the added twist of making them components in React and Vue.

Direct Link to ArticlePermalink

The post Animated SVG Radial Progress Bars appeared first on CSS-Tricks.

Scooped Corners in 2018

Css Tricks - Tue, 04/03/2018 - 4:00am

When I saw Chris' article on notched boxes, I remembered that I got a challenge a while ago to CSS a design like the one below in a cross-browser manner:

What the challenge looked like.

It looks pretty similar to the concept of notched boxes, except the corners are now scooped and we only have to worry about one corner per box. So let's see how we can do it, how we can expand the technique to multiple corners, what issues we run into and how we can get around them with or without making browser support compromises.

The initial idea: box-shadow!

We start with a box element:

<div class='box'></div>

We can give this some dimensions or let its dimensions be decided by the content—it doesn't really matter. For simplicity, we're just setting a max-width and a min-height on it. We're also giving it an outline so we can see its boundaries.

.box { outline: solid 2px; max-width: 15em; min-height: 10em; }

Next, we absolutely position a square ::before pseudo-element whose edge length is equal to the diameter (or twice the radius $r) of the scoop in the corner. We also give this pseudo-element a reddish box-shadow and a dummy background (that we'll remove later) just so that we can see it better:

$r: 2em; .box { position: relative; /* same styles as before */ &:before { position: absolute; padding: $r; box-shadow: 0 0 7px #b53; background: #95a; content: '' } }

And this is what we have so far:

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

Well, it doesn't look too exciting... yet! So let's move on and make this square a disc by setting border-radius: 50% on it and give it a negative margin equal to its radius $r, so that its central point coincides with the (0,0) point (top left corner) of its parent box. We also set overflow: hidden on the parent box, so that whatever of this pseudo-element is outside the .box gets cut out.

$r: 2em; .box { overflow: hidden; /* same styles as before */ &:before { /* same styles as before */ margin: -$r; border-radius: 50% } }

Now we're starting to see the shape we've been aiming for:

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

But it's still not quite what we want. In order to get there, we use the fourth length value for the box-shadow property: the spread radius. If you need a refresher on how box-shadow works with these four values, you can check out the interactive demo below:

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

You may have already guessed what we do next. We remove the dummy background, we zero the first three box-shadow values (the x and y offsets and the blur radius) and use a pretty big number for the last one (the spread radius):

box-shadow: 0 0 0 300px;

The interactive demo below shows how increasing the spread radius makes it cover up more and more of its parent .box:

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

So, the trick here is having a spread radius sufficiently large so that it covers the rest of the parent element. The cool thing about this is that we can make the box-shadow semi-transparent or have rounded corners on the parent .box:

.box { /* same styles as before */ border-radius: 1em; &:before { /* same styles as before */ box-shadow: 0 0 0 300px rgba(#95a, .75); } }

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

Of course, just like Chris pointed out in the article on notched boxes, we can make the scoop radius a CSS variable and then easily modify that from the JavaScript. Then everything updates nicely, even with text content in our box:

:root { --r: 50px } .box { /* same styles as before */ padding: var(--r); &:before { /* same styles as before */ margin: calc(-1*var(--r)); padding: inherit; }

Note that when we also have text content, we need to set a negative z-index on the ::before pseudo-element and explicitly position it in the corner as we now also have a padding on the .box to compensate for the scoop.

.box { /* same styles as before */ &:before { /* same styles as before */ z-index: -1; top: 0; left: 0 }

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

Applying this technique

Now, let's move further and see how we can apply this concept in order to reproduce the design I showed at the beginning. In this particular case, the central points of the pseudo-element discs don't coincide with box corners, but are outside, in the middle of the space in between boxes.

The structure used is pretty straightforward, just a <header> element followed by four <article> elements I've generated in a Pug loop:

while n-- article h3 #{data[n].name} section p #{data[n].quote} a(href='#') go

We use a wrapping flexbox layout on the <body> with the <header> really wide and with one or two <article> elements on each row, depending on how wide the viewport is.

Landscape (left) vs. portrait (right) mode.

If we have a single <article> on each row, we don't have scooped corners, so their radius is 0px. Otherwise, we give this radius --r a non-zero value.

$min-w: 15rem; /* min width of an article element */ $m: 1rem; /* margin of such an element */ html { --r: 0px; } article { margin: $m; min-width: $min-w; width: 21em; } @media (min-width: 2*($min-w + 2*$m) /* enough for 2 per row */) { html { --r: 4rem; } article { width: 40%; } }

Let's now consider just the situation when we have two <article> elements per row (and of course a scooped corner for each because that's what's of interest to us).

In the case of the first one, we start with the leftmost limit of the disc along the right edge of its parent. That's left: 100% so far. To move the x coordinate of the disc's central point on the right edge of its parent, we subtract the disc's radius, which brings us to left: calc(100% - var(--r)). But we don't want it on the right edge, we want it offset to the right by the <article> margin $m, which brings us to the final value:

left: calc(100% - var(--r) + #{$m});

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

Along the y axis, we start with the topmost limit of the disc along the bottom edge of its parent—that's top: 100%. To put the disc's central point on the bottom edge of the parent box, we move it up by one radius, which gives us top: calc(100% - var(--r)). Finally, we want this central point to be $m below the parent's bottom edge, which gives us the final vertical offset of:

top: calc(100% - var(--r) + #{$m});

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

For the second <article> (second on the same row), we have the same value in the case of the vertical offset.

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

Horizontally however, we start with the disc's left limit being along its parent's left edge—that's left: 0%. To put the disc's central point on its parent's left edge, we move it left by a radius --r, thus getting left: calc(0% - var(--r)). However, the final position is $m to the left of the parent's left edge:

left: calc(0% - var(--r) - #{$m});

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

For the third <article> (first on the last row), we have the same value for the offset along the x axis as in the case of the first one.

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

Vertically, we start with the disc's top limit along the top edge of its parent—that's top: 0%. To put the disc's central point on the parent's top edge, we move it up by a radius --r, thus getting top: calc(0% - var(--r)). But we want to have it $m above the parent's top edge, so the final top offset is:

top: calc(0% - var(--r) - #{$m});

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

For the final one (second on the last row), we have the same horizontal offset as in the case of the one above it and the same vertical offset as for the one to its left on the same row.

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

So, our offsets can be written:

article:nth-of-type(1) { /* 1st */ left: calc(100%/* 2*50% = (1 + 1)*50% = (1 + i)*50% */ - var(--r) + /* i=+1 */#{$m}); top: calc(100%/* 2*50% = (1 + 1)*50% = (1 + j)*50% */ - var(--r) + /* j=+1 */#{$m}); } article:nth-of-type(2) { /* 2nd */ left: calc( 0%/* 0*50% = (1 - 1)*50% = (1 + i)*50% */ - var(--r) - /* i=-1 */#{$m}); top: calc(100%/* 2*50% = (1 + 1)*50% = (1 + j)*50% */ - var(--r) + /* j=+1 */#{$m}); } article:nth-of-type(3) { /* 3rd */ left: calc(100%/* 2*50% = (1 + 1)*50% = (1 + i)*50% */ - var(--r) + /* i=+1 */#{$m}); top: calc( 0%/* 0*50% = (1 - 1)*50% = (1 + j)*50% */ - var(--r) - /* j=-1 */#{$m}); } article:nth-of-type(4) { /* 4th */ left: calc( 0%/* 0*50% = (1 - 1)*50% = (1 + i)*50% */ - var(--r) - /* i=-1 */#{$m}); top: calc( 0%/* 0*50% = (1 - 1)*50% = (1 + j)*50% */ - var(--r) - /* j=-1 */#{$m}); }

This means the positions of the central points of the discs depend on the gap in between our <article> elements (this gap is twice the margin: $m we set on them), on the disc radius r and on a couple of horizontal and vertical multipliers (--i and --j respectively). Both these multipliers are initially -1.

For the first two <article> elements (on the first row of the 2x2 grid), we change the vertical multiplier --j to 1 because we want the y coordinate of the discs' central points to be below the bottom edge, while for the odd ones (on the first column), we change the horizontal multiplier --i to 1 because we want the x coordinate to be to the right of the right edge.

html { --i: -1; --j: -1 } /* multipliers initially set to -1 */ h3, section { &:before { /* set generic offsets */ top: calc((1 + var(--j))*50% - var(--r) + var(--j)*#{$m}); left: calc((1 + var(--i))*50% - var(--r) + var(--i)*#{$m}); } } @media (min-width: 2*($min-w + 2*$m)) { article { /* change vertical multiplier for first two (on 1st row of 2x2 grid) */ &:nth-of-type(-n + 2) { --j: 1 } /* change horizontal multiplier for odd ones (on 1st column) */ &:nth-of-type(odd) { --i: 1 } }

Note that we only have visible disc cutouts on the <section> element for the first two <article> elements and only on the <h3> for the last two. So for the first two <article> elements, the radius --r on the heading's ::before pseudo-element is 0, while for the last two, this radius is 0 for the section's ::before pseudo:

@media (min-width: 2*($min-w + 2*$m)) { article { &:nth-of-type(-n + 2) h3, &:nth-of-type(n + 3) section { &:before { --r: 0 ; } } } }

In a similar manner, we add differentiated paddings to the children of the <article> elements:

$p: .5rem; h3, section { padding: $p; } @media (min-width: 2*($min-w + 2*$m)) { article { &:nth-of-type(-n + 2) section, &:nth-of-type(n + 3) h3 { padding-right: calc(.5*(1 + var(--i))*(var(--r) - #{$m}) + #{$p}); padding-left: calc(.5*(1 - var(--i))*(var(--r) - #{$m}) + #{$p}); } } }

This helps us get the result we're looking for:

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

The above demo works in current versions of all major browsers and, if we can do with some repetition instead of using CSS variables, we can extend support all the way back to IE9.

Potential issues with the above method

While this was a quick and easy cross-browser way to get the desired result in this particular case, we may not always be so lucky with this approach.

First off, we need a pseudo-element for each scooped corner, so if we want this effect for all corners, we need to bring in an extra element. Sad panda.

Secondly, we may not always want a solid background. We may want a semi-transparent one (which becomes a pain to get if we want to have more than one scooped corner), a gradient one (while we can emulate some radial gradients with box-shadow, it's a less than ideal solution) or even an image background (hardly doable with the only solution being to use mix-blend-mode which cuts out Edge support without an elegant fallback).

And how about really large boxes for which the spread we've set is not enough? Ugh.

So, let's explore other, more reliable approaches with various degrees of browser support.

Flexibility and good browser support? SVG it!

This is probably no surprise, but the full SVG solution fares best if we want something flexible and reliably cross-browser today. It's a solution that involves using an SVG element before the content of our box. This SVG contains a <circle> on which we've set a radius r attribute.

<div class='box'> <svg> <circle r='50'/> </svg> TEXT CONTENT OF BOX GOES HERE </div>

We absolutely position this SVG within the box and size it such that it fully covers its parent:

.box { position: relative; } svg { position: absolute; width: 100%; height: 100%; }

Nothing too interesting so far, so let's give the <circle> an id and clone it in the other corners:

<circle id='c' r='50'/> <use xlink:href='#c' x='100%'/> <use xlink:href='#c' y='100%'/> <use xlink:href='#c' x='100%' y='100%'/>

Note that if we want to exclude one corner or more, we just don't clone it there.

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

Alright, but what we've done here is create circles in the corners and what we actually want is... the exact opposite! What we do next is put these circles within a <mask>, on top of a white, full-size (covering the whole SVG) rectangle and then we use this mask on another full size rectangle:

<mask id='m' fill='#fff'> <rect id='r' width='100%' height='100%'/> <circle id='c' r='50' fill='#000'/> <use xlink:href='#c' x='100%'/> <use xlink:href='#c' y='100%'/> <use xlink:href='#c' x='100%' y='100%'/> </mask> <use xlink:href='#r' fill='#f90' mask='url(#m)'/>

The result can be seen below:

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

If we have text, we need to adapt the box padding to our corner radius, setting the it to the same value as we've set the radius of the SVG circle, using JavaScript to keep them in sync:

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

Of course, the fill of our background rectangle doesn't need to be a solid one. It may well be semi-transparent (as it is in the demo above), or we can use an SVG gradient or pattern for it. The latter would also allow us to use one or more background images.

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

But I came here for CSS candy!

Well, glad you asked! There are a number of things we can do here to shift the weight of the masking method from SVG to CSS.

Sadly, none of these is cross-browser, but they simplify things and they're definitely something to keep a watch for in the near or more distant future.

Use CSS masking on HTML elements instead

What we do here is remove everything outside the mask from the SVG. Then, from the CSS, we set a background (which can be semi-transparent, a CSS gradient, an image, a combination of multiple backgrounds... anything that CSS has to offer) and the mask property on the .box element:

.box { /* any kind of background we wish */ mask: url(#m); }

Note that setting an inline SVG mask on an HTML element only works in Firefox for now!

Version using CSS masking directly on our .box (live demo, Firefox only). Set the circle radius from the CSS

This means removing the r attribute from our <circle> and setting it in the CSS to the same variable as the box padding:

.box { padding: var(--r); } [id='c'] { r: var(--r); }

This way, when we change the value of --r, both the scoop radius and the padding around the .box content get updated!

Note that setting geometry properties for SVG elements from the CSS only works in Blink browsers for now!

Version using a CSS variable for the <circle> radius (live demo, Blink only). Combine the previous two methods

While this would be cool, it's sadly not possible in practice in any browser at the moment. But the good news is we can do even better than that!

Use CSS gradients for masking

Note that CSS masking on HTML elements doesn't work at all in Edge at this point, though it's listed as "In Development" and a flag for it (that doesn't do anything for now) has already shown up in about:flags.

We ditch the SVG part completely and start building our CSS gradient mask. We create the circles at the corners using radial gradients. The following CSS creates a circle of radius --r in the top left corner of a box:

.box { background: radial-gradient(circle at 0 0, #000 var(--r, 50px), transparent 0); }

It can be seen live in the demo below, where we've also given the box a red outline just so that we can see its boundaries:

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

We use the exact same gradient for our mask:

.box { /* same as before */ /* any CSS background we wish */ mask: radial-gradient(circle at 0 0, #000 var(--r, 50px), transparent 0); }

Note that WebKit browsers still need the -webkit- prefix for the mask properties.

We then add the circles at the other corners:

$grad-list: radial-gradient(circle at 0 0 , #000 var(--r, 50px), transparent 0), radial-gradient(circle at 100% 0 , #000 var(--r, 50px), transparent 0), radial-gradient(circle at 0 100%, #000 var(--r, 50px), transparent 0), radial-gradient(circle at 100% 100%, #000 var(--r, 50px), transparent 0); .box { /* same as before */ /* any CSS background we wish */ mask: $grad-list }

That's insanely repetitive, either a lot of writing or a lot of copy-pasting, so let's see what we can do about that.

First off, we use a CSS variable for the stop list. This eliminates repetition in the generated CSS.

$grad-list: radial-gradient(circle at 0 0 , var(--stop-list)), radial-gradient(circle at 100% 0 , var(--stop-list)), radial-gradient(circle at 0 100%, var(--stop-list)), radial-gradient(circle at 100% 100%, var(--stop-list)); .box { /* same as before */ /* any CSS background we wish */ --stop-list: #000 var(--r, 50px), transparent 0; mask: $grad-list; }

But it's still not much better, so let's generate the corners within a loop:

$grad-list: (); @for $i from 0 to 4 { $grad-list: $grad-list, radial-gradient(circle at ($i%2)*100% floor($i/2)*100%, var(--stop-list)); } .box { /* same as before */ /* any CSS background we wish */ --stop-list: #000 var(--r, 50px), transparent 0; mask: $grad-list; }

Much better as far as the code goes because now we don't have to write anything multiple times and run the risk of not updating everywhere later. But the result so far isn't what we were going for:

Result of the code above (live demo, no Edge support for now).

Here, we're cutting out everything but the corners, which is the opposite of what we want.

One thing we can do is reverse the gradients, make the corner circles transparent and the rest black with:

--stop-list: transparent var(--r, 50px), #000 0;

This does the trick when we use just one gradient for just one corner:

Result when using just one gradient (live demo, no Edge support for now).

However, when we stack up all four of them (or just even two), we get a black rectangle the size of our box for the mask, which means nothing actually gets masked out anymore.

Layering mask gradients (live demo, no Edge support for now).

So, we restrict each of these gradients to a quarter of our box - 50% of the width and 50% of the height, thus getting 25% (a quarter) of the area for each:

Our mask, split into four quarters (live).

This means we also need to set a mask-size of 50% 50%, a mask-repeat of no-repeat, and position each mask-image into the desired corner:

$grad-list: (); @for $i from 0 to 4 { $x: ($i%2)*100%; $y: floor($i/2)*100%; $grad-list: $grad-list radial-gradient(circle at $x $y, var(--stop-list)) /* mask image */ $x $y; /* mask position */ } .box { /* same as before */ /* any CSS background we wish */ --stop-list: transparent var(--r, 50px), #000 0; mask: $grad-list; mask-size: 50% 50%; mask-repeat: no-repeat; }

Note that WebKit browsers still need the -webkit- prefix for mask properties.

But the big problem here is... the problem with division and rounding in general—our four quarters put together don't always manage to make up a whole again, so we end up with gaps in between them.

Sadly, we may get gaps in between the four quarters (live demo).

Oh well, it's not like we can't cover up those gaps with thin linear-gradient() strips or increase the mask-size to let's say 51%:

Increasing the mask-size for each gradient layer fixes the problem of gaps (live demo).

But isn't there a more elegant way?

Well, there's a mask-composite property that can help us if we set it to intersect when reverting back to the full size gradient layers.

$grad-list: (); @for $i from 0 to 4 { $grad-list: $grad-list, radial-gradient(circle at ($i%2)*100% floor($i/2)*100%, var(--stop-list)); } .box { /* same as before */ /* any CSS background we wish */ --stop-list: transparent var(--r, 50px), #000 0; mask: $grad-list; mask-composite: exclude; }

This is extremely cool because it's a pure CSS, no SVG solution, but the not-so-good news is that support is limited to Firefox 53+ here.

Result using mask-composite: intersect (live demo).

However, it's still better than support for the final option we have when it comes to scooped corners.

The corner-shape option

Lea Verou came up with this idea some five years ago and even created a preview page for it. Sadly, not only is it not implemented by any browser yet, but the spec hasn't advanced much in the meanwhile. It's still something to keep in mind for the future, as it offers a lot of flexibility with very little code - recreating our effect would only require the following:

padding: var(--r); corner-shape: scoop; border-radius: var(--r);

No markup vomit, no long gradient lists, just this very simple piece of CSS. That is... when it finally gets supported by browsers!

The post Scooped Corners in 2018 appeared first on CSS-Tricks.

Ruby Sass to be put to pasture on March 26, 2019

Css Tricks - Tue, 04/03/2018 - 3:36am

There have long been multiple implementations of Sass. Most notably, the canonical Ruby version, now at 3.5.6. Then there is LibSass, the C++ version, which is at version 3.4 and...

Current LibSass 3.4 should be compatible with Sass 3.4.

LibSass is notable because it powers the majority of Sass ports. Over 30 of them, apparently, including the most popular one: node-sass, which provides Sass for the bajillion projects out there that wanna run an npm-y JavaScript-based dev environment and avoid the Ruby dependency.

It's a little unfortunate LibSass isn't up-to-date with current canonical Sass, but I think it's on freeze as it's been stated that LibSass will never be canonical Sass. Update: it's not on freeze. It was actually Ruby Sass that was once on freeze with the intention of allowing LibSass to catch up. As I write, LibSass is at 3.5.2, so it's close.

Dart Sass just went 1.0.0, and is now 100% compatible with Ruby Sass 3.5.6. They announced that Ruby Sass has now begun deprecation and—after March 26th, 2019—will no longer be maintained.

The future of Dart Sass looks pretty good:

Another big announcement: as of today, I'm working full-time on @SassCSS. This has been a goal for my entire career and I'm thrilled that it's finally happening

— Blue Gay Carmen San Diego (@nex3) April 3, 2018

The Dart Sass compatibility is also great, because node-sass can now switch to Dart Sass bindings and become entirely up to date. Will it? I have no idea. The maintainer of LibSass and node-sass is the same person (Michael Mifsud), and with 30+ bindings to LibSass, I can't imagine LibSass just going away. I guess we'll just have to wait and see a while. I gotta imagine someone will jump on making a node version of Dart Sass one way or another.

I, for one, would love to see a Web Worker version.

The post Ruby Sass to be put to pasture on March 26, 2019 appeared first on CSS-Tricks.

An Event Apart: The Way of the Web

LukeW - Mon, 04/02/2018 - 2:00pm

In his The Way of the Web presentation at An Event Apart in Seattle, Jeremy Keith discussed building for the Web today and how to manage the rate of change of technologies and tools for Web development. Here's my notes from his talk:

  • Science fiction is not about predicting the future, it is about looking at the concerns we have today and projecting them forward. Novels are empathy machines. You can really get into what the characters were feeling/experiencing and thereby share their concerns.
  • While science fiction books get some things right about the future, they also have blind spots. For instance, people went to phone booths instead of carrying mobile phones. In the present we have a future that was almost beyond what was predicted in seminal works of science fiction.
  • With where technology is today and what is possible, are we in a utopia or a dystopia? Are we excited or afraid of technology's possibilities. What makes the difference? Why are we excited about some technologies and apprehensive about others?
  • Working on the Web can be overwhelming as we have to endure constant changes in technology and processes. When that rate of change is especially steep, things get worse.
  • Stewart Brand's pace layers outline the rate of change of everything from people to buildings. Fashion changes quickly, culture changes slowly, and that's good. We get apprehensive when things that should move slow start changing too quickly. Example: quick changes in government are usually revolutions.
  • The materials of the Web (HTML, CSS, and Javascript) move slow and are more stable, they are lower pace layers. The tools of the Web move much faster and are more subject to change.
  • If a technology helps the developer but not the end user, there's a balance that needs to be understood. Is the trade-off of developer convenience worth a large download for users?
  • We can map Web technologies to pace layers. The bottom layer is the Internet (TCP/IP). This hasn't changed in decades and you don't want it to change. HTTP is the protocol layer above this and is changes very slowly, which is appropriate. URLs are the layer above, which change often but probably shouldn't. HTML and CSS are changing much more quickly but still not as fast as Javascript.
  • Every week there is a new Javascript library, which is where the Web feels apprehensive. Ideas get vetted out in Javascript and when they stabilize, they move down to HTML and CSS. It's ok that Javascript changes quickly -it needs to in order to work out new ideas.
  • You can choose to build single page Web sites in Javascript only. Going directly to URLs and HTTP. However this sets up a works great or doesn't work model. The power of the Web is that we have different levels of "working", a continuum. Everybody gets something with these in-between levels of experience.
  • The rule of least power: "choose the language of least power to accomplish something" It's not as powerful, but much more stable. Instead of doing everything in Javascript, see what can be done in HTML and CSS first.
  • The Web favors ubiquity over consistency. You can get to the content but it may not look the same to everyone. Start with the simplest element (like a select) and gradually apply styling/code to layer on additional enhancements.
  • This mode of building for the Web isn't just for simple sites. Even "complex" sites can be broken down into simpler elements. There's actually a continuum between simple and complex.
  • Progressive Web apps are Web sites that add HTTPS, a Web app manifest, and a service worker. This layering of technology allows sites to not only run securely but also offline.
  • People want browser features to be supported everywhere before they start using them, but that's not how it works. You can start using these elements now even if they only have partial support and get the benefits where they're available.

An Event Apart: Performance as User Experience

LukeW - Mon, 04/02/2018 - 2:00pm

In his Performance as User Experience presentation at An Event Apart in Seattle, Aaron Gustafson shared a number of ways to optimize Web page performance. Here's my notes from his talk:

  • Our jobs as designers is to reduce friction for our users. Poor performance causes friction and can negatively impact key metrics like conversion and revenue.
  • How do Web pages load: when you enter an address in a URL bar, a DNS look-up replies with an IP address, then there's a TCP handshake followed by the actual request for files/data, once there's a response the browser can actually do something.
  • Once the browser gets a response, it can assemble the document object, the render tree, layout, paint, and finally load. CSS and Javascript can delay this process and sometimes cause it to run again.
Steps for better performance
  • Use native features whenever possible. They are effectively free. Semantic elements not only reduce bytes but also contain attributes that provide a lot of functionality like placeholder, autocomplete, autocorrect, type, etc. System fonts can help reduce the need for custom font downloads. Font stacks can cover fallback issues.
  • Only include assets you actually need. Every tool has a cost, make sure you are really using enough of each tool to justify that cost. Chances are the tool you are trying to use is already on a CDN and you can use resource hints to speed up the download process. But downloading isn't everything as Javascript frameworks also take time to execute, which is slower than native JS processing.
  • Optimize everything. Task runners like Grunt and Gulp can help automate optimizations of Javascript, CSS and HTML. Minify and pre-compress all your files.
  • Think about when you load assets. If you have Javascript files divided into modules, you can defer functions you won't need until the after the DOM is loaded. The async attribute also allows you to load files when it makes the most sense. Just make sure you don't hit any race conditions if some of your Javascript files have dependencies on others.
  • Why so many different files? Under HTTP1, each resources was requested sequentially. Now with HTTP2, you set a single connection and then stream in resources as needed.
  • Consider how you load assets. Start simple by loading just your default (often mobile) CSS file. You can add a media query as a threshold for loading more advanced CSS in browsers than can render it. Conditional comments (which only work in IE8 and below) can either load or hide elements from older browsers. Similar techniques can be used to conditionally load images and animations (via SVG support).
  • Only load assets when they add value. Not every article needs an image, think twice before you include it. Images are 53% of the average web page and very expensive size-wise. If you need an image, use the right format. GIFs ae good for solid colors, JPGs for photographs, PNGs are JPG alternatives with alpha transparency, WebPs are note well supported but optimized in many ways.
  • Images can be optimized by removing color, blurring parts of images, resizing, compressing, and using appropriate formats. We can use the picture element to add WebP images in browsers that support them. Remember to put your smallest files first, because the first one that works is what gets used.
  • Every choice we make affects our users’ experiences. Let’s spend our time to save it for our users.

An Event Apart: Navigating Team Friction

LukeW - Mon, 04/02/2018 - 2:00pm

In her Navigating Team Friction presentation at An Event Apart in Seattle, Lara Hogan discussed what causes teams at work to have issues and how to address them. Here's my notes from her talk:

  • Teams of people are amazing. Its a privilege to work together with people to make things.
  • Bruce Tuckman found a series of stages that groups of people go through: forming (comes together in a new state), storming (some friction emerges), norming (clarity begins to emerge), performing (effective state). This is a cycle that repeats itself regularly.
  • Storming is a natural part of team dynamics but it does create friction. You need to be able to move past the friction in order to focus on what actually matters.
  • It can take a while for managers to identify and resolve points of friction. So what can team members do to address the issue earlier on?
Core Needs
  • Everyone transforms into different versions of themselves sometimes. The rationale part of our brains isn't always in control. Instead, we may be reacting to fear and/or threats that put us into fight or flight mode. These reactions come from more than use physical safety and shelter needs.
  • Modern humans have several core needs. First, people need to belong to a group or community. Second, people need to make improvements and/or progress (for team, company, or personally). Third, people need to be able to make choices about their work -they need flexibility, and decision-making capabilities. Fourth, people need access to equal resources, information, and fairness. Fifth, people require some amount of predictability in their work days. Lastly, people need to feel their work matters -they need recognition and visibility for work.
  • The BICEPS model (the needs above) gives you a way to assess what could be causing team friction.
  • As an example, moving desks are a great example of why people react emotionally to seemingly sound rationale decisions. They impact belonging, choice, predictability, etc. but do so differently for different people. To address these issues, try to identify the core need being effected.
  • To find which core needs are being impacted, look at the types of resistance you are seeing. Doubt: asking lots of questions/debating the issue. Avoid: not showing up. Fight: people create arguments against the issue. Bond: go to friends & peers to find support. Escape-route: changing roles, leaving company to avoid the threat.
Communication Style
  • When you spot some signals, ask open questions (which are different than yes/no questions). This helps you understand which core needs are being threatened on the team. Then you can figure out how to address the issue.
  • Reflect on the dynamics of the room, what are they thinking and/or worried about? Be aware of your medium: what words, body language are you using?
  • When you make an ask of someone, consider if they can act on what you are saying. Don't tear things down, try to elevate the conversation by being transparent.
  • Assume everyone has the best intentions at work and try to empathize with what other people may be going through.
  • Listen to learn: stay genuinely curious. Operate under the assumption that you don't know the whole story. Be excited to have your mind changed, it helps you learn and grow.
  • Humans aren't great at feedback but we can get better. Good feedback is specific and actionable. This kind of feedback helps us improve and grow.
  • Structure your feedback as: observation of a behavior (just the facts)+ impact of that behavior (share how you feel) + question or request. Write it out first to make sure it's communicating what you want.
  • It's ok to cause some friction, that's a natural part of working together. But know how you can move past it.
  • Retrospectives allow people to know their feelings have been heard. Name friction points in these meetings to acknowledge what didn't work.
  • Team charters and docs can helps align people's work against a common vision and clear responsibilities.
  • The absence of trust is the source of most team dysfunctions. How do you get these issues surfaced within a team? Determine if you agree or disagree with decisions and whether or not you can commit to a decision.
  • If/when you need to go to HR or leadership, state what's been tried and what you think could help now. Be prepared that they may take a different action after weighing the situation.

IBM Plex

Css Tricks - Mon, 04/02/2018 - 11:32am

Here’s a free new font for IBM Plex, a family of typefaces by the iconic company of the same name. It's on Google Fonts if you want to use it.

And we're talking about a multifaceted font. It touts having:

  • Roman and Italics
  • Four subfamilies
  • Eight weights
  • Support for 100 languages

The site promoting the font is noteworthy in and of itself. It's been designed to showcase how the typefaces were built as a single, complex system and tells the story in interactive sections using a parallax effect. Even if you’re not a big fan of the typefaces themselves (although I certainly am), it’s still super interesting to see how they visually describe the challenges they faced when in the design process. There’s lots of weird and interesting UI things going on here.

If you love news about companies making their own fonts, there have been a few others lately like U.S. Soccer's 90 Minutes and Netflix Sans.

Direct Link to ArticlePermalink

The post IBM Plex appeared first on CSS-Tricks.

Catching up on AMP News

Css Tricks - Mon, 04/02/2018 - 8:55am

The big news since we last talked about AMP is that the AMP team announced that there will be a way for non-AMP sites to make their way into the coveted Google search results carousel. Malte Ubl:

Based on what we learned from AMP, we now feel ready to take the next step and work to support more instant-loading content not based on AMP technology in areas of Google Search designed for this, like the Top Stories carousel.

You can't do it now, nor is it clear exactly how you'll be whitelisted, but apparently Google is open to it. The ticket in will be utilizing hopefully-someday standardized things like Feature Policies, which, like AMP, disallow certain features in the name of... well that's the thing. It used be be in the name of speed, but the messaging seems to be more like in the name of privacy and security now. Also a good goal, just funny that "Pages" is about the last thing left in the AMPcroymn. Sorry.

This is the checklist of related technologies. Makes my eyes glaze over a bit as I know precious little about any of them. Much of it needs to progress through standards processes and browser implementation first, and we'll just have to see how practical it all is. If it means people stop creating amp-dot version of their websites (the new m-dot), that'd be pretty swell.

Tim Kadlec and Yoav Weiss got shout-outs in that AMP announcement for their idea of a "Content Performance Policy". As in, if a website promises and upholds the promises of being fast and not doing nefarious crap, it gets the same benefits as an AMP site.

I mention that as Tim has some new AMP data to share, directly related to AMP's speed. Tim found 50 random news article pages that were using AMP and tested them various ways. I'll summarize the results in best to worst order:

  1. The non-AMP version: not great
  2. AMP version standalone: a bit better
  3. AMP version with cached copy of AMP library: a good bit better
  4. AMP version from Google Search: instant

Tim mentions that it isn't very useful to test against those instant results:

evaluating AMP’s performance based on how those pages load in search results tells us nothing about the effectiveness of AMP itself, but rather the effectiveness of preloading content.

If we can adhere to some standards-based stuff and get Google doing that same preloading for those of us who'd rather not amp-dot, that'd be great. Show me the money. Did I do that movie reference right? I never saw that movie.

The post Catching up on AMP News appeared first on CSS-Tricks.

Iron Man’s Arc Reactor Using CSS3 Transforms and Animations

Css Tricks - Mon, 04/02/2018 - 3:29am

Alright Iron Man fans, fire up your code editors! We are going to make the Arc reactor from Iron Man’s suit in CSS. Here’s what the end result will look like:

See the Pen Iron Man's Arc Reactor by Kunal Sarkar (@supersarkar) on CodePen.

The Full Page Wrapper

We will make our Arc reactor on a dark full-page background. Here’s our code to make a full page wrapper element:

body { margin: 0; } .fullpage-wrapper { height: 100vh; background: radial-gradient(#353c44, #222931); }

Why do we declare no margin on the body? The <body> element has some margin set to it by default in the user agent stylesheet. This prevents the elements inside the <body> to touch the edges of the screen. Since we want our wrapper to cover the entire screen, edge to edge, we removed that default margin on <body> element by setting it to 0.

We’ve given our .fullpage-wrapper the full height of the viewport. We don’t have to specify a width because a div is full width by default. We could have gone with another approach by setting both the width and height of the element to 100% but that comes with some possible drawbacks as more elements are added to the screen. Using viewport units ensures our wrapper always occupies the full vertical space of the screen, regardless of what it is or what other elements are added to the layout.

We also used a radial gradient on our wrapper using radial-gradient() CSS function. The parameters inside the function are the color start and end points. So, the center of the background will be more #353c44 and more #222931 towards the edges. It’s subtle, but a nice touch.

Centering the Reactor Container

Before we start creating our reactor, let’s create a container for it and center it:

.reactor-container { width: 300px; height: 300px; margin: auto; border: 1px dashed #888; }

This gives us a 300px x 300px box with dashed border. The margin: auto; declaration ensures equal horizontal spacing.

But why it doesn’t center it vertically?

Per CSS2 specs, if we give auto margin to the left and right side, then the entire available space will be equally divided to left and right margin. This isn’t the same case for the top and bottom margin though. For top and bottom margin the CSS2 spec says:

If margin-top, or margin-bottom are auto, their used value is 0.

However, we do have a good news. The flexbox layout follows new rules of alignment, and here’s what the Flexbox spec has to say:

Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.

This means if the element in consideration is displayed as a flex item, then margin: auto; will work in both the directions. Let’s make our wrapper a flex container and its child elements flex items:

.fullpage-wrapper { width: 100%; height: 100vh; background: radial-gradient(#353c44, #222931); display: flex; }

There, that’s much better:

There are many other methods to center elements in HTML. There’s a detailed guide on centering right here on CSS-Tricks to learn more.

The Reactor Core: Concentric Circles in CSS

We know that new elements in HTML are created from left to right (for left-to-right languages), or top to bottom. Elements never overlap, until you provide some negative margin.

So, how are we going to display concentric circles? We will use absolute positioning.

The default value of position property is static. Static and relative positioning follow the flow of top to bottom and left to right. However, an absolutely positioned element is not treated as a part of the document flow and can be positioned anywhere using the top, right, bottom and left properties.

Let’s start by creating the smallest circle:

<div class="fullpage-wrapper"> <div class="reactor-container"> <!-- the smallest circle --> <div class="core-inner"></div> </div> </div> .core-inner { position: absolute; width: 70px; height: 70px; border-radius: 50%; border: 5px solid #1b4e5f; background-color: #fff; }

We need to center this div. You might be tempted to apply the same flexbox concept we used on the reactor element to center this circle as well. But, here’s what CSS2 spec has to say about setting margin: auto; on absolutely positioned elements:

If none of the three (top, height, and bottom) are auto: If both margin-top and margin-bottom are auto, solve the equation under the extra constraint that the two margins get equal values.

This means if an absolutely positioned element has any value for top, height and bottom other than auto, then setting the top and bottom margin to auto will center the element vertically.

Same case for horizontal centering: if an absolutely positioned element has any value for left, width and right other than auto, then setting the left and right margin to auto will center the element horizontally.

That means we don’t need flexbox layout to center an absolutely positioned element with a known height and width. We just have to make sure that we give some value to top, right, bottom and left other than auto. So, we will use 0:

.core-inner { position: absolute; width: 70px; height: 70px; top: 0; right: 0; bottom: 0; left: 0; margin: auto; border-radius: 50%; border: 5px solid #1b4e5f; background-color: #fff; }

We do not want to repeat these five lines for all the concentric circles we are going to have, so let’s create a separate class for this. We also don’t want to define border-radius: 50%; for all the divs that we want to display as circles, so we will create a class for that too:

.circle { border-radius: 50%; } .abs-center { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; } .core-inner { width: 70px; height: 70px; border: 5px solid #1b4e5f; background-color: #fff; }

Also, add these new classes to out .core-inner element:

<div class="fullpage-wrapper"> <div class="reactor-container"> <!-- the smallest circle --> <div class="core-inner circle abs-center"></div> </div> </div>

Okay, our concentric circle is centered. Let’s make it glow.

But CSS doesn’t have any "glow" property.

Don’t worry, we have the box-shadow property. Instead of giving the shadow a dark color, we will give it a bright color to make the shadow look like glow. Pretty clever, isn’t it? &#x1f609;

Let’s do this:

.core-inner { width: 70px; height: 70px; border: 5px solid #1b4e5f; background-color: #fff; box-shadow: 0px 0px 7px 5px #52fefe; }

Let’s take a break and understand the syntax of box-shadow first because we will be using it a lot. Here are what those values for box-shadow mean in that order:

  • x-offset: how much we want to push the shadow on the right side (x-axis). Negative values will push the shadow to the left side.
  • y-offset: how much we want to push the shadow up or down (y-axis).
  • blur-radius: how blurry we want our shadow to be.
  • spread-radius: how much we want our shadow to spread.
  • color: color of the shadow.

Play with these values a bit to see their effects in real time.

In real life, shadows don’t drop only outside of an object. Shadows drop upon the objects too. Imagine a pit dug by a dog, it will have a shadow inside it, right?

We can give a shadow inside an element using the inset keyword in the box-sizing property. To give an element both, outside and inside shadow, we simply separate them with a comma. Let’s do this to get an outside and inside glow to our reactor’s inner core:

.core-inner { width: 70px; height: 70px; border: 5px solid #1B4e5f; background-color: #fff; box-shadow: 0px 0px 7px 5px #52fefe, 0px 0px 10px 10px #52fefe inset; }

Now it’s starting to look sci-fi!

Let’s create one more circle on top. We want the inner circle to display on top of the other circles, so we will add new circle divs *above* the inner-circle in code:

<div class="fullpage-wrapper"> <div class="reactor-container"> <!-- the second circle --> <div class="core-outer circle abs-center"></div> <!-- the smallest circle --> <div class="core-inner circle abs-center"></div> </div> </div>

The elements down in the code, are displayed above on the screen. If we put the core-outer below the core-inner in the code, then core-inner won’t be visible, because core-outer will cover it.

Let’s give style to outer-code. The outer core will be a little bigger than the inner core and we will give an outer and inner glow to core-outer too:

.core-outer { width: 120px; height: 120px; border: 1px solid #52fefe; background-color: #fff; box-shadow: 0px 0px 2px 1px #52fefe, 0px 0px 10px 5px #52fefe inset; }

I want you to do one thing: look at the shadows (glow) and try to identify which one is of which circle. There are four shadows and two circles (until now).

To finish designing the core, we will need one more circle that will wrap the inner and outer circles:

<div class="fullpage-wrapper"> <div class="reactor-container"> <!-- the third circle --> <div class="core-wrapper circle abs-center"></div> <!-- the second circle --> <div class="core-outer circle abs-center"></div> <!-- the smallest circle --> <div class="core-inner circle abs-center"></div> </div> </div>

This one will be a little bigger, and will again have same shadows, we will use a dark background for core-wrapper:

.core-wrapper { width: 180px; height: 180px; background-color: #073c4b; box-shadow: 0px 0px 5px 4px #52fefe, 0px 0px 6px 2px #52fefe inset; } Creating Reactor Coils and Rotating with CSS3 Transforms

We have the core of the reactor, now we need a tunnel around the core. Actually, we can create an illusion of a round tunnel by drawing just one more circle little bigger than the core-wrapper. Let’s do it:

<div class="fullpage-wrapper"> <div class="reactor-container"> <!-- the largest circle --> <div class="tunnel circle abs-center"></div> <!-- the third circle --> <div class="core-wrapper circle abs-center"></div> <!-- the second circle --> <div class="core-outer circle abs-center"></div> <!-- the smallest circle --> <div class="core-inner circle abs-center"></div> </div> </div>

...a little wider and add same glow to the tunnel:

.tunnel { width: 220px; height: 220px; background-color: #fff; box-shadow: 0px 0px 5px 1px #52fefe, 0px 0px 5px 4px #52fefe inset; }

Our tunnel is ready.

Make sure you do not just copy paste the code. Have a look at the glows of the circles and identify which glow is of which circle, whether it is outside glow or inset glow.

Now, we need eight coils on this tunnel. The coils are simple rectangles, but the major challenge is that we need the coils to run along the round path of the tunnel; not in straight line.

One way to do this would be to create eight small rectangles, shift their center to the center of the reactor, and rotate each coil by an increasing angle (in multiples of 45deg).

Let’s not complicate it and make one rectangle coil at a time:

<div class="fullpage-wrapper"> <div class="reactor-container"> <div class="tunnel circle abs-center"></div> <div class="core-wrapper circle abs-center"></div> <div class="core-outer circle abs-center"></div> <div class="core-inner circle abs-center"></div> <div class="coil-1"></div> </div> </div> .coil-1 { position: absolute; width: 30px; height: 26px; background-color: #073c4b; box-shadow: 0px 0px 5px #52fefe inset; }

Now, we want to place this coil in the center at top of the tunnel. Like this:

Our reactor-container is 300px x 300px, so the center is at 150px from top and left. The tunnel is 220px wide, so its radius will be 110px. This gives us the top offset of the coil: 150px - 110px.

We can keep left of the coil to 150px, but since our coil is 30px wide, it will shift the middle of the coil by 15px to right, that’s why we need to subtract 15px from 150px to get the left offset of the coil.

We can either calculate these ourselves and put the value, or we can use the CSS calc() function. Let’s use the CSS calc() function to calculate the top and left properties of the coil:

.coil-1 { position: absolute; width: 30px; height: 20px; top: calc(50% - 110px); left: calc(50% - 15px); background-color: #073c4b; box-shadow: 0px 0px 5px #52fefe inset; }

As you can see, the calc() function takes a mathematical expression as its argument and solves it.

Now we need eight such coils but they must lie on the tunnel. To do that, as discussed, we can simply place the eight coils at this same place, then transform their origin to the center of the reactor, and rotate each coil by an increment of 45 degrees.

We need to update the coil’s origin because by default it is set to the center of the coil; we want it at center of the reactor:

We will use transform-origin property to set the origin of the coil:

.coil-1 { position: absolute; width: 30px; height: 20px; top: calc(50% - 110px); left: calc(50% - 15px); transform-origin: 15px 110px; background-color: #073c4b; box-shadow: 0px 0px 5px #52fefe inset; }

The first value, 15px, in transform-origin is the x-offset (horizontal distance) from the top-left corner of the element, and the second value, 110px, is the y-offset (vertical distance) from the top-left corner of the element.

The coil’s origin is now at the center of the reactor, let’s rotate it by 45 degrees using the CSS3 transform property and see what happens:

.coil-1 { position: absolute; width: 30px; height: 20px; top: calc(50% - 110px); left: calc(50% - 15px); transform-origin: 15px 110px; transform: rotate(45deg); background-color: #073c4b; box-shadow: 0px 0px 5px #52fefe inset; }

Great! That’s exactly what we want.

Before creating all the eight coils, let’s create a coil container div that will contain all the eight coils:

<div class="fullpage-wrapper"> <div class="reactor-container"> <div class="tunnel circle abs-center"></div> <div class="core-wrapper circle abs-center"></div> <div class="core-outer circle abs-center"></div> <div class="core-inner circle abs-center"></div> <!-- the coil container --> <div class="coil-container"> <div class="coil coil-1"></div> </div> </div> </div>

You will notice we also added a class "coil" to the "coil-1" element. We will keep all the common styles for coils in the "coil" class, and the individual coil element classes will only have their angle of rotation:

.coil-container { position: relative; width: 100%; height: 100%; } .coil { position: absolute; width: 30px; height: 20px; top: calc(50% - 110px); left: calc(50% - 15px); transform-origin: 15px 110px; background-color: #073c4b; box-shadow: 0px 0px 5px #52fefe inset; } .coil-1 { transform: rotate(45deg); }

The output will remain same.

Now, let’s make all the eight coils inside .coil-container:

<div class="fullpage-wrapper"> <div class="reactor-container"> <div class="tunnel circle abs-center"></div> <div class="core-wrapper circle abs-center"></div> <div class="core-outer circle abs-center"></div> <div class="core-inner circle abs-center"></div> <!-- the coil container --> <div class="coil-container"> <div class="coil coil-1"></div> <div class="coil coil-2"></div> <div class="coil coil-3"></div> <div class="coil coil-4"></div> <div class="coil coil-5"></div> <div class="coil coil-6"></div> <div class="coil coil-7"></div> <div class="coil coil-8"></div> </div> </div> </div>

...and give different rotations to all the coils (in increment of 45 degrees):

.coil { position: absolute; width: 30px; height: 20px; top: calc(50% - 110px); left: calc(50% - 15px); transform-origin: 15px 110px; background-color: #073c4b; box-shadow: 0px 0px 5px #52fefe inset; } .coil-1 { transform: rotate(0deg); } .coil-2 { transform: rotate(45deg); } .coil-3 { transform: rotate(90deg); } .coil-4 { transform: rotate(135deg); } .coil-5 { transform: rotate(180deg); } .coil-6 { transform: rotate(225deg); } .coil-7 { transform: rotate(270deg); } .coil-8 { transform: rotate(315deg); }

Our reactor is almost ready.

Animating the Coils With CSS3 Animations

In Iron Man’s Arc reactor, the coils don’t move but they will in our reactor. We will animate the coils to rotate along the tunnel and will use CSS3 animations for this—no JavaScript.

To create an animation, you need to know the initial and final states of the object you are going to animate. We define these initial and final states in CSS by using @keyframes at-rule:

@keyframes reactor-anim { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

We want the element to be at 0 degrees and animate it until it reaches 360 degrees. And we named this animation as "reactor-anim."

The element we want to animate is .coil-contailer. Notice, we didn’t define which object to animate yet, we have only defined the initial and the final state and name of the animation.

We need to link the element to the animation in order to take effect. We do it by using animation-name property on .coil-container:

.coil-container { position: relative; width: 100%; height: 100%; animation-name: reactor-anim; animation-duration: 3s; }

Notice, we also gave the duration of animation using animation-duration property. This defines how much time it should take to go from the “from” state to the “to” state defined using the @keyframes at-rule.

See the Pen Arc-Reactor-Ease-In by Kunal Sarkar (@supersarkar) on CodePen.

We need to change two things here: we want the animation to go on infinitely and we want a linear animation. You can see the animation is slow at the beginning, then fast, then again slow at the end—this behavior is defined by the timing function of an animation.

Let’s make these changes:

.coil-container { position: relative; width: 100%; height: 100%; animation-name: reactor-anim; animation-duration: 3s; animation-iteration-count: infinite; animation-timing-function: linear; }

We used animation-iteration-count property to set the animation to infinite, and animation-timing-function to make the animation linear, the default value of animation-timing-function is ease.

See the Pen Arc-Reactor-Linear-Infinite by Kunal Sarkar (@supersarkar) on CodePen.

We can combine all of these animation properties...

animation-name: reactor-anim; animation-duration: 3s; animation-iteration-count: infinite; animation-timing-function: linear;

...into one shorthand property like this:

animation: 3s infinite linear reactor-anim; Final Touches to the Reactor Container

Our reactor is ready, now let’s make some final changes to the .reactor-container. First, we will need one dark circle behind the reactor:

<div class="fullpage-wrapper"> <div class="reactor-container"> <!-- dark circle behind the reactor --> <div class="reactor-container-inner circle abs-center"></div> <div class="tunnel circle abs-center"></div> <div class="core-wrapper circle abs-center"></div> <div class="core-outer circle abs-center"></div> <div class="core-inner circle abs-center"></div> <div class="coil-container"> <div class="coil coil-1"></div> <div class="coil coil-2"></div> <div class="coil coil-3"></div> <div class="coil coil-4"></div> <div class="coil coil-5"></div> <div class="coil coil-6"></div> <div class="coil coil-7"></div> <div class="coil coil-8"></div> </div> </div> </div>

Let’s give a dark background and add some glow to it:

.reactor-container-inner { height: 238px; width: 238px; background-color: rgb(22, 26, 27);; box-shadow: 0px 0px 4px 1px #52fefe; }

See the Pen Arc-Reactor-Semi-Final by Kunal Sarkar (@supersarkar) on CodePen.

See how the dark background and the glow creates an emboss effect?

Next, let’s make the .rotator-container round and give it some shadow and border, then we are done:

.reactor-container { width: 300px; height: 300px; margin: auto; border: 1px dashed #888; position: relative; border-radius: 50%; background-color: #384c50; border: 1px solid rgb(18, 20, 20); box-shadow: 0px 0px 32px 8px rgb(18, 20, 20), 0px 0px 4px 1px rgb(18, 20, 20) inset; }

See the Pen Iron Man's Arc Reactor by Kunal Sarkar (@supersarkar) on CodePen.

Cheers! Our Arc Reactor is ready and even with a little animation as an added bonus. To level this up, we could explore using custom properties to create reusable variables for our color and number values for easier maintenance. Similarly, we could look into using a preprocessor—like Sass, Less or PostCSS—to write functions that do the mathematical lifting for us. Would love to see examples like that in the comments!

The post Iron Man’s Arc Reactor Using CSS3 Transforms and Animations appeared first on CSS-Tricks.

An Event Apart: Content Performance Quotient

LukeW - Sun, 04/01/2018 - 2:00pm

In his Beyond Engagement: the Content Performance Quotient presentation at An Event Apart in Seattle, Jeffrey Zeldman introduced a new metric for tracking how well Web sites are performing. Here's my notes from his talk:

  • The number one stakeholder request for Web sites is engagement: we need people using our services more. But is it the right metric for all these situations?
  • For some apps, engagement is clearly the right thing to measure. For others, more time spent might be a sign of frustration.
  • Most of the Web sites we work on are like customer service desks where we want to give people what they need and get them on their way.
  • Content Performance Quotient (Design CPQ) is a metric of how quickly we can get the right content to solve the customer's problem. The shortest distance between problem & solution. This tracks your value to the customer by measuring the speed of usefulness.
  • Pretty garbage: when a Web site looks good but doesn't help anyone. Garbage in a delightfully responsive grid is still garbage.
  • Slash your architecture and shrink your content. Ask: "why do we need this?" Compare all your content to the goals you've established. Design should be intentional. Have purpose-driven design and purpose-driven content.
  • We can't always have meetings where everybody wins. We need to argue for the customer and that means not everyone in our meetings will get what they want. Purpose needs to drive our collaborations not individual agendas, which usually leak into our Web site designs.
  • It’s easy to give every stakeholder what they want. Don't take the easy way out. It’s harder to do the right thing. Harder for us, but better for the customer & bottom line.
  • Understanding the customer journey allows us to put the right content in the right place. Start with the most important interaction and build out from there. Focus on key interactions and build out form there.
  • Customers come to our sites with a purpose. Anything that gets in the way of that is a distraction. Constantly iterate on content to remove the cruft and surface what's needed.
  • When you want people to go deeper and engage, to slow down... scannability, which is good for transactions, can be bad for thoughtful content. Instead slow people down with bigger type, better typographic hierarchy, more whitespace.
  • Which sites should be slow? If the site is delivering content for the good of the general public, the presentation should enable slow, careful reading. If it’s designed to promote our business or help a customer get an answer to her question, it must be designed for speed of relevancy.
Syndicate content
©2003 - Present Akamai Design & Development.