Thursday, 25 June 2020

Grid for layout, flexbox for components

When should we reach for CSS grid and when should we use flexbox? Rachel Andrew wrote about this very conundrum way back in 2016:

Flexbox is essentially for laying out items in a single dimension – in a row OR a column. Grid is for layout of items in two dimensions – rows AND columns.

Ahmad Shadeed wrote a post where he gives the same advice, but from a different angle. He argues we should use grid for layout and flexbox for components:

Remember that old layout method might be perfect for the job. Overusing flexbox or grid can increase the complexity of your CSS by time. I don’t mean they are complex, but using them correctly and in the right context as explained from the examples in this article is much better.

Speaking of which, there’s so many great layout examples in this post, too.

Direct Link to ArticlePermalink

The post Grid for layout, flexbox for components appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/37hiKDB
via IFTTT

The Mad Magazine Fold-In Effect in CSS

This was always my favorite thing in Mad magazine. One page (the inside of the back cover, I think) was covered in a zany illustration. You folded that page in thirds, covering up the middle-third of that image, and a new image would form because the illustration was designed to perfectly line up with those folds. The new image (and text!) was part of the joke.

Every one was a clever trick, so of course, I’m delighted to see that trick make it’s way to CSS, courtesy of Thomas Park.

I’m pretty surprised Thomas was able to do it with a single state (:hover / :active) . I would have bet a nickel that it would have needed @keyframes to adjust the 3D transforms into different positions during the animation, but it looks like multiple transitions happening (both parent and child) handle that.


If you’re in the mood for other cool CSS paper effects…

Here’s a new one from Lynn Fischer:

A classic from Mandy Michael:

And more folding from Mattia Astorino:

Direct Link to ArticlePermalink

The post The Mad Magazine Fold-In Effect in CSS appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/3dKZS26
via IFTTT

Some Typography Links

I just can’t stop opening excellent typography-related articles, which means I need to subject you to blog posts that round them up so I can clean up my open tabs.

Vistaserve is “a grass-roots web hosting initiative hailing from Thornbury, Australia. Inspired by the quirky web of the 90s, we allow users to create home pages, your own little sandbox on the World Wide Web, as it were.” Caitlin & Paul (I think the no-last-name thing is part of the aesthetic) wanted to get the fonts right, which meant removing anti-aliasing (the thing that makes fonts look good on screens!). CSS was no help. Turned out to be quite a journey involving literally rebuilding the fonts.


Thomas Bohm makes the point that the kerning around punctation may require special attention. For example, a question mark needing a little extra space or moving a superscript number away from butting against a letter.

You could do it manually with stuff like   or &hairsp in between characters. But I’m far too lazy for that unless I’m working on a very special piece. Personally, I just cross my fingers that the font I’m using is high quality enough to have thought of and implemented this sort of attention to detail.


I’m sure we’ve all seen, “The quick brown fox jumps over the lazy dog” as a tester string for type, because it uses all the characters in the alphabet. Jonathan Hoefler created some new proofing text that is much more helpful for typographers like him.

That’s deep in the type nerd weeds there. More useful perhaps is another recent post from Jonathan on pairings. I’ve probably read dozens of posts on font pairings in my life, but this one resonates the most.

Some of the most dazzling typographic pairings — and certainly my favorites — are those that use unexpected fonts together. At left, the grey flannel suit that is Tungsten Compressed is paired with crimson silk doublet of the St. Augustin Civilité, a fiery sixteenth century typeface that demands a good foil.


If you’ve got macOS Catalina, you’ve got access to some really nice fonts you might not know about that need to be manually downloaded. Ralf Herrmann has the story on what you get:

You can download the fonts right from Font Book

I get Erik Kennedy’s Learn UI Design newsletter, and he mentions using Calena in it…

Overall, Canela walks this balance between the warmth of human handwriting and stately details. It makes me think of something literary, which is why I used it for project in one of the new video lessons in Learn UI Design.


Mark Boulton has a cool new site: TypeSpecimens.

Type specimens are curious objects. They aim to inspire designers. They are tools with which to make design decisions. They are also marketing material for foundries. This project will dig into specimens from these three perspectives: as artefacts made by and for font designers to evolve type culture; as tools for font users to make decisions about choosing and using type; and as effective marketing tools.

The post Some Typography Links appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2A4hx6d
via IFTTT

The Analytics That Matter

I’ve long been skeptical of quoting global browser usage percentages to justify their usage of browser features. It doesn’t matter what global usage of a browser is, other than nerdy cocktail party fodder. The usage that matters is what users on your site are using, and that can be wildly different from site to site.

