Front End Web Development

Using Immer for React State Management

Css Tricks - Wed, 08/07/2019 - 4:38am

We make use of state to keep track of application data. States change as users interact with an application. When this happens, we need to update the state that is displayed to the user, and we do this using React’s setState.

Since states are not meant to be updated directly (because React’s state has to be immutable), things can get really complicated as states become more complex. They become difficult to understand and follow.

This is where Immer comes in and that’s what we’re going to look at in this post. Using Immer, states can be simplified and much easier to follow. Immer makes use of something called "draft" which you can think of as the copy of your state, but not the state itself. It’s as though Immer hit CMD+C on the state and then cmd+V’d it somewhere else where it can be safely viewed without disturbing the original copy. Any updates you need to make happen on the draft, and the parts of the current state that change on the draft is updated.

Let’s say your application’s state looks like this;

this.state = { name: 'Kunle', age: 30, city: 'Lagos, country: 'Nigeria' }

This user happens to be celebrating his 31st birthday and which means we need to update the age value. With Immer running behind the scenes, a replica of this state will be made.

Now imagine the replica is made and handed over to a messenger, who gives the newly copied version of the state to Kunle. It means there are now two copies available — the current state and the draft copy that was handed over. Kunle then changes the age on the draft to 31. The messenger then returns to the application with the draft, compares both versions, and only updates the age since that’s the only part of the draft that changed.

It does not break the idea of an immutable state, as the current state does not get updated directly. Immer basically makes it convenient to work with immutable state.

Let’s look at an example of this at work

Say you want to build a traffic light for your community, you can give it a shot using Immer for your state updates.

See the Pen
Traffic Light Example with Reactjs
by CarterTsai (@CarterTsai)
on CodePen.

Using Immer, the component will look like this:

const {produce} = immer class App extends React.Component { state = { red: 'red', yellow: 'black', green: 'black', next: "yellow" } componentDidMount() { this.interval = setInterval(() => this.changeHandle(), 3000); } componentWillUnmount() { clearInterval(this.interval); } handleRedLight = () => { this.setState( produce(draft => { draft.red = 'red'; draft.yellow = 'black'; draft.green = 'black'; draft.next = 'yellow' }) ) } handleYellowLight = () => { this.setState( produce(draft => { draft.red = 'black'; draft.yellow = 'yellow'; draft.green = 'black'; draft.next = 'green' }) ) } handleGreenLight = () => { this.setState( produce(draft => { draft.red = 'black'; draft.yellow = 'black'; draft.green = 'green'; draft.next = 'red' }) ) } changeHandle = () => { if (this.state.next === 'yellow') { this.handleYellowLight() } else if (this.state.next === 'green') { this.handleGreenLight() } else { this.handleRedLight() } } render() { return ( <div className="box"> <div className="circle" style={{backgroundColor: this.state.red}}></div> <div className="circle" style={{backgroundColor: this.state.yellow}}></div> <div className="circle" style={{backgroundColor: this.state.green}}></div> </div> ); } };

produce is the default function we get from Immer. Here, we pass it as a value to the setState() method. The produce function takes a function which accepts draft as an argument. It is inside this function that we can then set the draft copy with which we want to update our state.

If that looks complicated, there is another way to write this. First, we create a function.

const handleLight = (state) => { return produce(state, (draft) => { draft.red = 'black'; draft.yellow = 'black'; draft.green = 'green'; draft.next = 'red' }); }

We are passing the current state of the application, and the function which accepts draft as arguments to the produce function. To make use of this inside our component, we do this;

handleGreenLight = () => { const nextState = handleLight(this.state) this.setState(nextState) } Another example: A shopping list

If you have been working with React for a while now, then you’re not a stranger to the spread operator. With Immer, you need not make use of the spread operator, especially when working with an array in your state.

Let’s explore that a little further by creating a shopping list application.

See the Pen
immer 2 - shopping list
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

Here’s the component we’re working with:

class App extends React.Component { constructor(props) { super(props) this.state = { item: "", price: 0, list: [ { id: 1, name: "Cereals", price: 12 }, { id: 2, name: "Rice", price: 10 } ] } } handleInputChange = e => { this.setState( produce(draft => { draft[event.target.name] = event.target.value })) } handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuid.v4(), name: this.state.name, price: this.state.price } this.setState( produce(draft => { draft.list = draft.list.concat(newItem) }) ) }; render() { return ( <React.Fragment> <section className="section"> <div className="box"> <form onSubmit={this.handleSubmit}> <h2>Create your shopping list</h2> <div> <input type="text" placeholder="Item's Name" onChange={this.handleInputChange} name="name" className="input" /> </div> <div> <input type="number" placeholder="Item's Price" onChange={this.handleInputChange} name="price" className="input" /> </div> <button className="button is-grey">Submit</button> </form> </div> <div className="box"> { this.state.list.length ? ( this.state.list.map(item => ( <ul> <li key={item.id}> <p>{item.name}</p> <p>${item.price}</p> </li> <hr /> </ul> )) ) : <p>Your list is empty</p> } </div> </section> </React.Fragment> ) } } ReactDOM.render( <App />, document.getElementById('root') );

As items are added to the list, we need to update the state of the list to reflect those new items. To update the state of list using setState(), we’ll have to do this:

handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuid.v4(), name: this.state.name, price: this.state.price } this.setState({ list: [...this.state.list, newItem] }) };

If you have to update multiple states in the application, you’ll have to do a ton of spreading to create a new state using the old state and the additional value. Which can look more complex as the number of changes increases. With Immer, it becomes very easy to do that, as we did in the example above.

What if we want to add a function that gets called as a callback after the state update?In this case, let’s say we are keeping a tally of the number of items in the list and the total price of all the items.

See the Pen
immer 3 - shopping list
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

Say we want to calculate the amount that will be spent based on the price of items in the list, we can have the handleSubmit function look like this:

handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuid.v4(), name: this.state.name, price: this.state.price } this.setState( produce(draft => { draft.list = draft.list.concat(newItem) }), () => { this.calculateAmount(this.state.list) } ) };

First, we create an object using the data entered by the user, which we then assign to newItem. To update our application’s state, we make use of .concat() which will return a new array that's comprised of the previous items and the new item. This updated copy is now set as the value of draft.list, which can then be used by Immer to update the state of the application.

The callback function gets called after the state update. It’s important to note that it makes use of the updated state.

The function we want to call will look like this:

calculateAmount = (list) => { let total = 0; for (let i = 0; i < list.length; i++) { total += parseInt(list[i].price, 10) } this.setState( produce(draft => { draft.totalAmount = total }) ) } Let’s look at Immer hooks

use-immer is a hook that allows you to manage state in your React application. Let’s see this in action using a classic counter example.

import React from "react"; import {useImmer} from "use-immer"; const Counter = () => { const [count, updateCounter] = useImmer({ value: 0 }); function increment() { updateCounter(draft => { draft.value = draft.value +1; }); } return ( <div> <h1> Counter {count.value} </h1> <br /> <button onClick={increment}>Increment</button> </div> ); } export default Counter;

useImmer is similar to useState. The function returns the state and an updater function. When the component loads at first, the value of the state (which is count in this example), is the same as the value passed to useImmer. Using the updater function which is returned, we can then create an increment function to increase the value of the count.

There is also a useReducer-like hook for Immer.

import React, { useRef } from "react"; import {useImmerReducer } from "use-immer"; import uuidv4 from "uuid/v4" const initialState = []; const reducer = (draft, action) => { switch (action.type) { case "ADD_ITEM": draft.push(action.item); return; case "CLEAR_LIST": return initialState; default: return draft; } } const Todo = () => { const inputEl = useRef(null); const [state, dispatch] = useImmerReducer(reducer, initialState); const handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuidv4(), text: inputEl.current.value }; dispatch({ type: "ADD_ITEM", item: newItem }); inputEl.current.value = ""; inputEl.current.focus(); } const handleClear = () => { dispatch({ type: 'CLEAR_LIST' }) } return ( <div className='App'> <header className='App-header'> <ul> {state.map(todo => { return <li key={todo.id}>{todo.text}</li>; })} </ul> <form onSubmit={handleSubmit}> <input type='text' ref={inputEl} /> <button type='submit' > Add Todo </button> </form> <button onClick={handleClear} > Clear Todos </button> </header> </div> ); } export default Todo;

useImmerReducer takes in a reducer function and the initial state, and it returns both state and the dispatch function. We can then loop through the state to display the items we have. We dispatch an action when submitting a todo item and clearing the list of them. The dispatched action has a type which we use in determining what to do in the reducer function.
In the reducer function, we make use of draft like we did before, instead of state. With that, we have a convenient way of manipulating the state of our application.

You can find the code used in the above example on GitHub.

That’s a look at Immer!

Going forward, you can begin to make use of Immer in your next project, or even slowly begin to use it in the current project you’re working on. It has proven to aid in making state management convenient.

The post Using Immer for React State Management appeared first on CSS-Tricks.

Quick Gulp Cache Busting

Css Tricks - Wed, 08/07/2019 - 4:05am

You should for sure be setting far-out cache headers on your assets like CSS and JavaScript (and images and fonts and whatever else). That tells the browser "hang on to this file basically forever." That way, when navigating from page to page on a site — or revisiting it, or refreshing the page — the browser doesn't have to download it again which produces way faster page loads. It's massively important for web performance, so do it!

But how do you force the browser to get a fresh version of the file? Well, there are a bunch of ways. Check out that blog post for more. But here's one that I've used just recently that I wanted to document.

The trick is to change the query string

