Web Standards

Quick LocalStorage Usage in Vue

Css Tricks - Thu, 11/05/2020 - 9:20am

localStorage can be an incredibly useful tool in creating experiences for applications, extensions, documentation, and a variety of use cases. I’ve personally used it in each! In cases where you’re storing something small for the user that doesn’t need to be kept permanently, localStorage is our friend. Let’s pair localStorage with Vue, which I personally find to be a great, and easy-to-read developer experience.

Simplified example

I recently taught a Frontend Masters course where we built an application from start to finish with Nuxt. I was looking for a way that we might be able to break down the way we were building it into smaller sections and check them off as we go, as we had a lot to cover. localStorage was a gsolition, as everyone was really tracking their own progress personally, and I didn’t necessarily need to store all of that information in something like AWS or Azure.

Here’s the final thing we’re building, which is a simple todo list:

CodePen Embed Fallback Storing the data

We start by establishing the data we need for all the elements we might want to check, as well as an empty array for anything that will be checked by the user.

export default { data() { return { checked: [], todos: [ "Set up nuxt.config.js", "Create Pages", // ... ] } } }

We’ll also output it to the page in the template tag:

<div id="app"> <fieldset> <legend> What we're building </legend> <div v-for="todo in todos" :key="todo"> <input type="checkbox" name="todo" :id="todo" :value="todo" v-model="checked" /> <label :for="todo">{{ todo }}</label> </div> </fieldset> </div> Mounting and watching

Currently, we’re responding to the changes in the UI, but we’re not yet storing them anywhere. In order to store them, we need to tell localStorage, “hey, we’re interested in working with you.” Then we also need to hook into Vue’s reactivity to update those changes. Once the component is mounted, we’ll use the mounted hook to select checked items in the todo list then parse them into JSON so we can store the data in localStorage:

mounted() { this.checked = JSON.parse(localStorage.getItem("checked")) || [] }

Now, we’ll watch that checked property for changes, and if anything adjusts, we’ll update localStorage as well!

watch: { checked(newValue, oldValue) { localStorage.setItem("checked", JSON.stringify(newValue)); } } That’s it!

That’s actually all we need for this example. This just shows one small possible use case, but you can imagine how we could use localStorage for so many performant and personal experiences on the web!

The post Quick LocalStorage Usage in Vue appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Build an app for monday.com and potentially win BIG

Css Tricks - Thu, 11/05/2020 - 9:18am

monday.com is an online Work OS platform where teams create custom workflows in minutes to run their projects, processes, and everyday work.

Over 100,000 teams use monday.com to work together.

They have launched a brand new app marketplace for monday.com, meaning you can add tools built by third-party developers into your monday.com space.

You can build apps for this marketplace. For example, you could build a React app (framework doesn’t matter) to help make different teams in an organization work better together, integrate other tools, make important information more transparent, or anything else you can think of that would be useful for teams.

You don’t need to be a monday.com user to participate. You can sign up as a developer and get a FREE monday.com account to participate in the contest.

Do a good job, impress the judges with the craftsmanship, scalability, impact, and creativity of your app, and potentially win huge prices. Three Teslas and ten MacBook Pro’s are among the top prizes. Not to mention it’s cool no matter what to be one of the first people building an app for this platform, with a built-in audience of over 100,000.

Learn More & Join Hackathon

The post Build an app for monday.com and potentially win BIG appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Animate the Details Element Using WAAPI

Css Tricks - Thu, 11/05/2020 - 5:01am

Animating accordions in JavaScript has been one of the most asked animations on websites. Fun fact: jQuery’s slideDown() function was already available in the first version in 2006.

In this article, we will see how you can animate the native <details> element using the Web Animations API.

CodePen Embed Fallback HTML setup

First, let’s see how we are gonna structure the markup needed for this animation.

The <details> element needs a <summary> element. The summary is the content visible when the accordion is closed.
All the other elements within the <details> are part of the inner content of the accordion. To make it easier for us to animate that content, we are wrapping it inside a <div>.

<details> <summary>Summary of the accordion</summary> <div class="content"> <p> Lorem, ipsum dolor sit amet consectetur adipisicing elit. Modi unde, ex rem voluptates autem aliquid veniam quis temporibus repudiandae illo, nostrum, pariatur quae! At animi modi dignissimos corrupti placeat voluptatum! </p> </div> </details> Accordion class

To make our code more reusable, we should make an Accordion class. By doing this we can call new Accordion() on every <details> element on the page.

class Accordion { // The default constructor for each accordion constructor() {} // Function called when user clicks on the summary onClick() {} // Function called to close the content with an animation shrink() {} // Function called to open the element after click open() {} // Function called to expand the content with an animation expand() {} // Callback when the shrink or expand animations are done onAnimationFinish() {} } Constructor()

The constructor is the place we save all the data needed per accordion.

constructor(el) { // Store the <details> element this.el = el; // Store the <summary> element this.summary = el.querySelector('summary'); // Store the <div class="content"> element this.content = el.querySelector('.content'); // Store the animation object (so we can cancel it, if needed) this.animation = null; // Store if the element is closing this.isClosing = false; // Store if the element is expanding this.isExpanding = false; // Detect user clicks on the summary element this.summary.addEventListener('click', (e) => this.onClick(e)); } onClick()

In the onClick() function, you’ll notice we are checking if the element is being animated (closing or expanding). We need to do that in case users click on the accordion while it’s being animated. In case of fast clicks, we don’t want the accordion to jump from being fully open to fully closed.

The <details> element has an attribute, [open], applied to it by the browser when we open the element. We can get the value of that attribute by checking the open property of our element using this.el.open.

onClick(e) { // Stop default behaviour from the browser e.preventDefault(); // Add an overflow on the <details> to avoid content overflowing this.el.style.overflow = 'hidden'; // Check if the element is being closed or is already closed if (this.isClosing || !this.el.open) { this.open(); // Check if the element is being openned or is already open } else if (this.isExpanding || this.el.open) { this.shrink(); } } shrink()

This shrink function is using the WAAPI .animate() function. You can read more about it in the MDN docs. WAAPI is very similar to CSS @keyframes. We need to define the start and end keyframes of the animation. In this case, we only need two keyframes, the first one being the current height the element, and the second one is the height of the <details> element once it is closed. The current height is stored in the startHeight variable. The closed height is stored in the endHeight variable and is equal to the height of the <summary>.

shrink() { // Set the element as "being closed" this.isClosing = true; // Store the current height of the element const startHeight = `${this.el.offsetHeight}px`; // Calculate the height of the summary const endHeight = `${this.summary.offsetHeight}px`; // If there is already an animation running if (this.animation) { // Cancel the current animation this.animation.cancel(); } // Start a WAAPI animation this.animation = this.el.animate({ // Set the keyframes from the startHeight to endHeight height: [startHeight, endHeight] }, { // If the duration is too slow or fast, you can change it here duration: 400, // You can also change the ease of the animation easing: 'ease-out' }); // When the animation is complete, call onAnimationFinish() this.animation.onfinish = () => this.onAnimationFinish(false); // If the animation is cancelled, isClosing variable is set to false this.animation.oncancel = () => this.isClosing = false; } open()

The open function is called when we want to expand the accordion. This function does not control the animation of the accordion yet. First, we calculate the height of the <details> element and we apply this height with inline styles on it. Once it’s done, we can set the open attribute on it to make the content visible but hiding as we have an overflow: hidden and a fixed height on the element. We then wait for the next frame to call the expand function and animate the element.

open() { // Apply a fixed height on the element this.el.style.height = `${this.el.offsetHeight}px`; // Force the [open] attribute on the details element this.el.open = true; // Wait for the next frame to call the expand function window.requestAnimationFrame(() => this.expand()); } expand()

The expand function is similar to the shrink function, but instead of animating from the current height to the close height, we animate from the element’s height to the end height. That end height is equal to the height of the summary plus the height of the inner content.

expand() { // Set the element as "being expanding" this.isExpanding = true; // Get the current fixed height of the element const startHeight = `${this.el.offsetHeight}px`; // Calculate the open height of the element (summary height + content height) const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`; // If there is already an animation running if (this.animation) { // Cancel the current animation this.animation.cancel(); } // Start a WAAPI animation this.animation = this.el.animate({ // Set the keyframes from the startHeight to endHeight height: [startHeight, endHeight] }, { // If the duration is too slow of fast, you can change it here duration: 400, // You can also change the ease of the animation easing: 'ease-out' }); // When the animation is complete, call onAnimationFinish() this.animation.onfinish = () => this.onAnimationFinish(true); // If the animation is cancelled, isExpanding variable is set to false this.animation.oncancel = () => this.isExpanding = false; } onAnimationFinish()

This function is called at the end of both the shrinking or expanding animation. As you can see, there is a parameter, [open], that is set to true when the accordion is open, allowing us to set the [open] HTML attribute on the element, as it is no longer handled by the browser.

onAnimationFinish(open) { // Set the open attribute based on the parameter this.el.open = open; // Clear the stored animation this.animation = null; // Reset isClosing & isExpanding this.isClosing = false; this.isExpanding = false; // Remove the overflow hidden and the fixed height this.el.style.height = this.el.style.overflow = ''; } Setup the accordions

Phew, we are done with the biggest part of the code!

All that’s left is to use our Accordion class for every <details> element in the HTML. To do so, we are using a querySelectorAll on the <details> tag, and we create a new Accordion instance for each one.

document.querySelectorAll('details').forEach((el) => { new Accordion(el); }); Notes

To make the calculations of the closed height and open height, we need to make sure that the <summary> and the content always have the same height.

For example, do not try to add a padding on the summary when it’s open because it could lead to jumps during the animation. Same goes for the inner content — it should have a fixed height and we should avoid having content that could change height during the opening animation.

Also, do not add a margin between the summary and the content as it will not be calculated for the heights keyframes. Instead, use a padding directly on the content to add some spacing.

The end

And voilà, we have a nice animated accordion in JavaScript without any library! &#x1f308;

CodePen Embed Fallback

The post How to Animate the Details Element Using WAAPI appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

More People Dipping Toes Into Web Monetization

Css Tricks - Thu, 11/05/2020 - 5:00am

Léonie Watson:

I do think that Coil and Web Monetization are at the vanguard of a quiet revolution.

Here’s me when I’m visiting Léonie’s site:

Enjoy the pennies!

My Coil subscription ($5/month) doles out money to sites I visit that have monetization set up and installed.

Other Coil subscribers deposit small bits of money directly into my online wallet (I’m using Uphold). I set this up over a year ago and found it all quick and easy to get started. But to be fair, I wasn’t trying to understand every detail of it and I’m still not betting anything major on it. PPK went as far to say it was user-hostile and I’ll admit he has some good points…

Signing up for payment services is a complete hassle, because you don’t know what you’re doing while being granted the illusion of free choice by picking one of two or three different systems — that you don’t understand and that aren’t explained. Why would I pick EasyMoneyGetter over CoinWare when both of them are black boxes I never heard of?

Also, these services use insane units. Brave use BATs, though to their credit I saw a translation to US$ — but not to any other currency, even though they could have figured out from my IP address that I come from Europe. Coil once informed me I had earned 0.42 XBP without further comment. W? T? F?

Bigger and bigger sites are starting to use it. TechDirt, is one example. I’ve got it on CodePen as well.

If this was just a “sprinkle some pennies at sites” play, it would be doomed.

I’m pessimistic at that approach. Micropayments have been done over and over and it hasn’t worked and I just don’t see it ever having enough legs to do anything meaningful to the industry.

At a quick glance, that’s what this looks like, and that’s how it is behaving right now, and that deserves a little skepticism.

There are two things that make this different
  1. This has a chance of being a web standard, not something that has to be installed to work.
  2. There are APIs to actually do things based on people transferring money to a site.

Neither of these things are realized, but if both of them happen, then meaningful change is much more likely to happen.

With the APIs, a site could say, “You’ll see no ads on this site if you pay us $1/month,” and then write code to make that happen all anonymously. That’s so cool. Removing ads is the most basic and obvious use case, and I hope some people give that a healthy try. I don’t do that on this site, because I think the tech isn’t quite there yet. I’d want to clearly be able to control the dollar-level of when you get that perk (you can’t control how much you give sites on Coil right now), but more importantly, in order to really make good on the promise of not delivering ads, you need to know very quickly if any given user is supporting you at the required level or not. For example, you can’t wait 2600 milliseconds to decide whether ads need to be requested. Well, you can, but you’ll hurt your ad revenue. And you can’t simply request the ads and hide them when you find out, lest you are not really making good on a promise, as trackers’n’stuff will have already done their thing.

Coil said the right move here is the “100+20” Rule, which I think is smart. It says to give everyone the full value of your site, but then give people extra if they hit monetization thresholds. For example, on this site, if you’re a supporter (not a Coil thing, this is old-school eCommerce), you can download the screencast originals (nobody else can). That’s the kind of thing I’d be happy to unlock via Web Monetization if it became easy to write the code to do that.

Maybe the web really will get monetized at some point and thus fix the original sin of the internet. I’m not really up on where things are in the process, but there is a whole site for it.

I’m not really helping, yet

While I have Coil installed and I’m a fan of all this, what will actually make a difference is having sites that actually do things for users that pay them. Like my video download example above. Maybe recipe sites offer some neat little printable PDF shopping list for people that pay them via Web Monetization. I dunno! Stuff like that! I’m not doing anything cool like that yet, myself.

If this thing gets legs, we’ll see all sorts of creative stuff, and the standard will make it so there is no one service that lords over this. It will be standardized APIs, so there could be a whole ecosystem of online wallets that accept money, services that help dole money out, fancy in-browser features, and site owners doing creative things.

The post More People Dipping Toes Into Web Monetization appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Write Loops with Preprocessors

Css Tricks - Wed, 11/04/2020 - 2:21pm

Loops are one of those features that you don’t need every day. But when you do, it’s awfully nice that preprocessors can do it because native HTML and CSS cannot.

Sass (SCSS) for Loop CodePen Embed Fallback while Loop CodePen Embed Fallback each Loop CodePen Embed Fallback Less for Loop CodePen Embed Fallback while Loop

(That’s what the above is. The when clause could be thought of exactly as while.)

each Loop CodePen Embed Fallback Stylus for Loop CodePen Embed Fallback while Loop

Only for loops in Stylus.

each Loop

The for loop actually behaves more like an each loop, so here’s a more obvious each loop example:

CodePen Embed Fallback Pug for Loop CodePen Embed Fallback while Loop CodePen Embed Fallback each Loop CodePen Embed Fallback Haml for Loop CodePen Embed Fallback while Loop CodePen Embed Fallback each Loop CodePen Embed Fallback Slim for Loop CodePen Embed Fallback while Loop CodePen Embed Fallback each Loop CodePen Embed Fallback

The post How to Write Loops with Preprocessors appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

This page is a truly naked, brutalist html quine.

Css Tricks - Wed, 11/04/2020 - 11:46am

Here’s a fun page coming from secretGeek.net. You don’t normally think “fun” with brutalist minimalism but the CSS trickery that makes it work on this page is certainly that.

The HTML is literally displayed on the page as tags. So, in a sense, the HTML is both the page markup and the content. The design is so minimal (or “naked”) that it’s code leaks through! Very cool.

The page explains the trick, but I’ll paraphrase it here:

  • Everything is a block-level element via * { display:block; }
  • …except for anchors, code, emphasis and strong, which remain inline with a,code,em,strong {display:inline}
  • Use ::before and ::after to display the HTML tags as content (e.g. p::before { content: '<p>'})

The page ends with a nice snippet culled from Josh Li’s “58 bytes of css to look great nearly everywhere”:

html { max-width: 70ch; padding: 2ch; margin: auto; color: #333; font-size: 1.2em; }

Direct Link to ArticlePermalink

The post This page is a truly naked, brutalist html quine. appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Getting the WordPress Block Editor to Look Like the Front End Design

Css Tricks - Wed, 11/04/2020 - 5:19am

I’m a WordPress user and, if you’re anything like me, you always have two tabs open when you edit a post: one with the new fancy pants block editor, aka Gutenberg, and another with a preview of the post so you know it won’t look wonky on the front end.

It’s no surprise that a WordPress theme’s styles only affect the front end of your website. The back end posy editor generally looks nothing like the front end result. We’re used to it. But what if I said it’s totally possible for the WordPress editor nearly mirror the front end appearance?

All it takes is a custom stylesheet.

Mind. Blown. Right? Well, maybe it’s not that mind blowing, but it may save you some time if nothing else. &#x1f642;

WordPress gives us a hint of what’s possible here. Fire up the default Twenty Twenty theme that’s packaged with WordPress, fire up the editor, and it sports some light styling.

This whole thing consists of two pretty basic changes:

  1. A few lines of PHP in your theme’s functions.php file that tell the editor you wish to load a custom stylesheet for editor styles
  2. Said custom stylesheet

Right then, enough pre-waffle! Let’s get on with making the WordPress editor look like the front end, shall we?

Step 1: Crack open the functions.php file

OK I was lying, just a little more waffling. If you’re using a WordPress theme that you don’t develop yourself, it’s probably best that you setup a child theme before making any changes to your main theme. </pre-waffle>

Fire up your favorite text editor and open up the theme’s functions.php file that’s usually located in the root of the theme folder. Let’s drop in the following lines at the end of the file:

// Gutenberg custom stylesheet add_theme_support('editor-styles'); add_editor_style( 'editor-style.css' ); // make sure path reflects where the file is located

What this little snippet of code does is tell WordPress to add support for a custom stylesheet to be used with Gutenberg, then points to where that stylesheet (that we’re calling editor-style.css) is located. WordPress has solid documentation for the add_theme_support function if you want to dig into it a little more.

Step 2: CSS tricks (see what I did there?!)

Now we’re getting right into our wheelhouse: writing CSS!

We’ve added editor-styles support to our theme, so the next thing to do is to add the CSS goodness to the stylesheet we defined in functions.php so our styles correctly load up in Gutenberg.

There are thousands of WordPress themes out there, so I couldn’t possibly write a stylesheet that makes the editor exactly like each one. Instead, I will show you an example based off of the theme I use on my website. This should give you an idea of how to build the stylesheet for your site. I’ll also include a template at the end, which should get you started.

OK let’s create a new file called editor-style.css and place it in the root directory of the theme (or again, the child theme if you’re customizing a third-party theme).

Writing CSS for the block editor isn’t quite as simple as using standard CSS elements. For example, if we were to use the following in our editor stylesheet it wouldn’t apply the text size to <h2> elements in the post.

h2 { font-size: 1.75em; }

Instead of elements, our stylesheet needs to target Block Editor blocks. This way, we know the formatting should be as accurate as possible. That means <h2> elements needs to be scoped to the .rich-text.block-editor-rich-text__editable class to style things up.

It just takes a little peek at DevTools to find a class we can latch onto. h2.rich-text.block-editor-rich-text__editable { font-size: 1.75em; }

I just so happened to make a baseline CSS file that styles common block editor elements following this pattern. Feel free to snag it over at GitHub and swap out the styles so they complement your theme.

I could go on building the stylesheet here, but I think the template gives you an idea of what you need to populate within your own stylesheet. A good starting point is to go through the stylesheet for your front-end and copy the elements from there, but you will likely need to change some of the element classes so that they apply to the Block Editor window.

If in doubt, play around with elements in your browser’s DevTools to work out what classes apply to which elements. The template linked above should capture most of the elements though.

The results

First of all, let’s take a look at what the WordPress editor looks like without a custom stylesheet:

The block editor sports a clean, stark UI in its default appearance. It’s pulling in Noto Serif from Google Fonts but everything else is pretty bare bones.

Let’s compare that to the front end of my test site:

Things are pretty different, right? Here we still have a simple design, but I’m using gradients all over, to the max! There’s also a custom font, button styling, and a blockquote. Even the containers aren’t exactly square edges.

Love it or hate it, I think you will agree this is a big departure from the default Gutenberg editor UI. See why I have to have a separate tab open to preview my posts?

Now let’s load up our custom styles and check things out:

Well would you look at that! The editor UI now looks pretty much exactly the same as the front end of my website. The content width, fonts, colors and various elements are all the same as the front end. I even have the fancy background against the post title!

Ipso facto — no more previews in another tab. Cool, huh?

Making the WordPress editor look like your front end is a nice convenience. When I’m editing a post, flipping between tabs to see what the posts looks like on the front end ruins my mojo, so I prefer not to do it.

These couple of quick steps should be able to do the same for you, too!

The post Getting the WordPress Block Editor to Look Like the Front End Design appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Additive Animations in CSS

Css Tricks - Tue, 11/03/2020 - 12:59pm

Daniel C. Wilson explains how with CSS @keyframe animations, when multiple of them are applied to an element, they do both work. But if any properties are repeated, only the last one works. They override each other. I’ve seen this limitation overcome by applying keyframes to nested elements so you don’t have to do deal with that fighting.

But the Web Animation API (WAAPI) in JavaScript has a way to do additive animations. It’s a matter of adding composite: "add" to the options. For example:

The same goes for moving an item 20px + 30px with margin left (not the most performant way to move an object, but it demonstrates length usage)… if the animations both run at the same time, with the same duration and in the same direction, the end result will be a movement of 50px.

Cool. That’s nice for JavaScript animations, but what about CSS? Are we ever going to get it? Maybe. Even now, you can apply additive animations to your existing CSS animations in just a line of JavaScript:

el.getAnimations().forEach(animation => { animation.effect.composite = 'add'; });

Kind of reminds me of indeterminate checkboxes. They exist, but there is no way to express them in HTML or CSS — you have to put them in that state via JavaScript.

Direct Link to ArticlePermalink

The post Additive Animations in CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Websites We Like: Whimsical

Css Tricks - Tue, 11/03/2020 - 11:22am

Whimsical is an app that lets you create flowcharts, wireframes, and mind maps but it was only earlier today that I spotted just how great the website is — especially the product pages. Check out this page where they describe how to use the Mind Maps feature where you can use the product right there on the marketing site.

Neat, huh? This is all done through the power of the <canvas> element. You could make something like this with SVG for sure but there’s always a blurry line between picking SVG and canvas.

However, in terms of design, I love this idea of the advertisement being the product. And I also love cutting out all the usual sign-up nonsense to show folks the value of the app. Most products make you sign up and go through onboarding before you can see the value of the product. But that’s just not the case here; the ad is the product!

Also, I just love the design of this thing. Each product feature has its own theme, which makes the product demos pop a bit more as you look around. It’s a small detail but makes me want to explore the rest of the site to see what other fancy UI trinkets are lying around.

I also like also being able to jump straight into a working example of a wireframe. There’s no marketing spiel about how revolutionary the app is or how it’ll change the art of mind maps forever. Everything gets out of the way to show you the product, first and foremost.

But! Going back to the navigation for a sec: choosing not to label those icons is an interesting decision. It’s lovely, but what does each icon mean? This is covered in a post Chris wrote a while back when he asked: Are icons content? That said, the argument about whether or not to label icons has been going on for decades in software design. Jef Raskin, one of the designers of the original Macintosh back in the 1980s, wrote a great book called The Humane Interface where he argues that we should never leave icons unlabelled. Perhaps that’s a bit much, but in this case, I don’t think it would hurt to label these icons since they’re product-specific and mind map icons aren’t something we see every day.

Whimsical’s typography is interesting, too! they’re using DIN Next which feels a little at odds with the visual design, at least to me. DIN Next is the kind of typeface that gets lost in the background, designed to stand back and display fonts take center stage:

But I think the font’s success is carried by the buck wild visual design — the squiggly lines, the floating circles and moon shapes that are found everywhere in the UI. Then again, perhaps you don’t want the typeface to stick out when your UI is so visually loud, and I mean that in a good way.

The trick to designing an interface like this is making sure color accessibility is taken into consideration though. Stacie Arellano wrote about why color contrast is so important a while back:

You can mathematically know if two colors have enough contrast between them. 

The W3C has a document called Web Content Accessibility Guidelines (WCAG) 2.1 that covers successful contrast guidelines. Before we get to the math, we need to know what contrast ratio scores we are aiming to meet or exceed. To get a passing grade (AA), the contrast ratio is 4.5:1 for most body text and 3:1 for larger text.

I’m not going to double check the numbers here for Whimsical, but it’s worth keeping an eye on… especially when a UI has a lot of white text on bright and colorful backgrounds. I’ve managed to mess this up more than a few times and it’s an easy thing to trip up on. But if folks can’t read the text in your UI, that’s a big problem.

Anyway, this site for the Whimsical product is a breath of fresh air. It’s visually striking and shows that communicating a product’s value and features can be done with show-and-tell instead of tell-and-tell.

Which leads me to ask you a question: Is there a website you’ve recently visited that caught your eye?

The post Websites We Like: Whimsical appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Thidrekssaga III: Witig

QuirksBlog - Tue, 11/03/2020 - 2:55am

You’re in for a treat today. Just now I published part III of the Thidrekssaga: Witig.

It is the second best story in the entire saga, and I give a complete version with only minimal notes. We hear how Witig Wieland's son and bearer of Mimung comes to Bern to fight with Dietrich, how he encounters Hildebrand and Heime along the way, and how Hildebrand becomes worried for Dietrich, mostly because he knows Mimung is better than Dietrich's equipment. We also hear how he solves this problem and teaches Dietrich a lesson in the process.


Gray Burst

Css Tricks - Mon, 11/02/2020 - 2:26pm

I made this neat little gray burst thing. It’s nothing particularly special, especially compared to the amazing creativity on CodePen, but I figured I could document some of the things happening in it for learning reasons.

CodePen Embed Fallback It’s SVG

SVG has <line x1 y1 x2 y2>, so I figured it would be easy to use for this burst look. The x1 y1 is always the middle, and the x2 y2 are randomly generated. The mental math for placing lines is pretty easy since it’s using viewBox="0 0 100 100". You might even prefer -50 -50 100 100 so that the coordinate 0 0 is in the middle.

Random numbers const getRandomInt = (min, max) => { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; };

It’s nice to have a function like that available for generate art. I use it not just for the line positioning but also the stroke width and opacity on the grays.

I’ve used that function so many times it makes me think native JavaScript should have a helper math function that is that clear.

Generating HTML with template literals is so easy

This is very readable to me:

let newLines; for (let i = 0; i < NUM_LINES; i++) { newLines += ` <line x1="50" y1="50" x2="${getRandomInt(10, 90)}" y2="${getRandomInt(10, 90)}" stroke="rgba(0, 0, 0, 0.${getRandomInt(0, 25)})" stroke-linecap="round" stroke-width="${getRandomInt(1, 2)}" />`; } svg.insertAdjacentHTML("afterbegin", newLines); Interactivity in the form of click-to-regenerate

If there is a single function to kick off drawing the artwork, click-to-regenerate is as easy as:

doArt(); window.addEventListener("click", doArt); Rounding

I find it far more pleasing with stroke-linecap="round". It’s nice we can do that with stroke endings in SVG.

The coordinates of the lines don’t move — it’s just a CSS transform

I just popped this on the lines:

line { transform-origin: center; animation: do 4s infinite alternate; } line:nth-child(6n) { animation-delay: -1s; } line:nth-child(6n + 1) { animation-delay: -2s; } line:nth-child(6n + 2) { animation-delay: -3s; } line:nth-child(6n + 3) { animation-delay: -4s; } line:nth-child(6n + 4) { animation-delay: -5s; } @keyframes do { 100% { transform: scale(0.69); } }

It might look like the lines are only getting longers/shorter, but really it’s the whole line that is shrinking with scale(). You just barely notice the thinning of the lines since they are so much longer than wide.

Notice the negative animation delays. That’s to stagger out the animations so they feel a bit random, but still have them all start at the same time.

What else could be done?
  • Colorization could be cool. Even pleasing, perhaps?
  • I like the idea of grouping aesthetics. As in, if you make all the strokes randomized between 1-10, it feels almost too random, but if it randomized between groups of 1-2, 2-4, or 8-10, the aesthetics feel more considered. Likewise with colorization — entirely random colors are too random. It would be more interesting to see randomization within stricter parameters.
  • More movement. Rotation? Movement around the page? More bursts?
  • Most of all, being able to play with more parameters right on the demo itself is always fun. dat.GUI is always cool for that.

The post Gray Burst appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Automate Project Versioning and Releases with Continuous Deployment

Css Tricks - Mon, 11/02/2020 - 6:02am

Having a semantically versioned software will help you easily maintain and communicate changes in your software. Doing this is not easy. Even after manually merging the PR, tagging the commit, and pushing the release, you still have to write release notes. There are a lot of different steps, and many are repetitive and take time.

Let’s look at how we can make a more efficient flow and completely automating our release process by plugin semantic versioning into a continuous deployment process.

Semantic versioning

A semantic version is a number that consists of three numbers separated by a period. For example, 1.4.10 is a semantic version. Each of the numbers has a specific meaning.

CodePen Embed Fallback Major change

The first number is a Major change, meaning it has a breaking change.

Minor change

The second number is a Minor change, meaning it adds functionality.

Patch change

The third number is a Patch change, meaning it includes a bug fix.

It is easier to look at semantic versioning as Breaking . Feature . Fix. It is a more precise way of describing a version number that doesn’t leave any room for interpretation.

Commit format

To make sure that we are releasing the correct version — by correctly incrementing the semantic version number — we need to standardize our commit messages. By having a standardized format for commit messages, we can know when to increment which number and easily generate a release note. We are going to be using the Angular commit message convention, although we can change this later if you prefer something else.

It goes like this:

<header> <optional body> <optional footer>

Each commit message consists of a header, a body, and a footer.

The commit header

The header is mandatory. It has a special format that includes a type, an optional scope, and a subject.

The header’s type is a mandatory field that tells what impact the commit contents have on the next version. It has to be one of the following types:

  • feat: New feature
  • fix: Bug fix
  • docs: Change to the documentation
  • style: Changes that do not affect the meaning of the code (e.g. white-space, formatting, missing semi-colons, etc.)
  • refactor: Changes that neither fix a bug nor add a feature
  • perf: Change that improves performance
  • test: Add missing tests or corrections to existing ones
  • chore: Changes to the build process or auxiliary tools and libraries, such as generating documentation

The scope is a grouping property that specifies what subsystem the commit is related to, like an API, or the dashboard of an app, or user accounts, etc. If the commit modifies more than one subsystem, then we can use an asterisk (*) instead.

The header subject should hold a short description of what has been done. There are a few rules when writing one:

  • Use the imperative, present tense (e.g. “change” instead of “changed” or “changes”).
  • Lowercase the first letter on the first word.
  • Leave out a period (.) at the end.
  • Avoid writing subjects longer than 80 charactersThe commit body.

Just like the header subject, use the imperative, present tense for the body. It should include the motivation for the change and contrast this with previous behavior.

The commit footer

The footer should contain any information about breaking changes and is also the place to reference issues that this commit closes.

Breaking change information should start with BREAKING CHANGE: followed by a space or two new lines. The rest of the commit message goes here.

Enforcing a commit format

Working on a team is always a challenge when you have to standardize anything that everyone has to conform to. To make sure that everybody uses the same commit standard, we are going to use Commitizen.

Commitizen is a command-line tool that makes it easier to use a consistent commit format. Making a repo Commitizen-friendly means that anyone on the team can run git cz and get a detailed prompt for filling out a commit message.

Generating a release

Now that we know our commits follow a consistent standard, we can work on generating a release and release notes. For this, we will use a package called semantic-release. It is a well-maintained package with great support for multiple continuous integration (CI) platforms.

semantic-release is the key to our journey, as it will perform all the necessary steps to a release, including:

  1. Figuring out the last version you published
  2. Determining the type of release based on commits added since the last release
  3. Generating release notes for commits added since the last release
  4. Updating a package.json file and creating a Git tag that corresponds to the new release version
  5. Pushing the new release

Any CI will do. For this article we are using GitHub Action, because I love using a platform’s existing features before reaching for a third-party solution.

There are multiple ways to install semantic-release but we’ll use semantic-release-cli as it provides takes things step-by-step. Let’s run npx semantic-release-cli setup in the terminal, then fill out the interactive wizard.

Th script will do a couple of things:

  • It runs npm adduser with the NPM information provided to generate a .npmrc.
  • It creates a GitHub personal token.
  • It updates package.json.

After the CLI finishes, it wil add semantic-release to the package.json but it won’t actually install it. Run npm install to install it as well as other project dependencies.

The only thing left for us is to configure the CI via GitHub Actions. We need to manually add a workflow that will run semantic-release. Let’s create a release workflow in .github/workflows/release.yml.

name: Release on: push: branches: - main jobs: release: name: Release runs-on: ubuntu-18.04 steps: - name: Checkout uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 12 - name: Install dependencies run: npm ci - name: Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # If you need an NPM release, you can add the NPM_TOKEN # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: npm run release

Steffen Brewersdorff already does an excellent job covering CI with GitHub Actions, but let’s just briefly go over what’s happening here.

This will wait for the push on the main branch to happen, only then run the pipeline. Feel free to change this to work on one, two, or all branches.

on: push: branches: - main

Then, it pulls the repo with checkout and installs Node so that npm is available to install the project dependencies. A test step could go, if that’s something you prefer.

- name: Checkout uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 12 - name: Install dependencies run: npm ci # You can add a test step here # - name: Run Tests # run: npm test

Finally, let semantic-release do all the magic:

- name: Release run: npm run release

Push the changes and look at the actions:

Now each time a commit is made (or merged) to a specified branch, the action will run and make a release, complete with release notes.

Release party!

We have successfully created a CI/CD semantic release workflow! Not that painful, right? The setup is relatively simple and there are no downsides to having a semantic release workflow. It only makes tracking changes a lot easier.

semantic-release has a lot of plugins that can make an even more advanced automations. For example, there’s even a Slack release bot that can post to a project channel once the project has been successfully deployed. No need to head over to GitHub to find updates!

The post How to Automate Project Versioning and Releases with Continuous Deployment appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

compute cuter

Css Tricks - Fri, 10/30/2020 - 12:13pm

Get that desk more cuter, fam. Amy (@sailorhg) has this perfectly cute minisite with assorted desktop backgrounds, fonts, editor themes, keyboard stuff, and other accessories. These rainbow cables are great.

And speaking of fonts, we’re still plucking away at this microsite for coding fonts and it’s ripe for contribution if anyone is into it.

Direct Link to ArticlePermalink

The post compute cuter appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Little Things on My Personal Site

Css Tricks - Fri, 10/30/2020 - 9:39am

I updated my personal website the other day. Always a fun project since it’s one of the few where it’s 100% just me. It’s my own personal playground with no other goal than making the site represent me to have a little fun. It’s not a complete re-write, just some new paint.

I thought I’d document little bits of it here just to hone in on some of the bits of trickery in the spirit of learning through sharing.

Hoefler Fonts

I think the Inkwell family is super cool. I like mix and matching not just the weights but the serif and sans-serif and caps vs not.

From the Inkwell introduction post.

I used Inkwell in the last design as well, but I was worried that it was a little too jokey for blog post body copy. My writing is extremely casual, but not always, and Inkwell is way too jovial for serious topics. I went with Ideal Sans for body copy last time, but the pairing with Inkwell felt a little off.

This time I went with Whitney for general body copy, which is still pretty lighthearted, but works when the copy is more straight toned.


If you’re going to zebra-stripe a table, you’d do something like…

tr:nth-child(even) { background-color: var(--color-1); } tr:nth-child(odd) { background-color: var(--color-2); }

What if you wanted to rotate four colors though? It’s still :nth-child trickery, selecting every four, and then offsetting. Here, I’ll do it with list items in Sass (the nesting is nice, not having to repeat the selector):

li { &:nth-child(4n) a { color: $blue; } &:nth-child(4n + 1) a { color: $yellow; } &:nth-child(4n + 2) a { color: $red; } &:nth-child(4n + 3) a { color: $purple; } }

That’s what I did to build the colorized blogroll:

Note the Sass used above… I used Sass because it was already in use on the project. All I had to do was open CodeKit and the processing was ready-to-go.

Oh, and blogrolls are cool again.

Chill YouTube

I used this click-to-load-YouTube-(at all) technique which is still extremely clever. Having an <iframe> that behaves just like a YouTube embed would but only loading a simple static image (rather than heaps and heaps of resources) is great for performance and behaves essentially the same as a normal YouTube embed does.

<iframe width="560" height="315" src="https://www.youtube.com/embed/Y8Wp3dafaMQ" srcdoc="<style>*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}</style><a href=https://www.youtube.com/embed/Y8Wp3dafaMQ?autoplay=1><img src=https://img.youtube.com/vi/Y8Wp3dafaMQ/hqdefault.jpg alt='Video The Dark Knight Rises: What Went Wrong? – Wisecrack Edition'><span>▶</span></a>" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="The Dark Knight Rises: What Went Wrong? – Wisecrack Edition" ></iframe> Custom Post Types everywhere

I’m a big fan of giving myself structured data to work with. In WordPress-land, that often means Custom Post Types paired with something like the Advanced Custom Fields plugin for just the right data needed for the job.

Then I can loop over stuff and output it however I want. This isn’t that fancy, but it opens up whatever future doors I want to a lot easier.

Build your own bio

There is nothing fancy about how this works:

I literally made 18 <div> elements (3 lengths * 2 styles * 3 code types = 18) and swap between with a bit of JavaScript that calculates a class string based on the current choices, selects that class, and unhides it while hiding the rest.

$(".bio-choices input").on("change", function () { var lengthClass = ".bio-" + $("input[name=length]:checked").attr("id"); var styleClass = ".bio-" + $("input[name=style]:checked").attr("id"); var codeClass = ".bio-" + $("input[name=code]:checked").attr("id"); var selector = lengthClass + styleClass + codeClass; $(".bio").hide(); $(selector).show(); });

jQuery! That’s what was already on the site, and the site also uses the jQuery version of FitVids for responsive videos — so I figured I’d just leave it all be.

If I was going to re-write these bits of the site, I’d probably rip out jQuery and use this for FitVids. Then I’d find a way to only have three bios (maybe six if I can’t find a nice way to handle first vs. third person with word swaps) and then get the rest by automatically converting the formats somehow (maybe some cloud function if I had to).


I used ztext for the header! It’s this kinda stuff that makes the web feel extra webby to me. I’m not sure I’d do something with quite so much movement on a site like CSS-Tricks (because people visit it more often and the time-on-site is higher). But for a site that people might land on once in a blue moon, it has the right amount of cheerful levity, I think.

Background SVG

I was stoked to see the SVG Backgrounds site get an upgrade lately. I was playing around in there and was like YES, I’m doing this.

I went with a background-attachment: fixed look, which I think I like. I also added the slideout footer effect on desktop, but I’m less sold that it’s working here. It’s more fun when the background changes, and that doesn’t happen here. I’ll probably either change the background of the footer, or rip the effect out.

Filter trick for links

Some of the different sections on the site use a different primary highlight color, and I’m having the links in those sections follow that color. That might be questionable (perhaps all links should be blue) but, so far, I think it makes decent sense (they still have hover and focus styles). When you have a variety of colors and styles for interactive elements though, it often means that you have to create special alternate styles for hover and focus. That could mean crafting bespoke color alterations for each color. Not the end of the world, but I really like this little trick for interactive styles that ends up with a consistent look across all colors:

a:focus, .button:focus, a:hover, .button:hover { filter: brightness(120%); }

Anyway! This was just a couple hours of paint on this site. Mostly because blogrolls were the CodePen Challenge that week. But I can never touch a site I haven’t in a while and just do one thing. I get sucked in and gotta do more!

The post Little Things on My Personal Site appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

In Defense of Tables and Floats in Modern Day Development

Css Tricks - Fri, 10/30/2020 - 4:44am

Twenty-plus years ago, tables were the main way web pages were created in HTML. It gave web builders consistent control of constructing pages with some “design.” No longer did sites only have to be top-to-bottom in a linear manner — they could be set up with columns that align left-to-right and top-to-bottom. Back then, it was seen as a huge breakthrough.

Tables, however, were never designed to lay out pages and, in fact, have all sorts of problems when used that way today. It was a convenient hack, but at the time, a very welcome one, particularly for those trying to achieve a super-specific layout that previous ways couldn’t handle.

Fast-forward to modern days and it’s now obvious that were tons of issues with the table layout approach. Accessibility is a big one.<table>, <th>, <tr> and <td> elements aren’t exactly accessible, especially when they’re nested several levels deep. Screen readers — the devices that read web content and serve as a measure of accessibility compliance — struggle to parse them into cohesive blocks of content. That’s not to say tables are bad; they simply were never intended as a layout mechanism.

Check out this table layout. Feel free to run it through VoiceOver or whatever screen reading software you have access to.

CodePen Embed Fallback

Yes, that example looks very much like a typical website layout, but it’s crafted solely with a table. You can see how quickly it becomes bloated and inaccessible the very moment we start using it for anything other than tabular data.

So after more than 20 years of being put through the ringer, you might think we should avoid tables altogether. If you’ve never shipped a table-based layout, you’ve undoubtedly heard war stories from those of us who have, and those stories are never kind. It’s like we’ve sort of made tables the “Internet Explorer of HTML elements.”

But that’s not totally fair because tables do indeed fill a purpose on the web and they are indeed accessible when they are used correctly.

Tables are designed to handle data that is semantically related and is best presented in a linear-like format. So, yes, we can use tables today in the year 2020, and that will likely continue to be true many years from now.

Here’s a table being used to display exactly what it’s intended to: tabular data!

CodePen Embed Fallback

With the push toward web standards in the early 2000s, tables were pushed aside as a layout solution in favor of other approaches, most notably the CSS float property. Designers and developers alike rejoiced because, for the first time, we had a true separation of concerns that let markup do the markup-y things it needs to do, and CSS to do the visual stuff it needs to do. That made code both cleaner and way easier to maintain and, as a result, we could actually focus on true standards, like accessibility, and even other practices, like SEO.

See (or rather hear) the difference in this example?

CodePen Embed Fallback

Many of us have worked with floats in the past. They were originally designed to allow content to flow around images that are floated either to the left or right, and still be in the document flow. Now that we’ve gotten newer layout features — again, like grid and flexbox — floats, too, have sort of fallen by the wayside, perhaps either because there are better ways to accomplish what they do, or because they also got the same bad rap as tables after being (ab)used for a long time.

But floats are still useful and relevant! In fact, we have to use them for the shape-outside property to work.

CodePen Embed Fallback

A legitimate float use case could be for wrapping content around a styled <blockquote>.

CodePen Embed Fallback

CSS features like grid, flexbox, and multicolumn layouts are among the wonderful tools we have to work with these days. With even more layout possibilities, cleaner and more accessible code, they will remain our go-to layout approaches for many years to come.

No hacks or extra code in this flexbox example of the same layout we’ve looked at throughout this article:

CodePen Embed Fallback

So, next time you find yourself considering tables or floats, reach for them with confidence! Well, when you know the situation aligns with their intended use. It’s not like I’m expecting you to walk away from this with a reinvigorated enthusiasm for tables and floats; only that, when used correctly, they are perfectly valid techniques, and even continue to be indispensable parts of our overall toolset.

The post In Defense of Tables and Floats in Modern Day Development appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Using Your Own Design System with KendoReact Components

Css Tricks - Thu, 10/29/2020 - 1:26pm

Maybe you’ve already heard of (or even worked with!) KendoReact. It’s popped up in some of my day-to-day conversations, especially those about working with design systems and React. You could think of it as a component library like Bootstrap or Material Design, except the components in KendoReact are far more robust. These are interactive, state-driven components ready to start building full-blown UI’s right out of the gate (not to mention, if you want to use Bootstrap as the theme, you absolutely can).

Whenever you’re thinking about using a UI library, you need to think about the styling capabilities. Are you able to really express your brand with these? Were they meant to be styled? What is the styling experience going to be like?

Fortunately, KendoReact really makes styling a citizen of the entire UI library.

KendoReact is a collection of UI components for building sites. It’s a pretty massive one. Over 80 by my count, and that doesn’t include the child components of heavy lifters like the <Grid /> family.

Here’s one, the <DropDownList />, and just using the default theme (even that is optional):

CodePen Embed Fallback

If I want to style this, I don’t need any special proprietary skills, I can just use CSS. Here’s me forcing a whole new look onto it with different colors and fonts, with just some simple CSS:

CodePen Embed Fallback

But hey, maybe you want to do something a bit more systematized than cowboying some random override CSS. I don’t blame you. Good news: KendoReact themes are Sass-powered. So you can control a lot of the colorization and styling just by changing a few Sass variables.

They have a whole theme builder you can use right on their site that spits out exactly what you need. Say you want to start from their base theme and go from there, select the Default theme:

Then you can play with all the colors in the UI to your liking. Here’s me poking at a theme with some CSS-Tricks colors.

I can download that from the site which will give me the variables as a SCSS file that I can apply before the default theme in my build (there is a great tutorial covering how to do that over on the Telerik blog). Plus, it gives me the whole dang CSS file of the theme if I want to use it that way, which is simple and quick. Here’s me using their conversational chat widget with that theme:

CodePen Embed Fallback

Again, I can start with Bootstrap, I can start with Material, I can start with their default theme, or I can start from scratch. Styling is totally up to me. Each theme has its perks and, as you might expect, are super flexible as far as configuring colors, fonts, and other design elements.

If you really get into this, of course you’ll be consulting their docs and finding your way around there (it’s nice to know they have really comprehensive docs). It’s all pretty straightforward though, you’ll do great! If you need to get going building out a state-driven interactive interface quickly without sacrificing any customizability or power, you’ll find KendoReact is your friend.

The post Using Your Own Design System with KendoReact Components appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

The CSS Custom Property Toggle Trick

Css Tricks - Thu, 10/29/2020 - 4:51am

Back in July 2020, I got an email from James0x57 (I always try to refer to people by their name, but I think I get the sense they prefer to go by screen name) that says:

The entire world of branching conditional logic and bulk feature toggling for custom CSS properties is possible and only exists because of a tiny footnote in the CSS spec that has gone unnoticed.

That line is:

Note: While <declaration-value> must represent at least one token, that one token may be whitespace.

In other words, --foo: ; is valid.

If you’re like me, this doesn’t read as some massive revelation that unlocks huge doors, but to smarter people, like James0x57, it does! We started working on a draft blog post, but for various reasons it didn’t make it all the way here. One of those reasons is that I just wasn’t getting it. Call me dense, sorry James0x57. One demo they sent me when I asked super dumbed-down example was helpful though, and I think it’s kind of clicked for me. Here’s my interpretation:

CodePen Embed Fallback

Let me attempt to explain:

  • The breakpoint we’ve set up here is a 900px max-width media query. You can see that’s where the variable --mq-sm flops from initial to an empty space value.
  • When the browser window is wider than 900px, that the value of --mq-sm is initial.
    • That makes the variable --padding-when-small contain two values — initial and 2rem —which, I guess is invalid.
    • So when we actually set the padding and call that variable like padding: var(--padding-when-small, var(--padding-when-large)), the second value (the “fallback”) is used because the first value is invalid.
  • When the browser window is narrower than 900px, the --mq-sm value is a space.
    • That makes the variable --padding-when-small value "(space)2rem" which, I guess is valid.
    • That means when we actually set the padding and call that variable like padding: var(--padding-when-small, var(--padding-when-large)), the first value is used.

So, now we can flip the padding between two values by changing a placeholder variable.

That clicks for me.

When see this as simply changing a single value, it’s almost like uh, ok, you’ve found a really complex way to change some padding, but you could have just changed the padding in the media query. But the trick is that now we have this placeholder variable that has changed and we can key into that to change unlimited other values.

We could have a single media query (or set of media queries) in our CSS that only toggles these placeholder variables and we use elsewhere to toggle values. That could be nice and clean compared to sprinkling media queries all over the CSS. It’s a proper toggle in CSS, like a form of IF/THEN logic that we haven’t quite had before.

James0x57 extended that thinking to all the logical possibilities, like AND, OR, XOR, NAND, NOR, and XNOR, but that lost me again. Not really a computer scientist over here. But you can follow their work if you want to see real world usage of this stuff.

This variable stuff is wild and gets very confusing. I noted in a possibly recent (but the byline says 2015?) article from Patrick Brosset that covers some tricky CSS custom properties stuff. For example, fallbacks can be infinitely nested, like:

color: var(--foo, var(--bar, var(--baz, var(--are, var(--you, var(--crazy)))));

Also, valid values for CSS custom properties can have commas in them like this:

content: var(--foo, one, two, three);

Is that really just one fallback with a single one, two, three value? This is rather mind-bending.

Anyway, fast-forward a bunch of months now, and CSS trickery master Lea Verou has set her sights on this whitespace-in-custom-properties stuff:

What if I told you you could use a single property value to turn multiple different values on and off across multiple different properties and even across multiple CSS rules?

It’s the same trick! In Lea’s example, though, she uses this ability to:

  • set variations on a button, and
  • set four different properties rather than one.

This really hones in on why this is the concept is so cool.

CodePen Embed Fallback

Lea points to some downsides:

There is no way to say “the background should be red if --foo is set and white otherwise”. Some such conditionals can be emulated with clever use of appending, but not most.

And of course there’s a certain readability issue: --foo: ; looks like a mistake and --foo: initial looks pretty weird, unless you’re aware of this technique.

We’re certainly entering the next era of how custom properties are used. First, we used them like preprocessor variables. Then we started seeing more cascade and fallback usage. Next, we used it alongside JavaScript more frequently. Now this.

There is even more writing about keeping CSS preprocessor variables around, not so much for the times when you only need what they can do, but for the things that only they can do, like having their color values manipulated.

The post The CSS Custom Property Toggle Trick appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Monetisation models and user hostility

QuirksBlog - Thu, 10/29/2020 - 3:00am

Recently Krijn pointed me to the Brave Rewards programme, and asked me what I thought of it. I immediately thought “Meh” but it took me a while to figure out why. Now I know.

If I understand correctly, the Brave system works as follows: you can give money to your favourite content creators (yay!), and can either donate that money yourself to Brave for redistribition (yay!) or earn it by watching ads (booh!). There is considerable choice involved in viewing ads (mkay...).


I tried signing up as a content creator, and now I’m in the phase where I have to pick a payment provider and do all kinds of complicated steps. I haven’t done so yet. The user-friendliness of these steps is appalling. I do not hold this against Brave, because other systems, notably Coil, have the same problem.

Signing up for payment services is a complete hassle, because you don’t know what you’re doing while being granted the illusion of free choice by picking one of two or three different systems — that you don’t understand and that aren’t explained. Why would I pick EasyMoneyGetter over CoinWare when both of them are black boxes I never heard of?

Also, these services use insane units. Brave use BATs, though to their credit I saw a translation to US$ — but not to any other currency, even though they could have figured out from my IP address that I come from Europe. Coil once informed me I had earned 0.42 XBP without further comment. W? T? F?

As long as signing up for an unclear, but probably tiny, reward in made-up units remains such a complete hassle few people will do it. We can’t roll out monetisation with such aggressively user-hostile sign-up and accounting processes in place. We are not cryptocurrency nerds. We just want to get paid.

Oh, and you should remember your password for the payment system in addition to the password for the redistribution system. And if you lose it, you should remember where your special code that I can’t remember the name of is stored — a code you get during sign-up without any indication that it is vitally important, and that is offhandedly and unclearly referred to in Forgot Password-mails. (True story, this.)

The redistribution system that first manages to hide all this junk from the user by reporting in real-world units and by just signing them up to a payment service automatically, without fake free choice — or, better still, by becoming a payment service — will have a significant competitive advantage because regular folk can actually use the system.


These problems are shared by Coil and Brave. The difference between their models boils down to ads. Coil has no ad component; you just pay Coil, and it redistributes your money over the sites you visit, weighted by time spent. Brave does something similar, but it also allows you to watch ads to earn more money to redistribute. This may sound great, but to me it doesn’t really.

Why involve ads at all?

Shouldn’t we teach people to pay for content they like? To see paying as a matter of honour, and of keeping the web clean and healthy?

I feel that involving ads shows that you’re unwilling to think outside the box. OK, it’s easy money, but in order to truly take back the web we have to break our dependence on easy ad money streams and travel the more complicated route of actually asking people to actually pay for what they consume — to tear down the free content entitlement that’s one of the least appealing aspects of the web development community.

YOU should pay. In, like, money — and not in “attention.”

But the Valley is unable to think outside the ad box. I don’t think we should look to it for a solution.

To me, the entire point of the coming wave of monetisation is to get rid of ads. Brave isn’t doing that — yet. That’s why I dislike its model and prefer Coil’s.

More on content-visibility

Css Tricks - Wed, 10/28/2020 - 12:32pm

Back in August 2020, when the content-visiblity property in CSS trickled its way into Chrome browsers, Una Kravets and Vladimir Levin wrote about it and we covered it. The weirdest part is that to get the performance value out of it, you pair it with contain-intrinsic-size on these big chunks of the page where you insert some arbitrary guess at a height. I wrote:

That part seems super weird to me. Just guess at a height? What if I’m wrong? Can I hurt performance? Can (or should) I change that value at different viewports if the height difference between small and large screens is drastic?

Jake Archibald and Das Surma just did a video on all this and it helped clarify that a bit. You can see at about 7:30 in just how confusing it is. Jake used this massive HTML spec page as a demo, and made <section> wrappers around big chunks of HTML, and applied:

section { content-visibility: auto; /* this is the thing that delays painting */ contain-intrinsic-size: 1px 5000px; /* this is the guess at the height of the content, and also saying width doesn't matter */ }

Apparently that 5000px isn’t the height of the element, it’s the size of the content of that element. I guess that matters because it will push that parent element taller by that number, unless the parent element overrides that with a height of its own. The magic comes from the fact that the browser will only paint¹ the first section (where it’s very likely the viewport isn’t over 5000px tall) and defer the painting on the rest. Sorta like lazy loading, but everything rather than media alone. It assumes the next section is 5000px tall, but once the top of it becomes visible, it will actually get painted and the correct height will be known. So assuming your page is just big ass blocks on top of each other, using an extremely large number should work fine there. Godspeed if your site is more complicated than that, I guess.

It’s a good video and you should watch it:

This is yet another thing where you have to inform the browser about your site so that it can Do Performance Good™. It is information that it can figure out by itself, but not until it has done things that have a performance cost. So you have to tell it up front, allowing it to avoid doing certain types of work. With responsive images, if we give images a srcset attribute with images and tell the browser in advance how big they are, including a sizes attribute with information about how our CSS behaves, it can do calculations ahead of time that only download the best possible image. Likewise, with the will-change property in CSS, we can tell the browser when we’re going to be doing movement ahead of time so it can pre-optimize for that in a way it couldn’t otherwise. It’s understandable, but a little tiresome. It’s like we need a stuff-you-need-to-know.manifest file to give browsers before it does anything else — only that would be an additional request!

The accessibility implications are important too. Steve Faulkner did a test applying content-visibility: auto to images and paragraphs:

The content is visually hidden, but in both JAWS and NVDA the hidden <img> is announced but the content of the <p> element is not. This has to do with how the img and the p element content are represented in the browser accessibility tree: The img is exposed in the accessibility tree with the alt text as the accessible name. The content of the p element is not present in the accessibility tree.

He notes that content hidden this way should not be available to screen readers, per the spec. I could see it going either way, like hide it all as if it was display: none, meaning none of it is in the accessibility tree. Or, leave it all in the accessibility tree. Right now it’s a tweener where you might see a bunch of stray images in the accessibility tree without any other context than their alt text. This is an interesting example of new tech going out with more rough edges than you might like to see.

Speaking of alt text, we all know those shouldn’t be empty when they represent important content that needs to be described to someone who can’t see them. They should be like paragraphs, says Dave:

I finally made the simplest of all connections: alt text is like a paragraph. Word pictures. Basic I know, but it helps me contextualize how to write good alt text as well as source order of my code.

I don’t want to be overly negative here! The performance gains for setting up a long-scrolling page with content-visibility is huge and that’s awesome. Being able to inform the browser about what is OK not to paint in two lines of code is pretty nice.

  1. I keep saying “paint” but I’m not sure if that’s really the right term or if it means something more specific. The spec says stuff like “allowing user agents to potentially omit large swathes of layout and rendering work until it becomes needed” (emphasis mine).

The post More on content-visibility appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Comparing Static Site Generator Build Times

Css Tricks - Wed, 10/28/2020 - 4:54am

There are so many static site generators (SSGs). It’s overwhelming trying to decide where to start. While an abundance of helpful articles may help wade through the (popular) options, they don’t magically make the decision easy.

I’ve been on a quest to help make that decision easier. A colleague of mine built a static site generator evaluation cheatsheet. It provides a really nice snapshot across numerous popular SSG choices. What’s missing is how they actually perform in action.

One feature every static site generator has in common is that it takes input data, runs it through a templating engine, and outputs HTML files. We typically refer to this process as The Build.

There’s too much nuance, context, and variability needed to compare how various SSGs perform during the build process to display on a spreadsheet — and thus begins our test to benchmark build times against popular static site generators.

This isn’t just to determine which SSG is fastest. Hugo already has that reputation. I mean, they say it on their website — The world’s fastest framework for building websites — so it must be true!

This is an in-depth comparison of build times across multiple popular SSGs and, more importantly, to analyze why those build times look the way they do. Blindly choosing the fastest or discrediting the slowest would be a mistake. Let’s find out why.

The tests

The testing process is designed to start simple — with just a few popular SSGs and a simple data format. A foundation on which to expand to more SSGs and more nuanced data. For today, the test includes six popular SSG choices:

Each test used the following approach and conditions:

  • The data source for each build are Markdown files with a randomly-generated title (as frontmatter) and body (containing three paragraphs of content).
  • The content contains no images.
  • Tests are run in series on a single machine, making the actual values less relevant than the relative comparison among the lot.
  • The output is plain text on an HTML page, run through the default starter, following each SSG’s respective guide on getting started.
  • Each test is a cold run. Caches are cleared and Markdown files are regenerated for every test.

These tests are considered benchmark tests. They are using basic Markdown files and outputting unstyled HTML into the built output.

In other words, the output is technically a website that could be deployed to production, though it’s not really a real-world scenario. Instead, this provides a baseline comparison among these frameworks. The choices you make as a developer using one of these frameworks will adjust the build times in various ways (usually by slowing it down).

For example, one way in which this doesn’t represent the real-world is that we’re testing cold builds. In the real-world, if you have 10,000 Markdown files as your data source and are using Gatsby, you’re going to make use of Gatsby’s cache, which will greatly reduce the build times (by as much as half).

The same can be said for incremental builds, which are related to warm versus cold runs in that they only build the file that changed. We’re not testing the incremental approach in these tests (at this time).

The two tiers of static site generators

Before we do that, let’s first consider that there are really two tiers of static site generators. Let’s call them basic and advanced.

  • Basic generators (which are not basic under the hood) are essentially a command-line interface (CLI) that takes in data and outputs HTML, and can often be extended to process assets (which we’re not doing here).
  • Advanced generators offer something in addition to outputting a static site, such as server-side rendering, serverless functions, and framework integration. They tend to be configured to be more dynamic right out of the box.

I intentionally chose three of each type of generator in this test. Falling into the basic bucket would be Eleventy, Hugo, and Jekyll. The other three are based on a front-end framework and ship with various amounts of tooling. Gatsby and Next are built on React, while Nuxt is built atop Vue.

Basic generatorsAdvanced generatorsEleventyGatsbyHugoNextJekyllNuxt My hypothesis

Let’s apply the scientific method to this approach because science is fun (and useful)!

My hypothesis is that if an SSG is advanced, then it will perform slower than a basic SSG. I believe the results will reflect that because advanced SSGs have more overhead than basic SSGs. Thus, it’s likely that we’re going to see both groups of generators — basic and advanced — bundled together, in the results with basic generators moving significantly quicker.

Let me expand on that hypothesis a bit.

Linear(ish) and fast

Hugo and Eleventy will fly with smaller datasets. They are (relatively) simple processes in Go and Node.js, respectively, and their build output will reflect that. While both SSG will slow down as the number of files grows, I expect them to remain at the top of the class, though Eleventy may be a little less linear at scale, simply because Go tends to be more performant than Node.

Slow, then fast, but still slow

The advanced, or framework-bound SSGs, will start out and appear slow. I suspect a single-file test to contain a significant difference — milliseconds for the basic ones, compared to several seconds for Gatsby, Next, and Nuxt.

The framework-based SSGs are each built using webpack, bringing a significant amount of overhead along with it, regardless of the amount of content they are processing. That’s the baggage we sign up for in using those tools (more on this later).

But, as we add thousands of files, I suspect we’ll see the gap between the buckets close, though the advanced SSG group will stay farther behind by some significant amount.

In the advanced SSG group, I expect Gatsby to be the fastest, only because it doesn’t have a server-side component to worry about — but that’s just a gut feeling. Next and Nuxt may have optimized this to the point where, if we’re not using that feature, it won’t affect build times. And I suspect Nuxt will beat out Next, only because there is a little less overhead with Vue, compared to React.

Jekyll: The odd child

Ruby is infamously slow. It’s gotten more performant over time, but I don’t expect it to scale with Node, and certainly not with Go. And yet, at the same time, it doesn’t have the baggage of a framework.

At first, I think we’ll see Jekyll as pretty speedy, perhaps even indistinguishable from Eleventy. But as we get to the thousands of files, the performance will take a hit. My gut feeling is that there may exist a point at which Jekyll becomes the slowest of all six. We’ll push up to the 100,000 mark to see for sure.

The results are in!

The code that powers these tests are on GitHub. There’s also a site that shows the relative results.

After many iterations of building out a foundation on which these tests could be run, I ended up with a series of 10 runs in three different datasets:

  • Base: A single file, to compare the base build times
  • Small sites: From 1 to 1024 files, doubling each to time (to make it easier to determine if the SSGs scaled linearly)
  • Large sites: From 1,000 to 64,000 files, double on each run. I originally wanted to go up to 128,000 files, but hit some bottlenecks with a few of the frameworks. 64,000 ended up being enough to produce an idea of how the players would scale with even larger sites.

Click or tap the images to view them larger.

Summarizing the results

A few results were surprising to me, while others were expected. Here are the high-level points:

  • As expected, Hugo was the fastest, regardless of size. What I didn’t expect is that it wasn’t even close to any other generator, even at base builds (nor was it linear, but more on that below.)
  • The basic and advanced groups of SSGs are quite obvious when looking at the results for small sites. That was expected, but it was surprising to see Next is faster than Jekyll at 32,000 files, and faster than both Eleventy and Jekyll at 64,000 files. Also surprising is that Jekyll performed faster than Eleventy at 64,000 files.
  • None of the SSGs scale linearly. Next was the closest. Hugo has the appearance of being linear, but only because it’s so much faster than the rest.
  • I figured Gatsby to be the fastest among the advanced frameworks, and suspected it would be the one to get closer to the basics. But Gatsby turned out to be the slowest, producing the most dramatic curve.
  • While it wasn’t specifically mentioned in the hypothesis, the scale of differences was larger than I would have imagined. At one file, Hugo was approximately 170 times faster than Gatsby. But at 64,000 files, it was closer — about 25 times faster. That means that, while Hugo remains the fastest, it actually has the most dramatic exponential growth shape among the lot. It just looks linear because of the scale of the chart.
What does it all mean?

When I shared my results with the creators and maintainers of these SSGs, I generally received the same message. To paraphrase:

The generators that take more time to build do so because they are doing more. They are bringing more to the table for developers to work with, whereas the faster sites (i.e. the “basic” tools) focus their efforts largely in converting templates into HTML files.

I agree.

To sum it up: Scaling Jamstack sites is hard.

The challenges that will present themselves to you, Developer, as you scale a site will vary depending on the site you’re trying to build. That data isn’t captured here because it can’t be — every project is unique in some way.

What it really comes down to is your level of tolerance for waiting in exchange for developer experience.

For example, if you’re going to build a large, image-heavy site with Gatsby, you’re going to pay for it with build times, but you’re also given an immense network of plugins and a foundation on which to build a solid, organized, component-based website. Do the same with Jekyll, and it’s going to take a lot more effort to stay organized and efficient throughout the process, though your builds may run faster.

At work, I typically build sites with Gatsby (or Next, depending on the level of dynamic interactivity required). We’ve worked with the Gatsby framework to build a core on which we can rapidly build highly-customized, image-rich websites, packed with an abundance of components. Our builds become slower as the sites scale, but that’s when we get creative by implementing micro front-ends, offloading image processing, implementing content previews, along with many other optimizations.

On the side, I tend to prefer working with Eleventy. It’s usually just me writing code, and my needs are much simpler. (I like to think of myself as a good client for myself.) I feel I have more control over the output files, which makes it easier for me to get &#x1f4af;s on client-side performance, and that’s important to me.

In the end, this isn’t only about what is fast or slow. It’s about what works best for you and how long you’re willing to wait.

Wrapping up

This is just the beginning! The goal of this effort was to create a foundation on which we can, together, benchmark relative build times across popular static site generators.

What ideas do you have? What holes can you poke in the process? What can we do to tighten up these tests? How can we make them more like real-world scenarios? Should we offload the processing to a dedicated machine?

These are the questions I’d love for you to help me answer. Let’s talk about it.

The post Comparing Static Site Generator Build Times appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Syndicate content
©2003 - Present Akamai Design & Development.