That idea of tracking real usage of your actual site concept has bounced around my head the last few days. And it’s not just “I can’t use CSS grid because IE 11 has 1.42% of global usage still” stuff, it’s about measuring metrics that matter to your site, no matter what they are.

Performance metrics are a big one. When you’re doing performance testing, much of it is what you would call synthetic testing. An automated browser loads your site and tracks what it finds as it loads, like the timing of a thing, the size of assets, the number of assets, etc. Synthetic information like this enters my mind when spending tons of time on performance. “I bet I can get rid of this one extra request,” I think. “I bet I can optimize this asset a little further.” And the performance tools we use report this kind of data to us readily. How big is our JavaScript bundle? What is our “Largest Contentful Paint”? What is our Lighthouse performance score? All things that are related to performance, but aren’t measuring actual user’s experience.

Let that sit for a second.

There are other analytics we can gather on a site, like usage analytics. For example, we might slap Google Analytics on a site, doing nothing but installing the generic snippet. This is going to tell us stuff like what pages are the most popular, how long people spend on the site, and what countries deliver the most traffic. Those are real user analytics, but it’s very generic analytic information.

If you’re hoping for more useful analytics data on your site, you have to think about it a little harder up front. What do you want to know? Maybe you want to know how often people use Feature X. Or you want to know how many files they have uploaded this week. Or how many messages they have sent. Or how many times they have clicked the star button. This is stuff that tells you how your site is doing. Generic analytics tracking won’t do that; you’ll have to write a little JavaScript to capture and report on those things. It takes a little effort to get the analytics you really care about.

Now apply that to performance tooling.

Rather than generic synthetic tests, why not measure things that are actually important to your specific site? One aspect to this is RUM, that is, “Real User Monitoring.” So rather than a single synthetic test being the source of all performance testing on your site, you’re tracking real users actually using the site on their actual devices. That makes a lot of sense to me, but aside from the logic of it, it unlocks some important data.

For example, one of Google’s Web Core Vitals, which are soon to affect the SEO of our pages, include a metric called First Input Delay (FID) and you have to collect data via JavaScript¹ on your page to use it.

Another Web Core Vital is “Largest Contentful Paint” which is a fascinating attempt at a more meaningful performance metric. Imagine a metric like “start render” or the first page paint. Is that interesting? Sorta. At least it is signaling to the user that something is happening (probably). Yet that first render might not be actually useful content, like the headline and body copy of a news article. So this metric makes a guess at what that useful content probably is and measures that. Very clever.

But, why guess? I get why Google has to guess. They have to measure LCP on a bazillion sites and provide generically useful measurements. But on your own site (again, where the focused analytics actually matter) we can tell performance tools which elements matter us and record when they render. Personally, I’d care about when the article itself renders on this site. With SpeedCurve’s hero rendering time, I could do something like:

<main elementtiming="article"></main>

<!-- or focus on the top of the page, like the "hero" timing suggests -->
<header elementtiming="hero"></header>

Now I’m measuring what matters to my site and not just generic numbers.

Similarly, FID is cool and all, but why not fire off a JavaScript event telling performance tooling when things happen that are important to your site. For example, on CodePen, we’d do that when the editor is ready to use. That’s called User Timing and it’s a dang W3C spec!

Editors.init();
performance.mark("Editors are initialized.");

These kind some-effort-required analytics are definitely better than the standard fare. Sure, a performance budget that warns you when you go over 200KB of JavaScript is great, but a performance budget that warns you when a core feature of your app isn’t ready until 1.4 seconds when your budget is 1.1 seconds is way more important.

  1. I say this because I was trying to make a chart on the SpeedCurve of the three Web Core Vitals, and you can’t add FID unless you have LUX running, which is their RUM thing. Phew that was a lot of acronyms, sorry.

The post The Analytics That Matter appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/3dwEvR9
via IFTTT

How to Disable Code: The Developer’s Production Kill Switch

The following is a guest post written by Carlos Schults.

Being able to disable code in production is a power that many developers aren’t aware of. And that’s a shame. The ability to switch off some portions—or even complete features—of the codebase can dramatically improve the software development process by allowing best practices that can shorten feedback cycles and increase the overall quality.

So, that’s what this post will cover: the mechanisms you can use to perform this switching off, why they’re useful and how to get started. Let’s dig in.

Why Would You Want to Disable Code?