There was an era where the prevailing wisdom was that changing the query string wasn't enough, but even then it, the reasons it wouldn't work were pretty much edge cases. These days, changing the query string is fine (assuming you don't change the default behavior, services like Cloudflare let you do it).

So, one day you ship it like this in your HTML:

<link rel="stylesheet" href="style.css?v=1" />

Then you change that query string to break the cache when you need to:

<link rel="stylesheet" href="style.css?v=2" />

The HTML, by the way, is either not cached or cached for a much shorter amount of time, so changes to HTML will be seen.

I sometimes do it by hand

For many years, I busted cache on this very site by setting a PHP variable and using it to break assets, like...

<?php $ver = 1.0; ?> <link rel="stylesheet" href="style.css?v=<?php echo $ver; ?>" /> <link rel="stylesheet" href="some-other-asset.css?v=<?php echo $ver; ?>" />

Hey that works, but it was me hand-manipulating that variable. I would sometimes forget to do it, and even if I did remember, I sort of resented having to do it.

Automating version busting with Gulp

I'm using a Gulp-powered build process at the moment on this site, which does all the classic stuff: Sass, Babel, file concatenation, live reloading...

It occurred to me I might as well have Gulp do the query-string changing whenever changes are made to CSS or JavaScript. JavaScript has a .replace() method, and that's available in Node/Gulp easily with the gulp-replace plugin.

I make a task. When I call it, it looks in my header filer for the string cache_bust= plus some value, and replaces it with a new randomized string based on the date and time.

gulp.task("cache-bust-css", function() { var cbString = new Date().getTime(); return gulp .src(["header.php"]) .pipe( replace(/cache_bust=\d+/g, function() { return "cache_bust=" + cbString; }) ) .pipe(gulp.dest(".")); });

I do the same thing in a separate task when JavaScript files are editing and compiled.

It's still a little dumb

Notice that I'm changing the query string on all the CSS assets every time any of them changes. That's not as efficient as it could be. I should probably be changing the query string only on the changed files.

I'll get to it eventually. Sometimes you just gotta baby-step your way to better solutions over time.

This is just one way! There are other Gulp plugins just for this. Other build systems have different approaches. This approached happened to work well for me and my exact needs at the time. Feel free to share your strategy!

The post Quick Gulp Cache Busting appeared first on CSS-Tricks.

Let’s Give Grunt Tasks the Marie Kondo Organization Treatment

Css Tricks - Tue, 08/06/2019 - 10:27am

We live in an era of webpack and npm scripts. Good or bad, they took the lead for bundling and task running, along with bits of Rollup, JSPM and Gulp. But let's face it. Some of your older projects are still using good ol' Grunt. While it no longer glimmers as brightly, it does the job well so there's little reason to touch it.

Though, from time to time, you wonder if there’s a way to make those projects better, right? Then start from "Organizing Your Grunt Tasks" article and come back. I'll wait. That’ll set the stage for this post and then we'll take it further together to create a solid organization of Grunt tasks.

Automatic Speed Daemon task loading

It’s no fun writing loading declarations for each task, like this:

grunt.loadNpmTasks('grunt-contrib-clean') grunt.loadNpmTasks('grunt-contrib-watch') grunt.loadNpmTasks('grunt-csso') grunt.loadNpmTasks('grunt-postcss') grunt.loadNpmTasks('grunt-sass') grunt.loadNpmTasks('grunt-uncss') grunt.initConfig({})

It's common to use load-grunt-tasks to load all tasks automatically instead. But what if I tell you there is a faster way?

Try jit-grunt! Similar to load-grunt-tasks, but even faster than native grunt.loadNpmTasks.

The difference can be striking, especially in projects with large codebases.

Without jit-grunt

loading tasks 5.7s ???????? 84% assemble:compile 1.1s ?? 16% Total 6.8s

With jit-grunt

loading tasks 111ms ? 8% loading assemble 221ms ?? 16% assemble:compile 1.1s ???????? 77% Total 1.4s

1.4 seconds doesn't really make it a Speed Daemon... so I kinda lied. But still, it's six times faster than the traditional way! If you're curious how that's possible, read about the original issue which led to the creation of jit-grunt.

How is jit-grunt used? First, install:

npm install jit-grunt --save

Then replace all tasks load statements with a single line:

module.exports = function (grunt) { // Intead of this: // grunt.loadNpmTasks('grunt-contrib-clean') // grunt.loadNpmTasks('grunt-contrib-watch') // grunt.loadNpmTasks('grunt-csso') // grunt.loadNpmTasks('grunt-postcss') // grunt.loadNpmTasks('grunt-sass') // grunt.loadNpmTasks('grunt-uncss') // Or instead of this, if you've used `load-grunt-tasks` // require('load-grunt-tasks')(grunt, { // scope: ['devDependencies', 'dependencies'] // }) // Use this: require('jit-grunt')(grunt) grunt.initConfig({}) }

Done!

Better configs loading

In the last example, we told Grunt how to load tasks itself, but we didn't quite finish the job. As “Organizing Your Grunt Tasks" suggests, one of the most useful things we're trying to do here is split up a monolithic Gruntfile into smaller standalone files.

If you read the mentioned article, you'll know it's better to move all task configuration into external files. So, instead of a large single gruntfile.js file:

module.exports = function (grunt) { require('jit-grunt')(grunt) grunt.initConfig({ clean: {/* task configuration goes here */}, watch: {/* task configuration goes here */}, csso: {/* task configuration goes here */}, postcss: {/* task configuration goes here */}, sass: {/* task configuration goes here */}, uncss: {/* task configuration goes here */} }) }

We want this:

tasks ?? postcss.js ?? concat.js ?? cssmin.js ?? jshint.js ?? jsvalidate.js ?? uglify.js ?? watch.js ?? sass.js gruntfile.js

But that will force us to load each external configuration into gruntfile.js manually, and that takes time! We need a way to load our configuration files automatically.

We’ll use load-grunt-configs for that purpose. It takes a path, grabs all of the configuration files there and gives us a merged config object which we use for Grunt config initialization.

Here how it works:

module.exports = function (grunt) { require('jit-grunt')(grunt) const configs = require('load-grunt-configs')(grunt, { config: { src: 'tasks/.js' } }) grunt.initConfig(configs) grunt.registerTask('default', ['cssmin']) }

Grunt can do the same thing natively! Take a look at grunt.task.loadTasks (or it's alias grunt.loadTasks).

Use it like this:

module.exports = function (grunt) { require('jit-grunt')(grunt) grunt.initConfig({}) // Load all your external configs. // It's important to use it _after_ Grunt config has been initialized, // otherwise it will have nothing to work with. grunt.loadTasks('tasks') grunt.registerTask('default', ['cssmin']) }

Grunt will automatically load all js or coffee config files from the specified directory. Nice and clean! But, if you'll try to use it, you'll notice it does nothing. How is that? We still need to do one more thing.

Let's look into our gruntfile.js code once again, this time without the comments:

module.exports = function (grunt) { require('jit-grunt')(grunt) grunt.initConfig({}) grunt.loadTasks('tasks') grunt.registerTask('default', ['cssmin']) }

Notice that grunt.loadTasks loads files from tasks directory, but never assigns it to our actual Grunt config.

Compare it with a way load-grunt-configs works:

module.exports = function (grunt) { require('jit-grunt')(grunt) // 1. Load configs const configs = require('load-grunt-configs')(grunt, { config: { src: 'tasks/.js' } }) // 2. Assign configs grunt.initConfig(configs) grunt.registerTask('default', ['cssmin']) }

We initialize our Grunt config before actually loadings tasks configuration. If you are getting a strong feeling that it will make us end up with empty Grunt config — you're totally right. You see, on contrary to the load-grunt-configs, grunt.loadTasks just imports files into gruntfile.js. It does nothing more.

Woah! So, how do we make use of it? Let's explore!

First, create a file inside directory tasks named test.js

module.exports = function () { console.log("Hi! I'm an external task and I'm taking precious space in your console!") }

Let's run Grunt now:

$ grunt

We'll see printed to the console:

> Hi! I'm an external task and I'm taking precious space in your console!

So, upon importing grunt.loadTasks, every function is executed as it loads files. That's nice, but what's the use of it for us? We still can't do a thing we actually want — to configure our tasks.

Hold my beer because there is a way to command Grunt from within external configuration files! Using grunt.loadTasks upon importing provides current Grunt instance as a function first argument and also binds it to this.

So, we can update our Gruntfile:

module.exports = function (grunt) { require('jit-grunt')(grunt) grunt.initConfig({ // Add some value to work with testingValue: 123 }) grunt.loadTasks('tasks') grunt.registerTask('default', ['cssmin']) }

...and change the external config file tasks/test.js:

// Add `grunt` as first function argument module.exports = function (grunt) { // Now, use Grunt methods on `grunt` instance grunt.log.error('I am a Grunt error!') // Or use them on `this` which does the same this.log.error('I am a Grunt error too, from the same instance, but from `this`!') const config = grunt.config.get() grunt.log.ok('And here goes current config:') grunt.log.ok(config) }

Now, let’s run Grunt again:

$ grunt

And what we'll get:

> I am Grunt error! > I am Grunt error too, from the same instance, but from `this`! > And here goes current config: > { testingValue: 123 }

See how we accessed native Grunt methods from an external file and were even able to retrieve the current Grunt config? Are you thinking about that too? Yeah, the full power of Grunt is already there, right at our fingertips in each file!

If you are wondering why methods inside external files can affect our main Grunt instance, it is because of a referencing. grunt.loadTasks passing this and grunt to our current Grunt instance — not a copy of it. By invoking methods on that reference, we're able to read and mutate our main Grunt configuration file.

Now, we need to actually configure something! One last thing...

This time, let’s make configuration loading work for real

Alright, we’ve come a long way. Our tasks are loaded automatically and faster. We learned how to load external configs with native Grunt method. But our task configs are still not quite there because they do not end up in Grunt config.

But we’re almost there! We learned that we can use any Grunt instance methods in imported files using grunt.loadTasks. They are available on grunt and this instances.

Among many other methods, there is a precious grunt.config method. It allows us to set a value in an existing Grunt config. The main one, which we initialized in our Gruntfile... remember that one?

What's important is the way we can define tasks configurations. Exactly what we need!

// tasks/test.js module.exports = function (grunt) { grunt.config('csso', { build: { files: { 'style.css': 'styles.css' } } }) // same as // this.config('csso', { // build: { // files: { 'style.css': 'styles.css' } // } // }) }

Now let's update Gruntfile to log the current config. We need to see what we did, after all:

module.exports = function (grunt) { require('jit-grunt')(grunt) grunt.initConfig({ testingValue: 123 }) grunt.loadTasks('tasks') // Log our current config console.log(grunt.config()) grunt.registerTask('default', ['cssmin']) }

Run Grunt:

$ grunt

...and here’s what we see:

> { testingValue: 123, csso: { build: { files: { 'style.css': 'styles.css' } } } }

grunt.config sets csso value when imported, so the CSSO task is now configured and ready to run when Grunt is invoked. Perfect.

Note that if you used load-grunt-configs previously, you had a code like that, where each file exports a configuration object:

// tasks/grunt-csso.js module.exports = { target: { files: { 'style.css': 'styles.css' } } }

That needs to be changed to a function, as described above:

// tasks/grunt-csso.js module.exports = function (grunt) { grunt.config('csso', { build: { files: { 'style.css': 'styles.css' } } }) }

OK, one more one more last thing... this time for real!

Taking external config files to the next level

We learned a lot. Load tasks, load external configuration files, define a configuration with Grunt methods... that's fine, but where's the profit?

Hold my beer again!

By this time, we’ve externalized all our task configuration files. So, the our project directory looks something like this:

tasks ?? grunt-browser-sync.js ?? grunt-cache-bust.js ?? grunt-contrib-clean.js ?? grunt-contrib-copy.js ?? grunt-contrib-htmlmin.js ?? grunt-contrib-uglify.js ?? grunt-contrib-watch.js ?? grunt-csso.js ?? grunt-nunjucks-2-html.js ?? grunt-postcss.js ?? grunt-processhtml.js ?? grunt-responsive-image.js ?? grunt-sass.js ?? grunt-shell.js ?? grunt-sitemap-xml.js ?? grunt-size-report.js ?? grunt-spritesmith-map.mustache ?? grunt-spritesmith.js ?? grunt-standard.js ?? grunt-stylelint.js ?? grunt-tinypng.js ?? grunt-uncss.js ?? grunt-webfont.js gruntfile.js

That keeps Gruntfile relatively small and things seem to be well organized. But do you get a clear picture of the project just by glancing into this cold and lifeless list of tasks? What actually do they do? What's the flow?

Can you tell that Sass files are going through grunt-sass, then grunt-postcss:autoprefixer, then grunt-uncss, and finally through grunt-csso? Is it obvious that the clean task is cleaning the CSS or that grunt-spritesmith is generating a Sass file which should be picked up too, as grunt-watch watches over changes?

Seems like things are all over the place. We may have gone too far with externalization!

So, finally... now what if tell you that there’s yet a better way would be group configs... based on features? Instead of a not-so-helpful list of tasks, we'll get a sensible list of features. How about that?

tasks ?? data.js ?? fonts.js ?? icons.js ?? images.js ?? misc.js ?? scripts.js ?? sprites.js ?? styles.js ?? templates.js gruntfile.js

That tells me a story! But how could we do that?

We already learned about grunt.config. And believe it or not, you can use it multiple times in a single external file to configure multiple tasks at once! Let’s see how it works:

// tasks/styles.js module.exports = function (grunt) { // Configuring Sass task grunt.config('sass', { build: {/* options */} }) // Configuring PostCSS task grunt.config('postcss', { autoprefix: {/* options */} }) }

One file, multiple configurations. Quite flexible! But there is an issue we missed.

How should we deal with tasks such as grunt-contrib-watch? Its configuration is a whole monolithic thing with definitions for each task that are unable to be split.

// tasks/grunt-contrib-watch.js module.exports = function (grunt) { grunt.config('watch', { sprites: {/* options */}, styles: {/* options */}, templates: {/* options */} }) }

We can't simply use grunt.config to set watch configuration in each file, as it will override the same watch configuration in already imported files. And leaving it in a standalone file sounds like a bad option too — after all, we want to keep all related things close.

Fret not! grunt.config.merge to the rescue!

While grunt.config explicitly sets and overrides any existing values in Grunt config, grunt.config.merge recursively merges values with existing values in other Grunt config files giving us a single Grunt config. A simple, but effective way to keep related things together.

An example:

// tasks/styles.js module.exports = function (grunt) { grunt.config.merge({ watch: { templates: {/* options */} } }) } // tasks/templates.js module.exports = function (grunt) { grunt.config.merge({ watch: { styles: {/* options */} } }) }

This will produce a single Grunt config:

{ watch: { styles: {/* options */}, templates: {/* options */} } }

Just what we needed! Let's apply this to the real issue — our styles-related configuration files. Replace our three external task files:

tasks ?? grunt-sass.js ?? grunt-postcss.js ?? grunt-contrib-watch.js

...with a single tasks/styles.js file that combines them all:

module.exports = function (grunt) { grunt.config('sass', { build: { files: [ { expand: true, cwd: 'source/styles', src: '{,**/}*.scss', dest: 'build/assets/styles', ext: '.compiled.css' } ] } }) grunt.config('postcss', { autoprefix: { files: [ { expand: true, cwd: 'build/assets/styles', src: '{,**/}*.compiled.css', dest: 'build/assets/styles', ext: '.prefixed.css' } ] } }) // Note that we need to use `grunt.config.merge` here! grunt.config.merge({ watch: { styles: { files: ['source/styles/{,**/}*.scss'], tasks: ['sass', 'postcss:autoprefix'] } } }) }

Now it's much easier to tell just by glancing into tasks/styles.js that styles have three related tasks. I'm sure you can imagine extending this concept to other grouped tasks, like all the things you might want to do with scripts, images, or anything else. That gives us a reasonable configuration organization. Finding things will be much easier, trust me.

And that's it! The whole point of what we learned.

That’s a wrap

Grunt is no longer the new darling it once was when it first hit the scene. But to date, it is a straightforward and reliable tool that does its job well. With proper handling, it gives even fewer reasons to swap it for something newer.

Let's recap what we can do to organize our tasks efficiently:

  1. Load tasks using jit-grunt instead of load-grunt-tasks. It's same but insanely faster.
  2. Move specific task configurations out from Gruntfile and into external config files to keep things organized.
  3. Use native grunt.task.loadTasks to load external config files. It's simple but powerful as it exposes all Grunt capabilities.
  4. Finally, think about a better way to organize your config files! Group them by feature or domain instead of the task itself. Use grunt.config.merge to split complex tasks like watch.

And, for sure, check Grunt documentation. It’s still worth a read after all these years.

If you’d like to see a real-world example, check out Kotsu, a Grunt-based starter kit and static website generator. You'll find even more tricks in there.

Got better ideas about how to organize Grunt configs even better? Please share them in the comments!

The post Let’s Give Grunt Tasks the Marie Kondo Organization Treatment appeared first on CSS-Tricks.

SSCCE

Css Tricks - Tue, 08/06/2019 - 4:28am

You know what a "reduced test case" is, right? We've talked about it here. I imagine the concept is useful in many walks of life, but in the world of front-end development, you can think of it like:

A reduced test case is a demo/example page you create which reproduces the problem you are having with the least amount of code possible. Only the HTML needed to show the problem content. Only CSS that is related to that reduced HTML. Only the JavaScript related to the problem functionality at hand.

The point of making these is typically troubleshooting. It's both for you and for anyone else looking at the trouble. The less unrelated code anyone has to wade through to understand the problem, the better. The secret trick is that while making a reduced test case, you often figure out the problem in the process. ;)

I recently found out another acronym for all this: SSCCE.

That stands for "Short, Self Contained, Correct (Compilable), Example." Sleuthing the meta tags, it looks like the credit is to Andrew Thompson and last updated in 2014. That landing page describes them wonderfully and explains what you need to do to create one.

It covers this classic situation where you discover the problem isn't where you think it is:

If trimming a very large amount if code for others to see, you might trim out a part of it early on that you think is not related to the problem, yet the problem is fixed.

...and closes with the most important thing:

We are not proposing that every single problem needs a SSCCE in order to be solved. It will, however, make people much more likely to help, and will therefore increase the chance of finding a solution.

I'd say it's a dramatic difference. The chances of me trying to help on a small bug where the bug is buried within a giant pile of unfamiliar code? Very low. The chances of me trying to help on a small bug with a SSCCE? High.

However, I think I still prefer "reduced test case" since the term is more self-explanatory.

The post SSCCE appeared first on CSS-Tricks.

Using Your Domain with a Netlify-Hosted Site

Css Tricks - Tue, 08/06/2019 - 4:25am

Netlify has their own docs for Custom Domains, so if you're looking for horse's mouth technical docs on this stuff, that should be treated as the source of truth. But I'd like to take a crack at it from a slightly different angle, where we look at where you are and what you wanna do, and the point you in the right direction.

Do you NOT own the domain yet?

If that's the case, you can buy it directly through Netlify if you want. There is a big advantage there in that it automatically gets set up to work perfectly, so it's easier.

You don't have to buy your domain through Netlify though, you can buy it wherever you like. There is nothing you can't do with Netlify if you choose to buy a domain elsewhere.

Easiest possible method: register the domain with Netlify.

Alternative: If you anticipate some hosting/DNS churn, like you think you might ultimately need to host elsewhere, it probably makes more sense to manage to domain somewhere agnostic where you can re-point DNS stuff wherever you need to. It's not that you can't manage the DNS on Netlify and point it elsewhere, it just doesn't make loads of sense. Also, there is something to be said (lower cognitive load) managing all your domains in one place if you can.

What if you already own the domain?

No problem. The rest of this article deals with that scenario.

Are you cool pointing the nameservers at Netlify?

If you are, this is the best way. It means you don't have to fiddle with subdomains and the CDN features work the best. The requires you to go into the DNS administration area of wherever you bought the domain and change the nameservers there. Every domain registrant will be a bit different in where and how you do that.

Changing nameservers on GoDaddy to point to Netlify. Can't or don't want to point nameservers at Netlify?

I would guess that the main reason you might have this preference is that you use Cloudflare, or perhaps something else similar that gives you fancy performance and security advantages by going through their proxy. Netlify actually says that you don't need Cloudflare with them, because many of the main advantages of Cloudflare Netlify already provides.

Technology is a moving place though, and it's entirely possible that you need or really want some feature that a proxy service like Cloudflare provides.

If you need to do this, you've got two options:

  • Use the www. version of your domain and a CNAME record to point to Netlify (you can "CNAME flatten" it to remove www. if you really want).
  • Point the A record to Netlify's load balancer IP address. I'd list it here, but you're better off getting it from their docs in case it changes.
Are you just dealing with a subdomain anyway?

This is actually a lot easier. If this is the case, you probably already own the domain name anyway, and you should stick with your existing DNS host. All you need to do is CNAME the subdomain to the Netlify domain. Here's an example where the root domain is hosted elsewhere and uses Cloudflare for DNS, but the subdomain is Netlify hosted and points with a CNAME.

If you care about the Netlify domain sitting there with the same content on it, you can always redirect it. Also, you might need to "gray cloud" (turn off the Cloudflare proxy) for those subdomains so Netlify can issue SSL certificates for it.

The post Using Your Domain with a Netlify-Hosted Site appeared first on CSS-Tricks.

Let Mavo Shine in Building Interactive Web Applications

Css Tricks - Mon, 08/05/2019 - 6:36pm

As you could guess from the title, this tutorial is dedicated to Mavo: a new, approachable way to create complex, reactive, persistent web applications just by writing HTML and CSS, without a single line of JavaScript and no server backend.

&#x1f407; Follow the white rabbit!

Mavo is developed in the Haystack Group at MIT CSAIL and led by Lea Verou).

The app we will build together is a flashcard study app for foreign language learners. It is a fully-fledged CRUD application that lets you:

  • Create, delete, update flashcards and re-arrange them via drag and drop.
  • Import and export flashcards.
  • Evaluate how well you've learned the word on a flashcard.

Here is what our finished application looks like:

In the tutorial, I will guide you through the entire process of building the app.

At the end of some steps, I provide suggestions for you to experiment with Mavo—to learn a bit more—and to make some enhancements to the application we are building.

Are you ready? Let's get started! &#x1f600;

Static template

See the Pen
01. Static template
by Dmitry Sharabin (@dsharabin)
on CodePen.

In order to illustrate how Mavo enhances standard HTML, we will first create a purely static HTML page and then use Mavo to turn this static HTML into a fully-functional web application.

Assume we have the following HTML code inside <body>:

<header> <h1>Flashcards</h1> </header> <main> <article> <p>Word or phrase</div> <p>Translation</div> </article> </main>

In that code, the <article> element represents a single flashcard.

Let's add some styling in order to make our HTML look more like an actual flashcards app. You can take a look at the source code and play with it here.

Getting started with Mavo

Right now, all we have is a static template. It's time to add functionality, so it can actually work like a flashcard application. Here comes Mavo!

In order to use Mavo, we first need to include its JavaScript and CSS files in our page’s <head> section:

<head> ... <script src="https://get.mavo.io/mavo.min.js"></script> <link rel="stylesheet" href="https://get.mavo.io/mavo.css"> ... </head> &#x1f407; Follow the white rabbit!

Perhaps you need to support older browsers, or want to be able to read the code? You can customize which build and version of Mavo you are using here by answering a few questions. Defining a Mavo app

To enable Mavo functionality on an HTML structure, we must use the mv-app attribute on the element that contains our Mavo app (which may even be the <body> or <html> element, that's fine!). Its value is an ID for our app that should be unique in the page.

&#x1f407; Follow the white rabbit!

If we use mv-app without a value and there is no id or name attribute on the same element, a name such as mavo1, mavo2, etc. will be automatically generated.

However, it is strongly recommended to name your Mavo apps, because the name is used in a number of places.

Considering that the <main> element is representing our Mavo app, let's add the mv-app attribute to it and give our app the ID "flashcards":

<main mv-app="flashcards"> ... </main> The property attribute

See the Pen
02. The property attribute
by Dmitry Sharabin (@dsharabin)
on CodePen.

It's time to tell Mavo what elements of our app are important, i.e., which elements we want to be editable and be saved.

Now we have two such elements, and they are the <p> elements. Let's add the property attribute to those elements to tell Mavo they contain data. Elements with the property attribute are called properties.

&#x1f407; Follow the white rabbit!

We can put the property attribute on any HTML5 element, and Mavo knows how to make it editable. For example, for a <span> you edit its contents, but a <time> lets you edit its date/time via an appropriate date/time picker.

You can also expand this set of rules and make elements editable in new ways (e.g., rich text), via plugins.

Keep in mind that the value of the property attribute should describe the element, similarly to an id or class attribute:

... <p property="source">Word or phrase</div> <p property="translation">Translation</div> ... &#x1f407; Follow the white rabbit!

If you already have a class, id, or itemprop attribute that describes the element sufficiently well, you can use property without a value, e.g., <p property class="source">.

Notice any changes in our app? The Mavo toolbar with an Edit button appeared at the top of the page. The Edit button lets the user switch between read and edit modes. Now our app is in read mode. That means we can't edit the data on the page.

&#x1f407; Follow the white rabbit!

The Mavo toolbar is fully customizable, as is almost all of the UI generated by Mavo: you can change its placement, remove its default styling, add custom button elements, or use your own HTML elements for it, among other things.

We will see one example of such customization later on in this tutorial.

Visit this section of the Mavo website to learn more.

Now lets us switch to edit mode by clicking the Edit button. What has changed? The text of the Edit button becomes Editing to indicate that we are in edit mode. If you hover over the paragraphs, Mavo communicates that you can click to edit them by highlighting them in yellow. Go ahead! Click the text and edit it. Wow! We can change the content of the page right in place!

&#x1f4bb; Let's get our hands dirty!

Assume that in addition to the word and its translation, the flashcard should have an example of the word's usage in a sentence. Enhance the app by adding the appropriate elements to the flashcard.

The mv-multiple attribute

See the Pen
03. The mv-multiple attribute
by Dmitry Sharabin (@dsharabin)
on CodePen.

At this point, we have only one flashcard in our app. That's not very useful! For a working flashcard application, we need the ability to add, delete, and rearrange flashcards. How can we do that? We could create more flashcards by adding more <article> elements to our code, but then how does an end user create and delete flashcards?

Fortunately, Mavo has something to offer that makes this a breeze: the mv-multiple attribute, which tells Mavo that certain elements can be multiplied. It converts the element it’s used on to an editable collection of items and generates (customizable) UI for adding, deleting, and rearranging items.

&#x1f407; Follow the white rabbit!

If mv-multiple is used on an element without a property attribute, Mavo automatically adds property="collection" to it (or collection2, collection3, etc. so that the name is unique). However, it's recommended to also use a property attribute, to name your collection and make sure its data is preserved if the HTML changes.

Let's use the mv-multiple attribute in our app to convert our lonely flashcard into a collection of flashcards:

<article property="flashcard" mv-multiple> ... </article> &#x1f407; Follow the white rabbit!

It is also possible to specify the property name as a value of mv-multiple, like so: <article mv-multiple="flashcard">.

The mv-multiple attribute goes on the element that will be multiplied, not the container of the collection. It's a common mistake for people to do <ul mv-multiple> instead of <li mv-multiple> and can often go undetected for a while until the element is inspected or the styling makes it obvious.

Now switch the app to edit mode. Note that below the flashcard, there is now an Add flashcard button. Let's give it a try: create a few flashcards with the help of that button. Now we can dynamically add new elements right in the app, even though there are no corresponding elements in the HTML. But that is not all!

&#x1f407; Follow the white rabbit!

Note that the property attribute on <article> does not actually make the entire <article> element editable, but instead acts as a grouping element. This happens when you use the property attribute on elements that contain other properties.

Try hovering over a flashcard and notice the three buttons that appear near its top right corner for adding, deleting and rearranging elements via a drag and drop handle. And by hovering over any item bar button, we can understand which flashcard they correspond: Mavo highlights it. Isn't that amazing?

&#x1f407; Follow the white rabbit!

You can customize any UI element generated by Mavo, e.g., you can create your own drag handle by using an mv-drag-handle class. &#x1f407; Follow the white rabbit!

The buttons added by Mavo to every item in a collection are also keyboard accessible. Even reordering: you can focus on the drag handle and use the arrow keys to move the item. The mv-storage attribute

See the Pen
04. The mv-storage attribute
by Dmitry Sharabin (@dsharabin)
on CodePen.

Now that we have the basic UI in place, let's try the following:

  • Switch to edit mode (if you haven't already done so).
  • Edit the first flashcard's source word and translation. Add a couple more flashcards too.
  • Switch the app back to read mode.
  • And finally... refresh the page.

What?! Where did our data go? Wasn't Mavo supposed to save it? What happened?

Actually, we never told Mavo if or where to store our data!

To do so, we need to use the mv-storage attribute. What options do we have? Well, Mavo opens great possibilities for us, and Mavo plugins open up even more!

In our application, we are going to store the data in the browser’s localStorage, which is one of the simplest options available, so it's good for our first Mavo app. We just need to add the attribute mv-storage with the value local to the element with the mv-app attribute (also called the Mavo root).

<main mv-app="flashcards" mv-storage="local"> ... </main>

Have a look at the Mavo toolbar. Notice something? Another button appeared—the Save button.

Try to edit the app data one more time. Note that the Save button is now highlighted. Hover over the Save button, and Mavo will highlight the properties with the unsaved data. Isn't that cool?

Click the Save button and refresh the page (there is no need to switch to read mode before refreshing the page). Is your data still there? Great! We are one step closer to our goal—a fully-fledged flashcard application.

The mv-autosave attribute

Now we have to click the Save button every time we need our data to be saved? That may be safer, to prevent destroying valuable data, but it can often be inconvenient. Can we just save the data automatically? Sure! To save the data automatically every time it is changed, we can use the mv-autosave attribute on our Mavo root. Its value is the number of seconds to throttle saving by. Let's add mv-autosave="3" to the root element of our app:

<main mv-app="flashcard" mv-storage="local" mv-autosave="3"> ... </main> &#x1f407; Follow the white rabbit!

If mv-autosave="3", Mavo can only save at most once every three seconds. This can be especially useful for backends which keep a change history (e.g., GitHub, Dropbox) to prevent flooding which would render that history useless.

To disable throttling and save immediately, we can use mv-autosave="0" or just mv-autosave, which will also remove the Save button from the UI (since it serves no purpose in that case).

Change the data one more time and have a look at the Save button. See? In the beginning, it was highlighted but after 3 seconds–it is not. All our data is now saved automatically!

So, now the main part of our app would look like that:

<main mv-app="flashcards" mv-storage="local" mv-autosave="3"> <article property="flashcard" mv-multiple> <p property="source">Word or phrase</div> <p property="translation">Translation</div> </article> </main> &#x1f4bb; Let's get our hands dirty!

We are almost done with the alpha version of our app. Now it’s your turn to make the app even better. No worries, you have all the knowledge you need.

Enhance the app so as flashcards could be organized by end users in different groups related to various topics, e.g., the users could gather all the flashcards corresponding to clothing in one group, all the flashcards associated with kitchen utensils in the other one, etc.

&#x1f4a1; Hints!

There are many ways to achieve that goal, and it's up to you to decide what to follow. However, I'd like you to think about some questions before proceeding:

  1. What HTML element would you use as a grouping element? It would be convenient for the users if they could see the name of the group of flashcards (topic name) and could collapse the group up to the title.
  2. What Mavo attribute(s) are you going to add to that element, if any? Will the element be a property or a collection?
  3. Will end users be able to add new topics, delete and rearrange them, change the title of a topic and move flashcards between different topics?

What if you decide not to organize flashcards in groups, but instead just label them with tags that correspond to various topics? Well, that is perfectly fine. The solution with tags is also appropriate. For the sake of practice, try to accomplish that approach too. The mv-bar attribute

See the Pen
05. The mv-bar attribute
by Dmitry Sharabin (@dsharabin)
on CodePen.

As our app stores the data locally, by default, the users of the app won't be able to share their cards with other users. Wouldn't it be great if we would let them export their flashcards and import somebody else's flashcards? Thankfully, these features are already implemented in Mavo, and we can very easily add them to our app!

The mv-bar attribute controls which buttons are going to appear in the toolbar, if any. It’s typically specified on the Mavo root (an element with the mv-app attribute). Buttons are represented by their ids (which are very logical): edit, import, export, etc.

As we only want to add a few buttons to the default set, we can use the so-called relative syntax, which allows us to add and remove buttons from the default set without having to explicitly list everything out. All we need is to start the mv-bar attribute's value with the with keyword.

By doing that, we would get the following:

<main mv-app="flashcards" mv-storage="local" mv-autosave="3" mv-bar="with import export"> ... </main> &#x1f4bb; Let's get our hands dirty!

Give those features a try: add some flashcards, try to export them in a file. Then delete existing flashcards and import the flashcards from the previously exported file.

Expressions and MavoScript

See the Pen
06. Expressions and MavoScript
by Dmitry Sharabin (@dsharabin)
on CodePen.

Let's now add some statistics to our app, such as the number of flashcards! Sounds interesting? I hoped so. &#x1f600;

To do that, we need to learn something new about Mavo.

We can dynamically refer to the value of any property we have defined, anywhere in our Mavo app (including in HTML attributes), by putting its name inside brackets, like this: [propertyName]. This is an example of a simple expression, which allows us to dynamically calculate things, reactively as they change.

&#x1f407; Follow the white rabbit!

Mavo’s expression syntax is called MavoScript. It is similar to spreadsheet formulas and lets us perform computations and other operations (with numbers, texts, lists, etc.), but is designed to be more readable and to accommodate nested relations. You can learn more about Mavo expressions and MavoScript in the documentation.

Now let’s experiment and add a [source] expression inside the flashcard property, e.g., between two properties: the source and the translation.

... <p property="source">Word or phrase</div> [source] <p property="translation">Translation</div> ...

What has changed in our app? The value of the flashcard source property is now shown on the page twice.

Switch to edit mode and try to change the value of the source property. Can you see that? The page content updates while you are changing the property value! That’s why I said earlier that Mavo lets us develop reactive web applications.

That's indeed cool, but unfortunately, in our case, it's not really helpful: we can't use this expression to count the number of flashcards—we would always have only one value.

What if we put the [source] expression outside the flashcard property? We will have something like that:

... [source] <article property="flashcard" mv-multiple> ... </article> ...

How does this differ from the previous case? To see the difference add some flashcards if you haven't done so yet. Now instead of one value we have a list of comma separated values: the source property of all flashcards. That's exactly we were looking for: the number of items in the list corresponds the number of flashcards in the app.

Makes sense? Well, yes, but it wouldn't it be more logical if we would count the number of flashcards, not the number of values of its source property? After all, a flashcard added exists even before we fill in its source or translation. I suggest you do the following: let's substitute the [source] expression with [flashcard]:

... [flashcard] <article property="flashcard" mv-multiple> ... </article> ...

Noticed the difference? We still have a list, but its values are not simple values but objects, i.e., complex values containing all data that pertains to each flashcard. The good news is that the number of these objects is equal to the number of flashcards, since there is one for each flashcard, even when it's completely empty. So, right now we have an object for each flashcard, but how do we count them and display the total count?

Now let's get familiar with the MavoScript functions and find the one that would let us count the number of flashcards. Remember, we have a list of flashcards, so we need to find a function that would let us count the number of items in a list. And here it is—the count() function does exactly that!

But how can we use functions in expressions? Are there any rules we need to be aware of? Well, yes, there is a couple:

  1. Expressions are denoted by brackets.
  2. Do not nest brackets.

Let's try using the count() function to count the number of flashcards:

... [count(flashcard)] <article property="flashcard" mv-multiple> ... </article> ...

And that's exactly what we were aiming for—now we have some statistics in our app! Isn't that cool?

&#x1f4bb; Let's get our hands dirty!

I hope you've already warmed up and ready to continue experimenting with Mavo.

Improve the application so that the statistics are displayed not only for the total number of flashcards in the app but also for the number of flashcards in each topic separately if there are any topics.

&#x1f4a1;Hint!
Want to filter a list based on some criteria? The where operator will help. The self-evaluation feature

We already have an application that lets us create, edit and store multiple flashcards. But how do we keep track of which ones we have already learned and which ones we need to practice more? Any respectable flashcards application needs a self-evaluation feature. Let's investigate how we can add that!

Suppose in our app we have two buttons for the self-evaluation: the Bad and the Good. What exactly do we want to happen every time an end user clicks the buttons? Well, the idea is rather simple:

  • Clicking the Bad button would indicate the user hasn't learned the word yet and we want our app to move the corresponding flashcard to the beginning of the list so they could see it as soon as possible after launching the app.
  • Clicking the Good button would indicate the user has learned the word and the corresponding flashcard needs to move to the end of the list to let them work with other flashcards which they haven't learned yet.

“Are you sure we can do that without JavaScript?” you may ask. Yep! Mavo is extremely powerful and is able to equip us with all the tools we need!

Now when we know what we are going to implement, let's set the UI in place first and then move on to the next step. Our markup would look something like this:

... <article property="flashcard" mv-multiple> ... <section> <h2>Evaluate Yourself</h2> <button>Bad</button> <button>Good</button> </section> </article> ... The mv-action attribute

See the Pen
07. The mv-action attribute
by Dmitry Sharabin (@dsharabin)
on CodePen.

Mavo actions allow us to create our very own controls that modify data in custom ways when the user interacts with them. Sounds promising right?

To define a custom action we need to use the mv-action attribute on an appropriate element inside our Mavo app. The action is performed every time the element is clicked. That’s exactly what we were looking for.

&#x1f407; Follow the white rabbit!

For <form> elements a custom action is performed when the form is submitted.

The value of the mv-action attribute is an expression. We can use any of the expression functions and syntax that MavoScript provides to us, as well as a few more to facilitate data manipulation, such as add(), set(), move(), or delete(). It is important to note that unlike normal expressions which are evaluated reactively, these expressions are only evaluated each time the action is triggered.

&#x1f407; Follow the white rabbit!

Mavo expects the value of the mv-action attribute would be an expression, so there is no need to enclose it in brackets: mv-action="expression". Moreover, if we include them, they will be considered part of the expression.

So, we need to move flashcards inside the collection, and Mavo has an appropriate function that lets us do that—the move() function. Its first argument refers to the item we are moving, and the second is its position in the collection. Bear in mind that elements of the collection are numbered starting from 0.

&#x1f407; Follow the white rabbit!

Want to learn more about the move function (and its variants), and about custom actions in general, see the documentation.

Let's implement the first point of the outline we discussed earlier: while self-evaluating, an end user clicks the Bad button and the corresponding flashcard moves to the beginning of the collection, i.e., it becomes the first one. So in the code, we have:

... <article property="flashcard" mv-multiple> ... <button mv-action="move(flashcard, 0)">Bad</button> ... </article> ...

Pay attention that in the mv-action attribute we refer to the flashcard property inside the property itself, since we want to deal with the current flashcard.

If we try to implement the second point of the outline, we will face a problem. Can you suggest what problem exactly will it be?

Let's remember that if an end user clicks the Good button the corresponding flashcard moves to the end of the collection, i.e., it becomes the last one. To make a flashcard last in the collection we need to know the number of items in it.

Thankfully, a bit earlier we've already solved that task and implemented the corresponding feature. But could we use that solution to solve our current problem? Unfortunately, we can't: as we already know, we can refer to the collection of flashcards by its name (and evaluate its size) only outside the flashcard property. But in our case, we need to do that inside it: the Good button for which we need to write an expression is inside the flashcard property.

What should we do then? I'm glad you ask. Mavo has the solution.

Using the meta element to hold intermediate values

See the Pen
08. The <meta> element
by Dmitry Sharabin (@dsharabin)
on CodePen.

So, on the one hand, we know that the [count(flashcards)] expression gives us the number of flashcards if it is evaluated outside the flashcard property. On the other hand, we need to use that value inside the flashcard property.

To solve that dilemma, we need to evaluate the number of flashcards outside the flashcard property and somehow hold the result to be able to use it elsewhere in the app, precisely inside the flashcard property. For cases like that, in Mavo, there are so-called computed properties.

To hold an intermediate result so we can refer to it, we need an HTML element in our code. It is recommended to use the <meta> element for that purpose, like so: <meta property="propertyName" content="[expression]">. The advantage of using this element is that it is hidden outside edit mode, both semantically and visually.

&#x1f407; Follow the white rabbit!

Bear in mind that computed properties are not saved by default.

Now let's add the flashcardCount computed property in our app. Remember, we must place it outside the flashcard property, but then we can refer to it from anywhere:

... <meta property="flashcardCount" content="[count(flashcard)]"> <article property="flashcard" mv-multiple> ... </article> ...

Only one step left to finish the implementation of the self-evaluation feature: if an end user clicks the Good button the corresponding flashcard moves to the end of the collection, i.e., it becomes the last one. Let's add the relevant action in the code of our app:

... <meta property="flashcardCount" content="[count(flashcard)]"> <article property="flashcard" mv-multiple> ... <button mv-action="move(flashcard, flashcardCount)">Good</button> </article> ...

We are done! Congratulations! &#x1f600;

&#x1f4bb; Let's get our hands dirty!

There is another way to solve that task: with the help of the $all special property. The $all property represents a collection itself if it is placed inside the collection. So there is no need to use any computed property in this case. Try to implement that solution on your own.

There is only one more tiny thing left that we need to fix. Remember the part where we added some stats to our app? Remember the expression we built to evaluate the number of flashcards in the app: [count(flashcard)]? Instead, we can (and should) now use the computed property we defined. Make the appropriate changes in the app. Takeaways

So what have we learned so far? Let's recap. In order to turn any static HTML page into a Mavo app we need to:

  1. Include the Mavo JavaScript and CSS files in the page’s <head> section.
  2. Add the mv-app attribute to the Mavo root element.
  3. Tell Mavo what elements of our app are important by adding the property attribute to them.
  4. Place the mv-multiple attribute on the element that will be multiplied and converted into a collection.
  5. Tell Mavo where to store our data by adding mv-storage attribute to the Mavo root.
  6. Decide whether Mavo should save our data automatically or not. If yes, add the mv-autosave attribute to the Mavo root.

    We also know that:

  7. The Mavo toolbar is fully-customizable. The mv-bar attribute controls which buttons are going to appear there.
  8. Expressions let us present the current value of properties in other elements and perform computations. An expression value (and type) vary depending on the place the expression takes in the code. Mavo’s expression syntax is called MavoScript.
  9. Custom actions allow creating controls that modify data in custom ways. To define a custom action set the mv-action attribute on an appropriate element inside a Mavo app
  10. Properties whose values are expressions are called computed properties. To hold an intermediate result to be able to refer to it elsewhere in the app, it is recommended to use the <meta> element.
Instead of an epilogue

So we built our app. Is it already perfect? Of course not, nothing is! There are so many things that can be improved, and so many features that can be added (with the help of Mavo, we can even make our app multilingual!). Go ahead, enhance it more, don't hesitate to try something new!

What we've learned so far about Mavo is just the tip of the iceberg, and there is so much more. I encourage you to give it a closer look, by reading the documentation, by examining examples (on the Mavo site, or on CodePen: made by Lea Verou and a few made by myself), and by creating new stuff! Good luck! &#x1f609;

Acknowledgments

I want to thank two great people. First of all, my huge thanks go to Lea Verou, who not only inspired me to write this tutorial (and helped me make it happen) but also inspires me all the time by the way she makes the world of web development a better place. I've never met such a gifted human being, and I am happy having an opportunity to make some stuff with her!

I also thank James Moore. The examples he uses in his course "Functional Programming for Beginners with JavaScript” on Udemy pushed me to make my very own version of a flashcard study app. He is a wonderful teacher!

The post Let Mavo Shine in Building Interactive Web Applications appeared first on CSS-Tricks.

Can you nest @media and @support queries?

Css Tricks - Mon, 08/05/2019 - 4:50am

Yes, you can, and it doesn't really matter in what order. A CSS preprocessor is not required. It works in regular CSS.

This works:

@supports(--a: b) { @media (min-width: 1px) { body { background: red; } } }

And so does this, the reverse nesting of the above:

@media (min-width: 1px) { @supports(--a: b) { body { background: green; } } }

You can keep going with the nesting, if it ever makes sense:

@media (min-width: 2px) { @media (min-width: 1px) { @supports (--a: b) { @supports (display: flex) { body { background: pink; } } } } }

There is probably a point where the logic of that gets out of hand, so careful. But hey, it works. Presumably, you can "infinitely" nest at-rules.

To look at nested code like that looks a little like a CSS preprocessor is in use, but that's not the case here. Regular ol' CSS handles this just fine, and in fact, CSS preprocessors don't meaningfully manipulate it at all (tested Sass, Less, and Stylus).

The post Can you nest @media and @support queries? appeared first on CSS-Tricks.

The Real Dark Web

Css Tricks - Mon, 08/05/2019 - 4:50am

Here’s a wonderful reminder from Charlie Owen that everyone in the web design industry isn’t using the latest and greatest technology. And that’s okay! Charlie writes:

Most web developers are working on very "boring" teams. They're producing workhorse products that serve the organisation needs. They aren't trying to innovate. They aren't trying to impress the next recruiter with their CV. They simply want to get paid, produce a solution that works, and go home.

Yet they are told, mostly implicitly, sometimes directly, that if they're not innovating and using the latest tools that they are somehow a failure. This feeling of failure for not implementing the latest tech permeates our industry.

This feeling needs to end.

I feel that this is a big problem for our community because there are a small number of folks on the bleeding edge that happen to be quite loud about their work (even here at CSS-Tricks) – and that’s great! We all need to learn from folks that are doing this work. However, we need to remind ourselves that this is a very small number of folks and not every project has to be a technical marvel to be a success.

Take Michelle Barker's personal site, for example. It's slick but is also dependency-free so she could focus on writing the languages she loves: HTML and CSS. Not a bad goal, nor a bad outcome.

This also harkens back to something Chris mentioned when discussing complexity in web development:

There are more developers these days working on in-house teams or agencies with big-ticket clients. That is, more and more developers on large-scope, long-scale, highly-complex jobs. So that's where their minds are at. Big complicated problems with big complicated solutions. That's what gets talked about. That's what gets blogged about. That's what gets argued about. That's the topic at a lot of conferences I've been to.

While you certainly can make a soup-of-the-day website with an index.html file and FTP, blog posts about that are fewer and farther between and don't get as many claps.

It's not so much that we need cheers to validate our work; it's merely recognizing that not everything has to be on the bleeding edge of technology. There's something to be said about "simple and boring" projects.

Perhaps the real thing to fear is less about what we're sharing and more about what we're not sharing.

Direct Link to ArticlePermalink

The post The Real Dark Web appeared first on CSS-Tricks.

Branching Out from the Great Divide

Css Tricks - Fri, 08/02/2019 - 8:51am

I like the term Front-End Developer. It's encapsulates the nature of your job if your concerns are:

  • Building UIs for web browsers
  • The spectrum of devices and platforms those web browsers run on
  • The people who use those web browsers and related assistive technology

The breadth of knowledge for all-things front-end development has gotten super deep. I've found that front-end developers that have stretched themselves to the point they are thinking of themselves as full-stack developers more and more. I think that's kinda cool and empowering, but it doesn't mean that everyone needs to go that wide.

Brad Frost referred to sides of the spectrum as "back of the front" and "front of the front." I once drew the line, in The Great Divide, as heavy JavaScript vs. not. These distinctions aren't to divide people, but to acknowledge the spectrum and that there are people all over it.

In a new article called "Frontend Design, React, and a Bridge over the Great Divide," Brad makes the point that the role of "Front-End Designer" exists on the spectrum right smack in the middle between design and development, where "development" refers to the back-end or deeper JavaScript stuff.

The jobs?

  • Crafting semantic HTML markup
  • Creating CSS code
  • Authoring JavaScript that primarily manipulates objects in the DOM
  • Testing across browsers and devices
  • Optimizing the performance of front-end code
  • Working with designers
  • Working with back-end and application developers

That sounds like the "traditional" explanation of a front-end developer to me — if there is such a thing — but it makes sense to rename that role since front-end development is the term that got so wide.

Brad adds these responsibilties to the list:

  • Create a library of presentational UI components
  • Author and document a robust, intuitive component API for each presentational component
  • Determine how flexible or rigid the component library should be
  • Maintain the presentational components as a product

That's where I think this metaphor comes in:

Me, Brad and a slew of you out there are front-end developers. We work in browsers and we care about the users and where and how they interact with those browsers. We do the things on Brad's first list like craft HTML and CSS, work with designs and do testing. We share that common trunk of skills on the tree above.

But Brad is more of a systems designer than I am. His dot lands somewhere differently on that tree. I don't know if I'm particularly skilled at anything, but my dot definitely falls elsewhere on that tree. Perhaps on an entirely different branch, as I quite like working with JavaScript tooling and logic and APIs and such. The bulk of Brad's article is about React and finding a place in the realm of front-end development where the job isn't ignoring React, but working with it in such a way that doesn't mean every other aspect of development doesn't have to come along for the ride.

The post Branching Out from the Great Divide appeared first on CSS-Tricks.

Using Netlify Forms and Netlify Functions to Build an Email Sign-Up Widget

Css Tricks - Fri, 08/02/2019 - 4:13am

Building and maintaining your own website is a great idea. Not only do you own your platform, but you get to experiment with web technologies along the way. Recently, I dug into a concept called serverless functions, starting with my own website. I’d like to share the results and what I learned along the way, so you can get your hands dirty, too!

But first, a 1-minute intro to serverless functions

A serverless function (sometimes called a lambda function or cloud function) is a piece of code that you can write, host, and run independently of your website, app, or any other code. Despite the name, serverless functions do, indeed, run on a server; but it’s a server you don’t have to build or maintain. Serverless functions are exciting because they take a lot of the legwork out of making powerful, scalable, apps.

There’s lots of great information on serverless functions out there, and a great place to start is CSS Trick’s own guide: The Power of Serverless Front-End Developers.

The Challenge: Build a Mailing List Sign Up Form

I started my journey with a challenge: I wanted to have an email list sign-up form on my site. The rules are as follows:

  • It should work without JavaScript. I’d like to see how much I can get by with just CSS and HTML. Progressive enhancements are OK.
  • It shouldn’t require external dependencies. This is a learning project, so I want to write 100% of the code if possible.
  • It should use serverless functions. Instead of sending data to my email list service client-side, let’s do it server(less)-side!
Meet the team: 11ty, Netlify, and Buttondown

My website is built using a static site framework called 11ty. 11ty allows me to write templates and components in HTML, so that’s how we’ll build our email form. (Chris recently wrote a great article about his experience with 11ty if you’re interested in learning more.)

The website is then deployed using a service called Netlify) and it is the key player on our team here: the point guard, the quarterback, the captain. That’s because Netlify has three features that work together to produce serverless excellence:

  • Netlify can deploy automatically from a GitHub repo. This means I can write my code, create a pull request, and instantly see if my code works. While there are tools to test serverless functions locally, Netlify makes it super easy to test live.
  • Netlify Forms handles any form submissions my site gets. This is one part of the serverless equation: instead of writing code to collect submissions, I’ll configure the HTML with a few simple attributes and let Netlify handle the rest.
  • Netlify Functions allows me to take action with the data from my forms. I’ll write some code to send emails off to my email list provider, and tell Netlify when to run that code.

Finally, I’ll manage my email list with a service called Buttondown. It’s a no-frills email newsletter provider, with an easy-to-use API.

Bonus: for personal sites like mine, 11ty, Netlify, and Buttondown are free. You can’t beat that.

The form

The HTML for my email subscription form is very minimal, with a few extras for Netlify Forms to work.

<form class="email-form" name="newsletter" method="POST" data-netlify="true" netlify-honeypot="bot-field"> <div hidden aria-hidden="true"> <label> Don’t fill this out if you're human: <input name="bot-field" /> </label> </div> <label for="email">Your email address</label> <div> <input type="email" name="email" placeholder="Email" id="email" required /> <button type="submit">Subscribe</button> </div> </form>

First, I set the data-netlify attribute to true to tell Netlify to handle this form.

The first input in the form is named bot-field. This tricks robots into revealing themselves: I tell Netlify to watch for any suspicious submissions by setting the netlify-honeypot attribute to bot-field. I then hide the field from humans using the html hidden and aria-hidden values — users with and without assistive technology won’t be able to fill out the fake input.

If the form gets submitted with anything in the bot-field input, Netlify knows it’s coming from a robot, and ignores the input. In addition to this layer of protection, Netlify automatically filters suspicious submissions with Askimethttps://www.netlify.com/blog/2019/02/12/improved-netlify-forms-spam-filtering-using-akismet/). I don’t have to worry about spam!

The next input in the form is named email. This is where the email address goes! I’ve specified the input-type as email, and indicated that is required; this means that the browser will do all my validation for me, and won’t let users submit anything other than a valid email address.

Progressive enhancement with JavaScript

One neat feature of Netlify Forms is the ability to automatically redirect users to a “thank you” page when they submit a form. But ideally, I’d like to keep my users on the page. I wrote a short function to submit the form without a redirect.

const processForm = form => { const data = new FormData(form) data.append('form-name', 'newsletter'); fetch('/', { method: 'POST', body: data, }) .then(() => { form.innerHTML = `<div class="form--success">Almost there! Check your inbox for a confirmation e-mail.</div>`; }) .catch(error => { form.innerHTML = `<div class="form--error">Error: ${error}</div>`; }) }

When I provide the content of my email form to this function via the form value, it submits the form using JavaScript’s built-in Fetch API. If the function was successful, it shows a pleasant message to the user. If the function hits a snag, it’ll tell my users that something went wrong.

This function is called whenever a user clicks the “submit” button on the form:

const emailForm = document.querySelector('.email-form') if (emailForm) { emailForm.addEventListener('submit', e => { e.preventDefault(); processForm(emailForm); }) }

This listener progressively enhances the default behavior of the form. This means that if the user has JavaScript disabled, the form still works!

The serverless function

Now that we have a working email submission form, it’s time to do some automation with a serverless function.

The way Netlify functions work is as follows:

  1. Write the function in a JavaScript file in your project.
  2. Tell Netlify where to look for your function via the netlify.toml file in your project.
  3. Add any environment variables you’ll need via Netlify’s admin interface. An environment variable is something like an API key that you need to keep secret.

That’s it! The next time you deploy your site, the function will be ready to go.

The function for my site is going to be in the functions folder, so I have the following in my netlify.toml file:

[build] base = "." functions = "./functions"

Then, I’ll add a file in the functions folder called submission-created.js. It’s important to name the file submission-created so that Netlify knows to run it every time a new form submission occurs. A full list of events you can script against can be found in Netlify’s documentation. If you’ve correctly named and configured your function, you should see it on Netlify’s Functions dashboard:

Netlify’s Functions dashboard shows I’ve correctly configured my submission-created function

The content in submission-created.js looks like this:

require('dotenv').config() const fetch = require('node-fetch') const { EMAIL_TOKEN } = process.env exports.handler = async event => { const email = JSON.parse(event.body).payload.email console.log(`Recieved a submission: ${email}`) return fetch('https://api.buttondown.email/v1/subscribers', { method: 'POST', headers: { Authorization: `Token ${EMAIL_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ email }), }) .then(response => response.json()) .then(data => { console.log(`Submitted to Buttondown:\n ${data}`) }) .catch(error => ({ statusCode: 422, body: String(error) })) }

Let’s look at this line-by-line.

Line 1 includes a library called dotenv. This will help me use environment variables. Environment variables are useful to hold information that I don’t want to make public, like an API key. If I’m running my project locally, I set my environment variables with a .env file in the repo, and make sure it’s listed my .gitignore file. In order to deploy on Netlify, I also set up environment variables in Netlify’s web interface.

On line 2, I add a small library called node-fetch. This allows me to use Javascript’s Fetch API in node, which is how we’ll send data to Buttondown. Netlify automatically includes this dependency, as long as it’s listed in my project’s package.json file.

On line 3, I import my API key from the environment variables object, process.env.

Line 4 is where the function is defined. The exports.handler value is where Netlify expects to find our function, so we define it there. The only input we’ll need is the event value, which will contain all of the data from the form submission.

After retrieving the email address from the event value using JSON.parse, I’m ready to send it off to Buttondown. Here’s where I use the node-fetch library I imported earlier: I send a POST request to https://api.buttondown.email/v1/subscribers, including my API key in the header. Buttondown’s API doesn’t have many features, so it doesn’t take long to read through the documentation if you’d like to learn more.

The body of my POST request consists of the email address we retrieved.

Then (using the neat .then() syntax), I collect the response from Buttondown’s server. I do this so I can diagnose any issues that are happening with the process — Netlify makes it easy to check your function’s logs, so use console.log often!

Deploying the function

Now that I’ve written my function, configured my netlify.toml file, and added my environment variables, everything is ready to go. Deploying is painless: just set up Netlify’s GitHub integration, and your function will be deployed when your project is pushed.

Netlify projects can also be tested locally using Netlify Dev. Depending on the complexity of your code, it can be faster to develop locally: just run npm i netlify -g, then netlify dev. Netlify Dev will use the netlify.toml file to configure and run the project locally, including any serverless functions. Neat, right? One caveat: Netlify Dev currently can’t trigger serverless functions on form submissions, so you’ll have to test that using preview builds.

An idea for the future

Buttondown’s API has a few possible responses when I submit a new email. For instance, if a user submits an email that’s already subscribed to the list, I’d love to be able to tell them as soon as they submit the form.

Conclusion

All in all, I only had to write about 50 lines of code to have a functional email newsletter sign-up form available on my website. I wrote it all in HTML, CSS, and JavaScript, without having to fret with the server side of the equation. The form handles spam, and my readers get a nice experience whether they have JavaScript enabled or not.

The post Using Netlify Forms and Netlify Functions to Build an Email Sign-Up Widget appeared first on CSS-Tricks.

Weekly Platform News: Preventing Image Loads with the Picture Element, the Web We Want, Svg Styles Are Not Scoped

Css Tricks - Thu, 08/01/2019 - 11:07am

In this week's week roundup of browser news, a trick for loading images conditionally using the picture element, your chance to tell bowser vendors about the web you want, and the styles applied to inline SVG elements are, well, not scoped only to that SVG.

Let's turn to the headlines...

Preventing image loads with the picture element

You can use the <picture> element to prevent an image from loading if a specific media query matches the user’s environment (e.g., if the viewport width is larger or smaller than a certain length value). [Try out the demo:

See the Pen
voZENR
by Šime Vidas (@simevidas)
on CodePen.

<picture> <!-- show 1?1 transparent image if viewport width ? 40em --> <source media="(max-width: 40em)" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /> <!-- load only image if viewport width > 40em --> <img src="product-large-screen.png" /> </picture>

(via Scott Jehl)

The Web We Want

The Web We Want (webwewant.fyi) is a new collaboration between browser vendors that aims to collect feedback from web developers about the current state of the web. You can submit a feature request on the website ("What do you want?"") and get a chance to present it at an event (An Event Apart, Smashing Conference, etc.).

(via Aaron Gustafson)

In other news
  • Firefox supports a non-standard Boolean parameter for the location.reload method that can be used to hard-reload the page (bypassing the browser’s HTTP cache) [via Wilson Page]
  • If you use inline <svg> elements that itself have inline CSS code (in <style> elements), be aware that those styles are not scoped to the SVG element but global, so they affect other SVG elements as well [via Sara Soueidan]
  • XSS Auditor, a Chrome feature that detects cross-site scripting vulnerabilities, has been deemed ineffective and will be removed from Chrome in a future version. You may still want to set the HTTP X-Xss-Protection: 1; mode=block header for legacy browsers [via Scott Helme]

Read more news in my new, weekly Sunday issue. Visit webplatform.news for more information.

The post Weekly Platform News: Preventing Image Loads with the Picture Element, the Web We Want, Svg Styles Are Not Scoped appeared first on CSS-Tricks.

Making a Realistic Glass Effect with SVG

Css Tricks - Thu, 08/01/2019 - 4:27am

I’m in love with SVG. Sure, the code can look dense and difficult at first, but you’ll see the beauty in the results when you get to know it. The bonus is that those results are in code, so it can be hooked up to a CMS. Your designers can rest easy knowing they don't have to reproduce an effect for every article or product on your site.

Today I would like to show you how I came up with this glass text effect.

Step 0: Patience and space

SVG can be a lot to take on, especially when you’re just starting to learn it (and if you are, Chris’ book is a good place to start). It’s practically a whole new language and, especially for people who lack design chops, there are lots of new techniques and considerations to know about. Like HTML, though, you’ll find there are a handful of tools that we can reach for to help make SVG much easier to grasp., so be patient and keep trying!

Also, give yourself space. Literally. SVG code is dense so I like to use two or three new lines to space things out. It makes the code easier to read and helps me see how different pieces are separated with less visual distraction. Oh, and use comments to mark where you are in the document, too. That can help organize your thoughts and document your findings.

I’ve made demos for each step we’re going to cover in the process of learning this glass effect as a way to help solidify the things we’re covering as we go.

OK, now that we’re mentally prepared, let’s get into the meat of it!

Step 1: Get the basic image in place

First things first: we need an image as the backdrop for our glass effect. Here we have an <svg> element and an <image> within it. This is similar to adding an <img> in HTML. You’ll notice the dimensions of the viewBox attribute and <image> element in the SVG element are the same. This ensures that the <image> is exactly the same size as the actual picture we’re linking to.

That’s a key distinction to note: we’re linking to an image. The SVG file itself does not draw a raster image, but we can reference one in the SVG code and make sure that asset is in the location we point to. If you’ve worked with Adobe InDesign before, it’s a lot like linking to an image asset in a layout — the image is in the InDesign layout, but the asset itself actually lives somewhere else.

See the Pen
SVG Glass Text Effect - basic image in place
by David Fitzgibbon (@loficodes)
on CodePen.

Step 2: Distort the image

Straightforward so far, but this is where things get complicated because we’re going to add a filter to the image we just inserted. This filter is going to distort the image. If you look closely at the difference between the demo in the last step and the one in this step, you’ll see that the edges of objects in the image are a little rough and wavy. That’s the filter at work!

First, we create another <svg> to hold filter. This means that if we ever want to reuse our filter — for example on multiple elements on the page — then we totally can!

Our first filter (#displacement) is going to distort our image. We’re going to use feTurbulence and feDisplacementMap, each explained by Sara Soueidan much better than I can in this post. Beau Jackson also wrote up a nice piece that shows how they can be used to make a cloud effect. Suffice to say, these two filters tend to go together and I like to think of them as when something needs to appear "wobbly."

With our filter container in place, we just need to apply that filter to our image with a filter attribute on the <image>, magic!

<svg> <!-- more stuff --> <!-- DISTORTION IMAGE: clipped --> <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 clip-path="url(#clip)" filter= "url(#distortion)"></image> <!-- FILTER: wobbly effect --> <filter id="distortion"> <feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="2" result="turbulence"/> <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="20" xChannelSelector="R" yChannelSelector="G"/> </filter> <!-- more stuff --> </svg>

See the Pen
SVG Glass Text Effect - image distorted
by David Fitzgibbon (@loficodes)
on CodePen.

Step 3: Clip the text

We don’t want the entire image to be distorted though. We’re going to clip the shape of our distorted <image> to the shape of some text. This will essentially be the portion of the picture seen "through" the glass.

To do this, we need to add a <text> element in a <clip-path> and give it an id. Calling this id in the clip-path of our <image> now restricts its shape to that of our <text>. Wonderful!

See the Pen
SVG Glass Text Effect - text clipped
by David Fitzgibbon (@loficodes)
on CodePen.

Step 4: Reveal the full image

OK, so it’s bueno that we have the distorted <image> clipped to the <text>, but now the rest of the image is gone. No bueno.

We can counteract this by adding a copy of the same <image> but without the clip-path or filter attributes before our existing <image>. This is where I like to add some nice comments to keep things neat. The idea is like placing a transparent layer over what we have so far.

I know, I know, this isn’t very neat, and we’re repeating ourselves. Ideally, we would set our filter straight on the <text> element and use the in="BackgroundImage property for feDisplacementMap to warp what’s behind the text, without the need for extra elements. Unfortunately, this has poor browser support, so we’re going to go with multiple images.

<svg> <!-- more stuff --> <!-- BACKGROUND IMAGE - visible --> <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 ></image> <!-- DISTORTION IMAGE - clipped --> <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 clip-path="url(#clip)" filter= "url(#distortion)"></image> <!-- more stuff --> </svg>

See the Pen
SVG Glass Text Effect - warp complete
by David Fitzgibbon (@loficodes)
on CodePen.

Step 5: Place the text... again

Next, we’re going to duplicate our text just as we did for the image in the last step. Unfortunately, because the text is in a clip-path, it’s now not available for rendering. This is the last time we’re going to duplicate content like this, I promise!

Now we should have something that looks like a normal image with black text over it. If the distortion filter on the <image> we’ve already made is what we can see "through" the glass, then our new <text> is going to be the glass itself.

<svg> <!-- more stuff --> <!-- TEXT - clipped --> <clipPath id="clip"> <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle">KYOTO</text> </clipPath> <!-- TEXT - visible --> <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle">KYOTO</text> <!-- more stuff --> </svg>

See the Pen
SVG Glass Text Effect - text in place again
by David Fitzgibbon (@loficodes)
on CodePen.

Step 6: Creating the dark edge of the text

This is where things start to get exciting, at least for me! &#x1f913;

We want to create a dark edge along the text element which, when paired with a light edge (we’ll look at that next), will add depth to the appearance of the text against the image.

We want a new filter for our <text>, so let’s create one in our filter's SVG element and give it an id="textFilter and link it to the filter attribute of the <text> element.

SVG works from the background to the foreground, so the first thing we’re going put in our filter is the shadow that the glass would have, as that is furthest back. I’m gonna level with you, this one is pretty complex, but we’re going to go through it one step at a time.

For this effect, we’re using four filter primitives: feMorphology, feOffset, feFlood and feComposite.

feMorphology is first. We’re using this to make the text fatter. In the demo below, comment out the next three primitives ( feOffset, feFlood, feComposite ) and play with it. I have the value radius="4" to achieve the glass effect, but see what happens if you set it to 1... or 100!

feOffset is used to move all the "pixels" in the previous primitive ( feMorphology ) across the x- or y-axis. The values dx="5" and dy="5" move the "pixels" right on the x-axis and y-axis, respectively. The higher the number, the further they move. Put in negative numbers for dx and the "pixels" will move left. Negative dy and they’ll move up! Again, the is the sort of thing you start to learn as you play around with them.

The reason I have quotes around "pixels" is because they’re not screen pixels like you might expect in CSS. Rather, they refer to the dimensions we set on the parent <svg>. I think of them as percentages. We have used these settings viewBox="0 0 1890 1260" in our example. This means our <svg> is 1890 "pixels" wide. If we set dx="189" it means we’ll move our element 10% of the way across the SVG (1890 divided by 189).

feFlood is great. If you want to fill the screen with color, this is the primitive you need! You might wonder why we can’t read our text now when we apply it. That’s because you can only see the result of the last filter primitive that was created. The result of each of the previous primitives was related to our <text> element. The result of feFlood is just like its name: a flood of color. It doesn't know what you did before and it doesn't care — it’s merely going to fill an area with color.

This is where some people start getting frustrated with SVG. It’s hard to work on something when you can’t see it! Trust me, as you work with SVG more you’ll get used to this. In fact, the next few steps will need us to rely on this and trust that everything is still in place.

feComposite is going to solve this issue for us. What does it do? MDN describes it as:

The SVG filter primitive performs the combination of two input images pixel-wise in image space using one of the Porter-Duff compositing operations: over, in, atop, out, xor, and lighter.

That to me is jibba-jabba. I think of it as affecting the alpha layer of in with the color/alpha of in2.

With this in place we can once again see our text spelled out and, because the color we used is slightly transparent, we can even see the distorted "glass" effect coming through. Great!

<svg> <!-- more stuff --> <!-- dark edge --> <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="dark_edge_01" /> <feConvolveMatrix order="3,3" kernelMatrix= "1 0 0 0 1 0 0 0 1" in="dark_edge_01" result="dark_edge_02" /> <feOffset dx="5" dy="5" in="dark_edge_02" result="dark_edge_03"/> <feFlood flood-color="rgba(0,0,0,.5)" result="dark_edge_04" /> <feComposite in="dark_edge_04" in2="dark_edge_03" operator="in" result="dark_edge" /> </filter> <!-- more stuff --> </svg>

See the Pen
SVG Glass Text Effect - dark edge
by David Fitzgibbon (@loficodes)
on CodePen.

Step 7: Let’s do the light edge

This is essentially the same as what we literally just did, but we’re going to shift the shape up and to the left using negative dx/dy values. We’re also setting a slightly white color this time. We’re aiming for a nice depth effect.

We’re again in a position where what we can see is the most recent result from a filter primitive, but we can’t see our dark edge! feComposite isn't what we want to use to bring them together because we don't want the alpha of the dark edge colored by the light edge… we want to see both! Which leads us to…

<svg> <filter id="textFilter"> <!-- more stuff --> <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="light_edge_01" /> <feConvolveMatrix order="3,3" kernelMatrix= "1 0 0 0 1 0 0 0 1" in="light_edge_01" result="light_edge_02" /> <feOffset dx="-2" dy="-2" in="light_edge_02" result="light_edge_03"/> <feFlood flood-color="rgba(255,255,255,.5)" result="light_edge_04" /> <feComposite in="light_edge_04" in2="light_edge_03" operator="in" result="light_edge" /> <!-- more stuff --> </filter> </svg>

See the Pen
SVG Glass Text Effect - light edge
by David Fitzgibbon (@loficodes)
on CodePen.

Step 8: Combine the edges

feMerge! It’s a hero. It lets us take any number of primitive results and merge them, making a new image. Woohoo, we can now see both dark and light edges together!

However, we do want them to be edges rather than both filling up the entire text, so we need to remove the space that the original <text> takes up. What we need next is another feComposite to chop out the original SourceGraphic. Because we used feMorphology to fatten the letters for our edges, we can now chop the original letter shapes out of the result of our feMerge.

<svg> <filter id="textFilter"> <!-- more stuff --> <feMerge result="edges"> <feMergeNode in="dark_edge" /> <feMergeNode in="light_edge" /> </feMerge> <feComposite in="edges" in2="SourceGraphic" operator="out" result="edges_complete" /> </filter> </svg>

See the Pen
SVG Glass Text Effect - edges combined
by David Fitzgibbon (@loficodes)
on CodePen.

Now we’re starting to look like glass, with just one piece missing.

Step 9: Yes, a bevel

We have a pretty good 3D-looking glass effect. However, the letters look flat. Let’s add one more effect and make them look more rounded.

To achieve this we’re going to create a bevelled effect.

First we’re going to use feGaussianBlur. This will blur our existing filters slightly. We’re going to use this blurred result as basis to add some feSpecularLighting. As usual, feel free to play with the numbers here and see what effects you can get! The main one you might want to change is the lighting-color attribute. The image that we’re using here is slightly dark, so we’re using a bright lighting-color. If your image was very bright, this would make the letters hard to read, so you might use a darker lighting-color in that case.

<svg> <filter id="textFilter"> <!-- more stuff --> <feGaussianBlur stdDeviation="5" result="bevel_blur" /> <feSpecularLighting result="bevel_lighting" in="bevel_blur" specularConstant="2.4" specularExponent="13" lighting-color="rgba(60,60,60,.4)"> <feDistantLight azimuth="25" elevation="40" /> </feSpecularLighting> <feComposite in="bevel_lighting" in2="SourceGraphic" operator="in" result="bevel_complete" /> </filter> </svg>

See the Pen
SVG Glass Text Effect - bevel
by David Fitzgibbon (@loficodes)
on CodePen.

Step 10: All together now!

Finally, with all the pieces ready, we do one last feMerge to get everything in place for the finished effect!

<svg> <filter id="textFilter"> <!-- more stuff --> <feMerge result="complete"> <feMergeNode in="edges_complete" /> <feMergeNode in="bevel_complete" /> </feMerge> </filter> </svg>

Here’s everything together, nicely spaced out and commented:

<!-- VISIBLE SVG --> <svg viewBox="0 0 1890 1260"> <!-- BACKGROUND IMAGE - visible --> <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 ></image> <!-- DISTORTION IMAGE - clipped --> <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 clip-path="url(#clip)" filter= "url(#distortion)"></image> <!-- TEXT - clipped --> <clipPath id="clip"> <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle">KYOTO</text> </clipPath> <!-- TEXT - visible --> <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle" filter="url(#textFilter)">KYOTO</text> </svg> <!-- FILTERS --> <svg> <filter id="distortion"> <feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="2" result="turbulence"/> <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="20" xChannelSelector="R" yChannelSelector="G"/> </filter> <filter id="textFilter"> <!-- dark edge --> <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="dark_edge_01" /> <feOffset dx="5" dy="5" in="dark_edge_01" result="dark_edge_03"/> <feFlood flood-color="rgba(0,0,0,.5)" result="dark_edge_04" /> <feComposite in="dark_edge_04" in2="dark_edge_03" operator="in" result="dark_edge" /> <!-- light edge --> <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="light_edge_01" /> <feOffset dx="-2" dy="-2" in="light_edge_01" result="light_edge_03"/> <feFlood flood-color="rgba(255,255,255,.5)" result="light_edge_04" /> <feComposite in="light_edge_04" in2="light_edge_03" operator="in" result="light_edge" /> <!-- edges together --> <feMerge result="edges"> <feMergeNode in="dark_edge" /> <feMergeNode in="light_edge" /> </feMerge> <feComposite in="edges" in2="SourceGraphic" operator="out" result="edges_complete" /> <!-- bevel --> <feGaussianBlur stdDeviation="5" result="bevel_blur" /> <feSpecularLighting result="bevel_lighting" in="bevel_blur" specularConstant="2.4" specularExponent="13" lighting-color="rgba(60,60,60,.4)"> <feDistantLight azimuth="25" elevation="40" /> </feSpecularLighting> <feComposite in="bevel_lighting" in2="SourceGraphic" operator="in" result="bevel_complete" /> <!-- everything in place --> <feMerge result="complete"> <feMergeNode in="edges_complete" /> <feMergeNode in="bevel_complete" /> </feMerge> </filter> </svg>

See the Pen
SVG Glass Text Effect
by David Fitzgibbon (@loficodes)
on CodePen.

The post Making a Realistic Glass Effect with SVG appeared first on CSS-Tricks.

Register Now for An Event Apart 2019 in Chicago

Css Tricks - Thu, 08/01/2019 - 4:23am

(This is a sponsored post.)

An Event Apart juuuuust wrapped up its Washington D.C. event yesterday. We hope we got to see you at the event but if not, perhaps we'll see you at the next one happening Aug. 28-28 in Chicago.

Why would you go, you might ask? It's three days of experts imparting their knowledge on topics ranging from CSS Houdini to intrinsic layouts — and that's just the first day!

Seriously, there are lot of reasons why you'd want to go. The speakers are top-notch, the opportunities to network with others will be aplenty and you'll be upping your front-end development chops the entire time. Not a bad collection of perks, for sure.

The time to register is now and, when you do, use coupon code AEACP at checkout and get $100 off the price!

Register Today

Direct Link to ArticlePermalink

The post Register Now for An Event Apart 2019 in Chicago appeared first on CSS-Tricks.

Fetching Data in React using React Async

Css Tricks - Wed, 07/31/2019 - 1:03pm

You’re probably used to fetching data in React using axios or fetch. The usual method of handling data fetching is to:

  • Make the API call.
  • Update state using the response if all goes as planned.
  • Or, in cases where errors are encountered, an error message is displayed to the user.

There will always be delays when handling requests over the network. That’s just part of the deal when it comes to making a request and waiting for a response. That’s why we often make use of a loading spinner to show the user that the expected response is loading.

See the Pen
ojRMaN
by Geoff Graham (@geoffgraham)
on CodePen.

All these can be done using a library called React Async.

React Async is a promised-based library that makes it possible for you to fetch data in your React application. Let’s look at various examples using components, hooks and helpers to see how we can implement loading states when making requests.

For this tutorial, we will be making use of Create React App. You can create a project by running:

npx create-react-app react-async-demo

When that is done, run the command to install React Async in your project, using yarn or npm:

## yarn yarn add react-async ## npm npm install react-async --save Example 1: Loaders in components

The library allows us to make use of <Async> directly in our JSX. As such, the component example will look like this;

// Let's import React, our styles and React Async import React from 'react'; import './App.css'; import Async from 'react-async'; // We'll request user data from this API const loadUsers = () => fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()) // Our component function App() { return ( <div className="container"> <Async promiseFn={loadUsers}> {({ data, err, isLoading }) => { if (isLoading) return "Loading..." if (err) return `Something went wrong: ${err.message}` if (data) return ( <div> <div> <h2>React Async - Random Users</h2> </div> {data.map(user=> ( <div key={user.username} className="row"> <div className="col-md-12"> <p>{user.name}</p> <p>{user.email}</p> </div> </div> ))} </div> ) }} </Async> </div> ); } export default App;

First, we created a function called loadUsers. This will make the API call using the fetch API. And, when it does, it returns a promise which gets resolved. After that, the needed props are made available to the component.

The props are:

  • isLoading: This handles cases where the response has not be received from the server yet.
  • err: For cases when an error is encountered. You can also rename this to error.
  • data: This is the expected data obtained from the server.

As you can see from the example, we return something to be displayed to the user dependent on the prop.

Example 2: Loaders in hooks

If you are a fan of hooks (as you should), there is a hook option available when working with React Async. Here’s how that looks:

// Let's import React, our styles and React Async import React from 'react'; import './App.css'; import { useAsync } from 'react-async'; // Then we'll fetch user data from this API const loadUsers = async () => await fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()) // Our component function App() { const { data, error, isLoading } = useAsync({ promiseFn: loadUsers }) if (isLoading) return "Loading..." if (error) return `Something went wrong: ${error.message}` if (data) // The rendered component return ( <div className="container"> <div> <h2>React Async - Random Users</h2> </div> {data.map(user=> ( <div key={user.username} className="row"> <div className="col-md-12"> <p>{user.name}</p> <p>{user.email}</p> </div> </div> ))} </div> ); } export default App;

This looks similar to the component example, but in this scenario, we’re making use of useAsync and not the Async component. The response returns a promise which gets resolved, and we also have access to similar props like we did in the last example, with which we can then return to the rendered UI.

Example 3: Loaders in helpers

Helper components come in handy in making our code clear and readable. These helpers can be used when working with an useAsync hook or with an Async component, both of which we just looked at. Here is an example of using the helpers with the Async component.

// Let's import React, our styles and React Async import React from 'react'; import './App.css'; import Async from 'react-async'; // This is the API we'll use to request user data const loadUsers = () => fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()) // Our App component function App() { return ( <div className="container"> <Async promiseFn={loadUsers}> <Async.Loading>Loading...</Async.Loading> <Async.Fulfilled> {data => { return ( <div> <div> <h2>React Async - Random Users</h2> </div> {data.map(user=> ( <div key={user.username} className="row"> <div className="col-md-12"> <p>{user.name}</p> <p>{user.email}</p> </div> </div> ))} </div> ) }} </Async.Fulfilled> <Async.Rejected> {error => `Something went wrong: ${error.message}`} </Async.Rejected> </Async> </div> ); } export default App;

This looks similar to when we were making use of props. With that done, you could break the different section of the app into tiny components.

Conclusion

If you have been growing weary of going the route I mentioned in the opening section of this tutorial, you can start making of React Async in that project you are working on. The source code used in this tutorial can be found in their different branches on GitHub.

The post Fetching Data in React using React Async appeared first on CSS-Tricks.

Bringing CSS Grid to WordPress Layouts

Css Tricks - Wed, 07/31/2019 - 4:26am

December 6th, 2018 was a special date for WordPress: it marked the release of version 5.0 of the software that, to this day, powers more than one-third of the web. In the past, people working on the platform pointed out that there has never been any special meaning to version numbers used in WordPress releases; as such, WordPress 5.0 was simply the follower to WordPress 4.9. Yet, 5.0 brought possibly the biggest innovation since Custom Post Types were introduced in version 3.0 – that's almost a decade, folks.

The Block Editor — codename "Gutenberg" — is now the new default writing tool in WordPress. Before its adoption in Core, our beloved CMS has relied on what we now call the Classic Editor. And, by the way, the Classic Editor isn't really gone: you can bring it back by installing a plugin that restores the default editing experience you've known all these years.

So, why was the Classic Editor replaced? Essentially because it embodied an old concept of writing, a concept that was conceived when the only need of a text editor was to visually compose HTML code.

Not to create layouts. Not to embed dynamic content form heterogeneous sources. Not to offer a representation of what your post or page would look like when you pressed that "Publish" button, and go live with your piece of content.

In short, the Classic Editor delivered a very basic writing experience and, frankly, it always fell short at creating anything more than flowing text.

The Block Editor is based on the idea of content "blocks" in the sense that everything we can add to a page — a text paragraph, an image, an embed — is technically a block, that is, an atomic entity that's defined by a certain series of properties. The combination of these properties determines the state of that particular block. Combine several blocks one after the other, and you'll get the content of your page.

In this transition from unorganized text to rigorous content structure lies the biggest change introduced by the Block Editor.

Layouts pre-Block Editor

Before all of this bursted into existence, people who wanted to create a layout within WordPress had to choose between either of these options:

  1. Create a custom template from scratch, getting their hands dirty with code – a noble intent, yet not so appealing to the masses.
  2. Use a tool, better if a visual one, that helped them composing a page structure without having much code knowledge.

That's how page builders were born: page builders are plugins that provide a visual way to compose a layout, ideally without touching a single line of code, and they were created out of necessity to fill a gap between visual mockups and the actual, finished website.

Page builders have always suffered from a bad reputation, for a variety of reasons:

  1. They tend to be slow and bulky.
  2. Some offer poor editing experiences.
  3. They end up locking users into a framework or ecosystem that's tough to replace.

The first point is as obvious as it is unavoidable: if you're a page builder author (and, hopefully, aspire to sell copies of your product), you have to make it as appealing as possible; physiologically, builders started to slowly become big code soups with everything in them, at the detriment of performance.

The second point may be subjective, at least to to some extent. The third point, however, is a fact. Sure, one could be perfectly fine using the same tool for every project, perfecting knowledge of the instrument as time goes by, but the more you stick to it, the harder it gets to potentially stop using it one day.

The Block Editor aims to surpass this deadlock: from the user's point of view, it aims at offering a better, richer writing experience, while, from the developer's perspective, providing a unified, shared API from which to build upon.

A brief history of CSS layouts

If you're old enough, you'll probably know the story already. If not, it might be fun for you to hear what life was like for a front-end developer back in the day.

The first version of the CSS specification dates back to 1996, and it allowed an embedded stylesheet to add font styling, pick colors for elements, change the alignments and spacing of objects in the page. The problem was that, in those days, the concept of semantic HTML wasn't exactly widespread. In other words, there was no clear separation between content and form. The markup we'd write and the appearance we want were completely intertwined in the same document.

This led to HTML elements to be used more for presentation purposes, than conveying meaning to their presence in the page. For example, on the layout side of things, this also led to to table elements being used to create layouts instead of actual tabular data. To achieve even more complex layouts, tables began being nested into other tables, making the page become a nightmare from the semantic point of view, its size grow and grow, and resulting very hard to maintain over time. If you've ever coded an HTML email, then you have a good idea of what life was like. And, really, this still sort of happens in websites today, even if it's for smaller elements rather than complete page layouts.

Then the Web Standards movement came along with the goal to raise awareness among developers that we could be doing things differently and better; that style and content should be separated, that we need to use HTML elements for their meaning, and reinforcing the concept that a lighter page (in terms of code weight) is a fundamentally better option than an unmanageable ocean of nested tables.

We then began (over)using div elements, and juxtaposed them using the float property. The presentation focus was shifted from the markup to the stylesheet. Floats became the most reliable layout tool available for years, yet they can be a bit problematic to handle, since they have to be cleared in order for the page to return to its standard flow. Also, in this age, page markups were still too redundant, even though using divs instead of tables helped make our content more accessible.

The turnaround moment came in 2012, with the publication of the Flexbox specification. Flexbox allowed developers to solve a whole series of long standing little layout problems, complete with an elegant syntax that requires a lot less markup to be implemented. Suddenly (well, not that suddenly, we still have to care about browser support, right?), reliably centering things on both axises wasn't an issue anymore. It was refreshing. Finally, tweaking a layout could be reduced to altering just one property in our stylesheet.

As important as Flexbox is to this day, it is not the end of the story.

It's 2019! Let's use CSS Grid.

If you've come this far reading this piece, we think it's safe to assume that two things are for sure:

  1. That we clearly aren't in this industry to live peaceful, quiet professional lives.
  2. The things we use are going to change.

In 2017, the CSS Grid Layout Module specification was officially published, but, as it always happens with CSS specs, its draft and interim implementations had already been around for some time.

CSS Grid is a bold leap into what CSS can and should do. What if we stopped micromanaging our pages styles, and started thinking more holistically? What if we had a system to reliably position elements on the screen that doesn't depend at all on the markup being used, nor the order of elements, and that is, at the same time, programmatically applicable on smaller screens?

No, this isn't just a thought. This is more of a dream; one of those good ones you don't want to wake up from. Except that, in 2019, this has become a reality.

The main difference between Grid and Flexbox is more nuanced, of course, but basically comes down to Grid operating in two dimensions, while Flexbox is limited to one. Knowing what elements are going to be placed within the limits of a container, we can choose exactly where those elements are going to end up, entirely from directives written in the stylesheet.

Do we want to tweak the layout down the road? Fine, that modification won't affect the markup.

The basic idea behind Grid is that elements are laid out in, well, a grid. By definition, a grid is composed by a certain amount of columns and rows, and the boundaries between columns and rows form a series of cells that can be filled with content.

The savings of this approach in terms of quantity of code being used to achieve the desired result are extraordinary: we just need to identify a container element, apply the display: grid rule to it, and then pick elements within that container and tell CSS what column/row they begin/end in.

.my-container { display: grid; grid-template-columns: repeat( 3, 1fr ); grid-template-rows: repeat( 2, 1fr ); } .element-1 { grid-column-start: 2; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3; }

The above example creates a 3x2 grid associated to the .my-container element; .element-1 is a 2x2 block that is inscribed in the grid, with its upper left vortex being positioned in the second column of the first row of the grid.

Sounds pretty neat, right?

The even neater thing about CSS Grid is the fact that you can create template areas, give those areas meaningful names (e.g. "header" or "main"), and then use those identifiers to programmatically position elements in those areas.

.item-a { grid-area: header; } .item-b { grid-area: main; } .item-c { grid-area: sidebar; } .item-d { grid-area: footer; } .container { display: grid; grid-template-columns: 50px 50px 50px 50px; grid-template-rows: auto; grid-template-areas: "header header header header" "main main . sidebar" "footer footer footer footer"; }

For those who have begun working in this business in the tables era, the code above is nothing short of science fiction.

More good news, anyway: support for CSS Grid is pretty great, today.

Using CSS Grid in WordPress

So, this is great, and knowing that we can do so many more things today than we could compared to a few years ago probably makes you want to give Grid a try, at last.

If you are working on a WordPress project, you're back facing the two options mentioned above: do we start from scratch and manually coding a template, or is there something that can give us a little help? Luckily, there is a plugin that might interest you, one that we have created with a dual goal in mind:

  1. Create a bridge between the Block Editor and CSS Grid.
  2. Create a plugin that could perhaps make people move past the initial skepticism of adopting the Block Editor.

It's called Grids, and it's a free download on the WordPress plugins repository.

Grids only takes care of the layout structure. It puts a 12x6 grid at your disposal (called Section), over which you can drag and draw the elements (Areas) that are going to be contained in that Section.

The system allows you to manually specify dimensions, backgrounds, responsive behavior, all using visual controls in the Block Editor, but by design, it doesn't provide any content block. Sure, one could see this approach as a weak point, but we think it's actually Grids' biggest strength because it enables the plugin to integrate with the myriad content blocks that other developers all around the world are creating. More so, in a way Grids helps bringing those blocks, and WordPress as a platform, in touch with CSS Grid itself.

Yet, even if the plugin doesn't strictly produce content, it's inevitable to put it in the same phrase with successful page builders, in fact comparing its functionality to that offered by those. If you care about concepts like separation of form and content, page weight, ease of maintenance, Grids offers a cleaner solution to the problem of creating visually appealing layouts in WordPress.

The generated markup is minimal. In its most basic form, a Section (that is, the element with the display: grid property) is only composed by its own element — of course, an internal wrapper (that couldn't be avoided and that's used for spacing purposes), and then one element per Area belonging to the Section. This is a huge step forward in terms of avoiding using unnecessary markup.

For those of you who haven't been afraid of getting your hands dirty with the development of blocks for the Block Editor, the rendering of the block is done server-side, which allows for custom classes to be added to Section and Area elements using filters.

This choice also directly determines what happens in the eventuality that you disable Grids in your install.
??
??If you don’t re-save your page again, what’s left of Grids on the front end is actually exclusively the content you put inside the content Areas. Not any extra markup elements, not any weird-looking shortcode.
??
??On the back-end side of things, the Block Editor has a system in place that warns you if you're editing a page that is supposed to use a particular block type, but that block type isn’t currently available: in that case, you could easily turn Grids back on temporarily, move your content in another place, and then get rid of the Section altogether.

CSS generated to create the grid is also dynamically added to the page, as an inline style in the <head> portion of the document. We haven't been exactly fans of styles written in the page directly, because ideally we'd like to delegate all of the styling to files that we could put under version control, yet this is a case where we found that approach to be very convenient.

Another viable option would have been to identify all the possible combinations of column/row starting/ending points, and programmatically map those with classes that could then be used to actually position elements within the grid. On a 12x6 grid, that would have lead to having a grand total of 36 class selectors, looking like this:

.grids-cs-1 { grid-column-start: 1; } .grids-ce-2 { grid-column-end: 2; }

What if we decide to offer more control over how a grid is composed and, say, give users access to options that determine how many columns or rows form the grid structure?

We'd have to manually map the classes that we don't yet have in the stylesheet (and release an update to the plugin just for that), or, again, generate them inline, and then add those classes to the grid elements.

While perfectly fine, this approach kind of goes against the idea of having a leaner, more scannable markup, so we've decided not to follow this route, and pay the price of having style dynamically put in the head of the document, knowing that it could be easily cached.

Because of the experimental nature of the plugin, the backend UI that's being used to actually compose the grid is created with CSS Grid, and a set of CSS variables through which we control the properties of content Areas. Using variables has immensely sped up our work behind the grid creator prototype — had we chosen a different path there, things wouldn't just be much longer in terms of development times, but also more complex and less clear to maintain down the road.

Feedback wanted!

To further foster the adoption of CSS Grid, we need tools that automate the process of creating layouts with it.

While we have been seeing great examples of this technology out in the wild, it would be short-sighted to assume that every website that is published today has a team of front-end devs behind it, that can take care of the issue.

We need tools that produce good markup, that don't hinder the maintenance of the website stylesheets, and, most importantly in the WordPress world, that can be easily integrated with the existing themes that people love to use.

We think Grids is a step forward in that direction, as it's a tool that is built upon two standards — the Block Editor API, and CSS Grid — and, as such, suffers less risk of reinventing the proverbial wheel.

While we've been recording general interest in the plugin at the recent WordCamp Europe in Berlin – with Matt Mullenweg himself displaying a brief demo of the plugin during his keynote — we know that it still needs a lot of feedback that can only be obtained with real-life scenarios. So, if you want to take Grids for a spin, please use it, test it and, why not, suggest new features.

The post Bringing CSS Grid to WordPress Layouts appeared first on CSS-Tricks.

A More Accessible Portals Demo

Css Tricks - Wed, 07/31/2019 - 4:16am

The point of the <portal> element (behind a flag in Chrome Canary) is that you can preload another whole page (like <iframe>), but then have APIs to animate it to the current page. So "Single Page App"-like functionality (SPA), but natively. I think that's pretty cool. I'm a fan of JavaScript frameworks in general, when they are providing value by helping do things that are otherwise difficult, like fancy state management, efficient re-rendering, and component composition. But if the framework is being reached for just for SPA qualities, that's unfortunate. The web platform is at its best when it seems what people are doing are in step with native, standardized solutions.

But it's not the web platform at its best when things are done inaccessibly. Steve Faulkner wrote "Short note on the portal element" where he points out seven issues with the portal element as it exists now. Here's a demo of it with some of those issues addressed. I guess it's somewhat of an implementation issue if a lot can be fixed from the outside, but I imagine much of it cannot (e.g. back button behavior, whether the loaded pages becomes part of the accessibility tree, etc.).

Here's a video of the basic behavior:

Direct Link to ArticlePermalink

The post A More Accessible Portals Demo appeared first on CSS-Tricks.

How much specificity do @rules have, like @keyframes and @media?

Css Tricks - Tue, 07/30/2019 - 12:58pm

I got this question the other day. My first thought is: weird question! Specificity is about selectors, and at-rules are not selectors, so... irrelevant?

To prove that, we can use the same selector inside and outside of an at-rule and see if it seems to affect specificity.

body { background: red; } @media (min-width: 1px) { body { background: black; } }

The background is black. But... is that because the media query increases the specificity? Let's switch them around.

@media (min-width: 1px) { body { background: black; } } body { background: red; }

The background is red, so nope. The red background wins here just because it is later in the stylesheet. The media query does not affect specificity.

If it feels like selectors are increasing specificity and overriding other styles with the same selector, it's likely just because it comes later in the stylesheet.

Still, the @keyframes in the original question got me thinking. Keyframes, of course, can influence styles. Not specificity, but it can feel like specificity if the styles end up overridden.

See this tiny example:

@keyframes winner { 100% { background: green; } } body { background: red !important; animation: winner forwards; }

You'd think the background would be red, especially with the !important rule there. (By the way, !important doesn't affect specificity; it's a per-rule thing.) It is red in Firefox, but it's green in Chrome. So that's a funky thing to watch out for. (It's been a bug since at least 2014 according to Estelle Weyl.)

The post How much specificity do @rules have, like @keyframes and @media? appeared first on CSS-Tricks.

Intrinsically Responsive CSS Grid with minmax() and min()

Css Tricks - Tue, 07/30/2019 - 12:57pm

The most famous line of code to have come out of CSS grid so far is:

grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));

Without any media queries, that will set up a grid container that has a flexible number of columns. The columns will stretch a little, until there is enough room for another one, and then a new column is added, and in reverse.

The only weakness here is that first value in minmax() (the 10rem value above). If the container is narrower than whatever that minimum is, elements in that single column will overflow. Evan Minto shows us the solution with min():

grid-template-columns: repeat(auto-fill, minmax(min(10rem, 100%), 1fr));

The browser support isn't widespread yet, but Evan demonstrates some progressive enhancement techniques to take advantage of now.

Direct Link to ArticlePermalink

The post Intrinsically Responsive CSS Grid with minmax() and min() appeared first on CSS-Tricks.

Creating Dynamic Routes in a Nuxt Application

Css Tricks - Tue, 07/30/2019 - 4:32am

In this post, we’ll be using an ecommerce store demo I built and deployed to Netlify to show how we can make dynamic routes for incoming data. It’s a fairly common use-case: you get data from an API, and you either don’t know exactly what that data might be, there’s a lot of it, or it might change. Luckily for us, Nuxt makes the process of creating dynamic routing very seamless.

Let’s get started!

Demo Site

GitHub Repo Creating the page

In this case, we’ve got some dummy data for the store that I created in mockaroo and am storing in the static folder. Typically you’ll use fetch or axios and an action in the Vuex store to gather that data. Either way, we store the data with Vuex in store/index.js, along with the UI state, and an empty array for the cart.

import data from '~/static/storedata.json' export const state = () => ({ cartUIStatus: 'idle', storedata: data, cart: [] })

It’s important to mention that in Nuxt, all we have to do to set up routing in the application is create a .vue file in the pages directory. So we have an index.vue page for our homepage, a cart.vue page for our cart, and so on. Nuxt automagically generates all the routing for these pages for us.

In order to create dynamic routing, we will make a directory to house those pages. In this case, I made a directory called /products, since that’s what the routes will be, a view of each individual product details.

In that directory, I’ll create a page with an underscore, and the unique indicator I want to use per page to create the routes. If we look at the data I have in my cart, it looks like this:

[ { "id": "9d436e98-1dc9-4f21-9587-76d4c0255e33", "color": "Goldenrod", "description": "Mauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci. Mauris lacinia sapien quis libero.", "gender": "Male", "name": "Desi Ada", "review": "productize virtual markets", "starrating": 3, "price": 50.40, "img": "1.jpg" }, … ]

You can see that the ID for each entry is unique, so that’s a good candidate for something to use, we’ll call the page:

_id.vue

Now, we can store the id of the particular page in our data by using the route params:

data() { return { id: this.$route.params.id, } },

For the entry from above, our data if we looked in devtools would be:

id: "9d436e98-1dc9-4f21-9587-76d4c0255e33"

We can now use this to retrieve all of the other information for this entry from the store. I’ll use mapState:

import { mapState } from "vuex"; computed: { ...mapState(["storedata"]), product() { return this.storedata.find(el => el.id === this.id); } },

And we’re filtering the storedata to find the entry with our unique ID!

Let the Nuxt config know

If we were building an app using yarn build, we’d be done, but we’re using Nuxt to create a static site to deploy, in our case on Netlify. When we use Nuxt to create a static site, we’ll use the yarn generate command. We have to let Nuxt know about the dynamic files with the generate command in nuxt.config.js.

This command will expect a function that will return a promise that resolves in an array that will look like this:

export default { generate: { routes: [ '/product/1', '/product/2', '/product/3' ] } }

To create this, at the top of the file we’ll bring in the data from the static directory, and create the function:

import data from './static/storedata.json' let dynamicRoutes = () => { return new Promise(resolve => { resolve(data.map(el => `product/${el.id}`)) }) }

We’ll then call the function within our config:

generate: { routes: dynamicRoutes },

If you’re gathering your data from an API with axios instead (which is more common), it would look more like this:

import axios from 'axios' let dynamicRoutes = () => { return axios.get('https://your-api-here/products').then(res => { return res.data.map(product => `/product/${product.id}`) }) }

And with that, we’re completely done with the dynamic routing! If you shut down and restart the server, you’ll see the dynamic routes per product in action!

For the last bit of this post, we’ll keep going, showing how the rest of the page was made and how we’re adding items to our cart, since that might be something you want to learn, too.

Populate the page

Now we can populate the page with whatever information we want to show, with whatever formatting we would like, as we have access to it all with the product computed property:

<main> <section class="img"> <img :src="`/products/${product.img}`" /> </section> <section class="product-info"> <h1>{{ product.name }}</h1> <h4 class="price">{{ product.price | dollar }}</h4> <p>{{ product.description }}</p> </section> ... </main>

In our case, we’ll also want to add items to the cart that’s in the store. We’ll add the ability to add and remove items (while not letting the decrease count dip below zero)

<p class="quantity"> <button class="update-num" @click="quantity > 0 ? quantity-- : quantity = 0">-</button> <input type="number" v-model="quantity" /> <button class="update-num" @click="quantity++">+</button> </p> ... <button class="button purchase" @click="cartAdd">Add to Cart</button>

In our methods on that component, we’ll add the item plus a new field, the quantity, to an array that we’ll pass as the payload to a mutation in the store.

methods: { cartAdd() { let item = this.product; item.quantity = this.quantity; this.tempcart.push(item); this.$store.commit("addToCart", item); } }

In the Vuex store, we’ll check if the item already exists. If it does, we’ll just increase the quantity. If not, we’ll add the whole item with quantity to the cart array.

addToCart: (state, payload) => { let itemfound = false state.cart.forEach(el => { if (el.id === payload.id) { el.quantity += payload.quantity itemfound = true } }) if (!itemfound) state.cart.push(payload) }

We can now use a getter in the store to calculate the total, which is what we’ll eventually pass to our Stripe serverless function (another post on this coming soon!). We’ll use a reduce for this as reduce is very good at retrieving one value from many. (I wrote up more details on how reduce works here).

cartTotal: state => { if (!state.cart.length) return 0 return state.cart.reduce((ac, next) => ac + next.quantity * next.price, 0) } Demo Site

GitHub Repo

And there you have it! We’ve set up individual product pages, and Nuxt generates all of our individual routes for us at build time. You’d be Nuxt not to try it yourself. &#x1f62c;

The post Creating Dynamic Routes in a Nuxt Application appeared first on CSS-Tricks.

The Simplest Way to Load CSS Asynchronously

Css Tricks - Tue, 07/30/2019 - 4:31am

Scott Jehl:

One of the most impactful things we can do to improve page performance and resilience is to load CSS in a way that does not delay page rendering. That’s because by default, browsers will load external CSS synchronously—halting all page rendering while the CSS is downloaded and parsed—both of which incur potential delays.

<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">

Don't just up and do this to all your stylesheets though, otherwise, you'll get a pretty nasty "Flash of Unstyled Content" (FOUC) as the page loads. You need to pair the technique with a way to ship critical CSS. Do that though, and like Scott's opening sentence said, it's quite impactful.

Interesting side story... on our Pen Editor page over at CodePen, we had a FOUC problem (warning, there is a very fast flash of white in this video):

This has done this for (years?) on CodePen in @firefox.

We have a totally normal <link rel=“stylesheet”> at the top of the page that is supposed to be render-blocking, yes?

Would love to understand. pic.twitter.com/HGTHwpemiy

— Chris Coyier (@chriscoyier) June 20, 2019

What makes it weird is that we load our CSS in <link> tags in the <head> completely normally, which should block-rendering and prevent FOUC. But there is some hard-to-reproduce bug at work. Fortunately we found a weird solution, so now we have an empty <script> tag in the <head> that somehow solves it.

Direct Link to ArticlePermalink

The post The Simplest Way to Load CSS Asynchronously appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.