Before we take a deep dive into feature flags, explaining what they are and how they’re implemented, you might be asking: Why would people want to switch off some parts of their codebase? What’s the benefit of doing that?

To answer these questions, we need to go back in time to take a look at how software was developed a couple of decades ago. Time for a history lesson!

The Dark Ages: Integration Hell

Historically, integration has been one of the toughest challenges for teams trying to develop software together. 

Picture several teams inside an organization, working separately for several months, each one developing its own feature. While the teams were working in complete isolation, their versions of the application were evolving in different directions. Now they need to converge again into a single, non conflicting version. This is a Herculean task. 

That’s what “integration hell” means: the struggle to merge versions of the same application that have been allowed to diverge for too long. 

Enter the Solution: Continuous Integration

“If it hurts, do it more often.” What this saying means is that there are problems we postpone solving because doing so is hard. What you often find with these kinds of problems is that solving them more frequently, before they accumulate, is way less painful—or even trivial.

So, how can you make integrations less painful? Integrate more often.

That’s continuous integration (CI) in a nutshell: Have your developers integrate their work with a public shared repository, at the very least once a day. Have a server trigger a build and run the automated test suite every time someone integrates their work. That way, if there are problems, they’re exposed sooner rather than later.

How to Handle Partially Completed Features

One challenge that many teams struggle with in CI is how to deal with features that aren’t complete. If developers are merging their code to the mainline, that means that any developments that take more than one day to complete will have to be split into several parts. 

How can you avoid the customer accessing unfinished functionality? There are some trivial scenarios with similarly trivial solutions, but harder scenarios call for a different approach: the ability to switch off a part of the code completely.

Feature Flags to the Rescue

Defining Feature Flags

There are many names for the mechanisms that allow developers to switch a portion of their code off and on. Some call them “feature toggles” or “kill switches.” But “feature flags” is the most popular name, so that’s what we’ll use for the remainder of this post. So, what are feature flags?

Put simply, feature flags are techniques that allow teams to change the behavior of an application without modifying the code. In general, flags are used to prevent users from accessing and using the changes introduced by some piece of code, because they’re not adequate for production yet for a number of reasons.

Disable Code: What Are the Use Cases?

We’ll now cover some of the most common use cases for disabling code in production.

Switching Off Unfinished Features

As you’ve seen, one of the main use cases for feature flags is preventing users from accessing features that aren’t ready for use yet.

That way, programmers developing features that are more complex and take a longer time to complete aren’t prevented from integrating their work often and benefiting from it.

Enabling A/B Testing

The adoption of feature flags enables the use of several valuable practices in the software development process, one of which is A/B testing

A/B testing is a user experience research technique that consists of comparing two versions of a website or application to decide which one to keep. It entails randomly splitting users into two groups, A and B, and then delivering a different version of the application to each group. One group might receive the current production version, which we call the “control,” whereas the second group would receive the candidate for the new version, called the “treatment.” 

The testers then monitor the behavior of both groups and determine which of the versions achieved better results. 

Feature flags are a practical way to enable A/B testing because they allow you to quickly and conveniently change between the control and treatment versions of your application.

Enabling Canary Releases

If you deliver the new version of your app to your entire userbase at once, 100 percent of your users will be impacted if the release is bad in some way. What if you could gradually roll out the new version instead? You’d first deploy to a small subset of users, monitoring that group to detect issues. If something went wrong, you could roll it back. If everything looked fine, you could then gradually release the version for larger groups. That’s a canary release in a nutshell. It’s another powerful technique that feature flags might help with.

Customizing Features According to Users’ Preferences

It’s not uncommon to have to customize your application according to the needs of specific users, and there are several ways in which software teams can accomplish that—some more efficient, and others less so (companies that create separate branches or entire repositories for each client come to mind).

This is another area where feature flags could help, allowing teams to dynamically switch between different versions of the same functionality.

Disable Code in Production 101

How do you go about disabling code? That’s what we’re going to see now, in three increasingly sophisticated phases.

First Stage: The Most Basic Approach

We start with an approach that’s so primitive, it maybe shouldn’t be considered a feature flag at all. Consider the pseudocode below:

calculateAdditionalWorkHours(Employee employee, Date start, Date end) {
  // return calculateAdditionalWorkHoursSameOldWay(employee, start, end);
  return calculateAdditionalWorkHoursImproved(employee, start, end);
}

In the code above, we’re just commenting out the old version of some method and replacing it with a new version. When we want the older version to be used, we just do the opposite. (Well, I said it was primitive.) This approach lacks one of the most fundamental properties of a feature flag—the ability to change how the application behaves without changing its code.

However, it plants the seed for more sophisticated approaches.

Second Stage: Taking the Decision Out of the Code

The previous approach didn’t allow developers to select the desired version of the feature without changing the code. Fortunately, that’s not so hard to do. First, we introduce a logical variable to determine which version we’re going to use:

calculateAdditionalWorkHours(Employee employee, Date start, Date end) {

  var result = useNewCalculation
    ? calculateAdditionalWorkHoursImproved(employee, start, end)
    : calculateAdditionalWorkHoursSameOldWay(employee, start, end);

  return result;
}

Then, we use some mechanism to be able to assign the value to the variable from an external source. We could use a configuration file:

var useNewCalculation = config[newCalculation];

Passing arguments to the application might be another option. What matters is that we now have the ability to modify how the app behaves from the outside, which is a great step toward “true” feature flagging.

Keep in mind that the code examples you see are all pseudocode. Using your favorite programming language, there’s nothing stopping you from starting with this approach and taking it up a notch. You could, for instance, use classes to represent the features and design patterns (e.g., factories) to avoid if statements.

Stage 3: Full-Fledged Feature Flag Management

The previous approach might be enough when your application has only a small number of flags. But as that number grows, things start to become messy.

First, you have the issue of technical debt. Manually implemented feature flags can create terribly confusing conditional flows in your codebase. That only grows worse with new flags being introduced each day. Additionally, they might make the code harder to understand and navigate, especially for more junior developers, which is an invitation for bugs.

Another problem is that as the number of flags grows, it becomes more and more common to forget to delete old, obsolete ones.

The main problem of a homegrown approach is that it doesn’t give you an easy way to see and manage all of your flags at once. That’s why our third and final stage is a single piece of advice: Instead of rolling out your own feature flags approach, adopt a third-party feature flag management system.

Feature Flags Are a CI/CD Enabler

We’ve covered the mechanisms developers can use to disable portions of their codebase in production without having to touch the code. This capability is powerful and enables techniques such as A/B testing and canary releases, which are all hallmarks of a modern, agile-based software development process.

The names for the techniques might vary—feature flags, feature toggles, feature flipper, and so on. The way in which the techniques are implemented can also vary—from a humble if statement to sophisticated cloud-based solutions.

But no matter what you call them, you can’t overstate the benefit these mechanisms offer. They’re an enabler of Continuous Integration, which is essential for any modern software organization that wants to stay afloat.

The post How to Disable Code: The Developer’s Production Kill Switch appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2B7IdU4
via IFTTT

Wednesday, 24 June 2020

Hide Scrollbars During an Animation

CSS still can’t animate to auto dimensions.

.dropdown {
  transition: 0.2s;
  height: 0;
}
.dropdown.open {
  /* the height will change, but it won't animate. */
  height: auto;
}

There is JavaScript trickery you can try. Brandon Smith outlined several techniques here a little while back. My mind always goes to this solution just because it’s so simple:

.dropdown {
  transition: 0.2s;
  max-height: 0;
}
.dropdown.open {
  /* 🎉 */
  max-height: 400px;
}

Now we have this 400px magic number which is really not ideal. But the fact that this works and is so simple makes it extremely appealing that I use it production all the time.

But the magic number isn’t the only problem. Another problem is scrollbars.

When we set max-height: 0;, we also need overflow: hidden; to make sure the dropdown is actually hidden when it is closed. When the dropdown is open, we should probably be using overflow: auto; so that we don’t accidentally cut off content in case the natural height of the dropdown is taller than the max-height after it expands. The use of overflow: auto; solves that problem while introducing another: during the expansion, our dropdown will always have scrollbars for at least part of the expansion, even if the final expansion height doesn’t need them. That’s awkward!

CSS trickery to the rescue.

We can still use overflow: auto; on the expanded state — we’ll just override it during the animation. As we learned in the great CSS specificity battle, @keyframes have an amazing ability to override anything while they are active. Let’s use them not to animate the opening, but just for this scrollbar-hiding functionality:

.dropdown {
  max-height: 0;
  overflow: hidden;
  transition: max-height 1.2s ease-in-out;
}
.dropdown.open {
  overflow: auto;
  max-height: 400px;
  animation: hide-scroll 1.2s backwards;
  @keyframes hide-scroll {
    from, to { overflow: hidden; } 
  }
}

That does the trick!

Try adjusting the height to something less to see how you don’t see scrollbars during the animation but only at the end when they are needed. That causes a little bit of jerkiness when the scrollbar pops in, but that was acceptable in my case as it’s rare that it happens at all. If you absolutely wanted to stop the jerkiness, you’d probably apply a (custom) scrollbar at all times to the dropdown and perhaps adjust the styling of the scrollbar during the animation, if needed.


Credit here to Mr. Stephen Shaw of the fancy @keyframers for this trick. I yanked him in to help me figure it out while I was working on it for something on CodePen. We decided to turn the trick into a video for the CodePen channel showcasing Collab Mode, which we used to figure out the problem/solution:

The post Hide Scrollbars During an Animation appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2YwbH7d
via IFTTT

How to Make localStorage Reactive in Vue

Reactivity is one of Vue’s greatest features. It is also one of the most mysterious if you don’t know what it’s doing behind the scenes. Like, why does it work with objects and arrays and not with other things, like localStorage?

Let’s answer that that question, and while we’re at it, make Vue reactivity work with localStorage.

If we were to run the following code, we would see that the counter being displayed as a static value and not change like we might expect it to because of the interval changing the value in localStorage.

new Vue({
  el: "#counter",
  data: () => ({
    counter: localStorage.getItem("counter")
  }),
  computed: {
    even() {
      return this.counter % 2 == 0;
    }
  },
  template: `<div>
    <div>Counter: </div>
    <div>Counter is </div>
  </div>`
});
// some-other-file.js
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", +counter + 1);
}, 1000);

While the counter property inside the Vue instance is reactive, it won’t change just because we changed its origin in localStorage

There are multiple solutions for this, the nicest perhaps is using Vuex and keep the store value in sync with localStorage. But what if we need something simple like what we have in this example? We have to take a dive in how Vue’s reactivity system works.

Reactivity in Vue

When Vue initializes a component instance, it observes the data option. This means it walks through all of the properties in data and converts them to getters/setters using Object.defineProperty. By having a custom setter for each property, Vue knows when a property changes, and it can notify the dependents that need to react to the change. How does it know which dependents rely on a property? By tapping into the getters, it can register when a computed property, watcher function, or  render function accesses a data prop.

// core/instance/state.js
function initData () {
  // ...
  observe(data)
}
// core/observer/index.js
export function observe (value) {
  // ...
  new Observer(value)
  // ...
}

export class Observer {
  // ...
  constructor (value) {
    // ...
    this.walk(value)
  }
  
  walk (obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
  }
} 


export function defineReactive (obj, key, ...) {
  const dep = new Dep()
  // ...
  Object.defineProperty(obj, key, {
    // ...
    get() {
      // ...
      dep.depend()
      // ...
    },
    set(newVal) {
      // ...
      dep.notify()
    }
  })
}

So, why isn’t localStorage reactive? Because it’s not an object with properties.

But wait. We can’t define getters and setters with arrays either, yet arrays in Vue are still reactive. That’s because arrays are a special case in Vue. In order to have reactive arrays, Vue overrides array methods behind the scenes and patches them together with Vue’s reactivity system.

Could we do something similar with localStorage?

Overriding localStorage functions

As a first try, we can fix our initial example by overriding localStorage methods to keep track which component instances requested a localStorage item.

// A map between localStorage item keys and a list of Vue instances that depend on it
const storeItemSubscribers = {};


const getItem = window.localStorage.getItem;
localStorage.getItem = (key, target) => {
  console.info("Getting", key);


  // Collect dependent Vue instance
  if (!storeItemSubscribers[key]) storeItemSubscribers[key] = [];
  if (target) storeItemSubscribers[key].push(target);


  // Call the original function 
  return getItem.call(localStorage, key);
};


const setItem = window.localStorage.setItem;
localStorage.setItem = (key, value) => {
  console.info("Setting", key, value);


  // Update the value in the dependent Vue instances
  if (storeItemSubscribers[key]) {
    storeItemSubscribers[key].forEach((dep) => {
      if (dep.hasOwnProperty(key)) dep[key] = value;
    });
  }


  // Call the original function
  setItem.call(localStorage, key, value);
};
new Vue({
  el: "#counter",
  data: function() {
    return {
      counter: localStorage.getItem("counter", this) // We need to pass 'this' for now
    }
  },
  computed: {
    even() {
      return this.counter % 2 == 0;
    }
  },
  template: `<div>
    <div>Counter: </div>
    <div>Counter is </div>
  </div>`
});
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", +counter + 1);
}, 1000);

In this example, we redefine getItem and setItem in order to collect and and notify the components that depend on localStorage items. In the new getItem, we note which component requests which item, and in setItems, we reach out to all the components that requested the item and rewrite their data prop.

In order to make the code above work, we have to pass on a reference to the component instance to getItem and that changes its function signature. We also can’t use the arrow function anymore because we otherwise wouldn’t have the correct this value.

If we want to do better, we have to dig deeper. For example, how could we keep track of dependents without explicitly passing them on?

How Vue collects dependencies

For inspiration, we can go back to Vue’s reactivity system. We previously saw that a data property’s getter will subscribe the caller to the further changes of the property when the data property is accessed. But how does it know who made the call? When we get a data prop, its getter function doesn’t have any input regarding who the caller was. Getter functions have no inputs. How does it know who to register as a dependent? 

Each data property maintains a list of its dependents that need to react in a Dep class. If we dig deeper in this class, we can see that the dependent itself is already defined in a static target variable whenever it is registered. This target is set by a so-far-mysterious Watcher class. In fact, when a data property changes, these watchers will be actually notified, and they will initiate the re-rendering of the component or the recalculation of a computed property.

But, again, who they are?

When Vue makes the data option observable, it also creates watchers for each computed property function, as well as all the watch functions (which shouldn’t be confused with the Watcher class), and the render function of every component instance. Watchers are like companions for these functions. They mainly do two things:

  1. They evaluate the function when they are created. This triggers the collection of dependencies.
  2. They re-run their function when they are notified that a value they rely on has changed. This will ultimately recalculate a computed property or re-render a whole component.

There is an important step that happens before watchers call the function they are responsible for: they set themselves as target in a static variable in the Dep class. This makes sure the they are registered as dependent when a reactive data property is accessed.

Keeping track of who called localStorage

We can’t exactly do that because we don’t have access to the inner mechanics of Vue. However, we can use the idea from Vue that lets a watcher set the target in a static property before it calls the function it is responsible for. Could we set a reference to the component instance before localStorage gets called?

If we assume that localStorage gets called while setting the data option, then we can hook into beforeCreate and created. These two hooks get triggered before and after initializing the data option, so we can set, then clear, a target variable with a reference to the current component instance (which we have access to in lifecycle hooks). Then, in our custom getters, we can register this target as a dependent.

The final bit we have to do is make these lifecycle hooks part of all our components. We can do that with a global mixin for the whole project.

// A map between localStorage item keys and a list of Vue instances that depend on it
const storeItemSubscribers = {};

// The Vue instance that is currently being initialised
let target = undefined;

const getItem = window.localStorage.getItem;
localStorage.getItem = (key) => {
  console.info("Getting", key);

  // Collect dependent Vue instance
  if (!storeItemSubscribers[key]) storeItemSubscribers[key] = [];
  if (target) storeItemSubscribers[key].push(target);

  // Call the original function
  return getItem.call(localStorage, key);
};

const setItem = window.localStorage.setItem;
localStorage.setItem = (key, value) => {
  console.info("Setting", key, value);

  // Update the value in the dependent Vue instances
  if (storeItemSubscribers[key]) {
    storeItemSubscribers[key].forEach((dep) => {
      if (dep.hasOwnProperty(key)) dep[key] = value;
    });
  }
  
  // Call the original function
  setItem.call(localStorage, key, value);
};

Vue.mixin({
  beforeCreate() {
    console.log("beforeCreate", this._uid);
    target = this;
  },
  created() {
    console.log("created", this._uid);
    target = undefined;
  }
});

Now, when we run our initial example, we will get a counter that increases the number every second.

new Vue({
  el: "#counter",
  data: () => ({
    counter: localStorage.getItem("counter")
  }),
  computed: {
    even() {
      return this.counter % 2 == 0;
    }
  },
  template: `<div class="component">
    <div>Counter: </div>
    <div>Counter is </div>
  </div>`
});
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", +counter + 1);
}, 1000);

The end of our thought experiment

While we solved our initial problem, keep in mind that this is mostly a thought experiment. It lacks several features, like handling removed items and unmounted component instances. It also comes with restrictions, like the property name of the component instance requires the same name as the item stored in localStorage. That said, the primary goal is to get a better idea of how Vue reactivity works behind the scenes and get the most out of it, so that’s what I hope you get out of all this.

The post How to Make localStorage Reactive in Vue appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2BBe1Rn
via IFTTT

Passkeys: What the Heck and Why?

These things called  passkeys  sure are making the rounds these days. They were a main attraction at  W3C TPAC 2022 , gained support in  Saf...