Web Standards

How To Create A Better User Experience For Wearables

Usability Geek - Wed, 06/05/2019 - 11:51am
While smartphones offer us advanced technology that fits in our pocket, the next step in the technological revolution is embedded in the tech we wear. In many ways, this step has been taken. In 2009,...
Categories: Web Standards

JAMstack? More like SHAMstack.

Css Tricks - Wed, 06/05/2019 - 5:30am

I'm a fan of the whole JAMstack thing. It seems like a healthy web movement. I'm looking forward to both of the upcoming conferences.

Of any web trend, #jamstack seems like it will be the least regrettable.

— Chris Coyier (@chriscoyier) May 22, 2019

I feel like the acronym might not be quite doing it justice though. Not that I suggest we change it. Once a thing like that has legs, I find it's best to roll with it. Same deal with serverless. Heck, the name of this website is pretty... not great.

To me, the most important part of JAMstack is rooted in the concept of static file hosting. Static file hosting is the foundation of all the power. It opens up a bunch of doors, like:

  • Everything can be CDN-hosted. "The edge," as they say. Even the HTML (the M in JAMStack also refers to Markup) can be CDN-hosted, which you otherwise can't do. That gives you an amazing base of speed that encourages you to keep that speed as you build.
  • The project feels easier to work with. Git clone, npm install, build. Deployments are git pushes of a dist folder. It's so cool, for example, Netlify gives you a URL for every build, even on branches you're working on. This is made possible by deploys being kind of immutable. A set of files at a particular point in time.
  • Cloud functions are awesome. Because you don't have a traditional server-side language to reach for, you build it with cloud functions when you do need server-side code — which is a cool way to architect things anyway and is very spiritually connected to all this.

Don't think, "Oh, JAMstack is just for Jekyll blogs," or whatever. True, static site generators are extremely JAMstack-y, and JAMstack highly encourages as much prebuilt markup as possible (which is good for speed and SEO and all that), but pre-built markup isn't a requirement.

I'd go so far as to say that a client-side JavaScript-powered app that ships a <div id="root"></div> and a bundle of JavaScript that hits APIs and builds out the site is still a JAMstack site. It's still statically hosted (probably) with cloud functions serving up data.

I’d say “yes”.

Perhaps a little more SSR would be good for all the reasons but meh, not required for a jamstack merit badge.

— Chris Coyier (@chriscoyier) May 22, 2019

But as long as you're JAMStack anyway, that encourages you to put more in those static files. In that way, it encourages static content as well, when possible. I'd say "server-side rendered" (SSR) as that's the common term, but it's beyond that. It's not a server side language generating the markup on request; it's built in a build step ahead of time, before deployment. Again it's not required, just encouraged.

So, we've got static-hosted HTML, and all our other files (e.g. CSS, images, etc.) are also static. Then:

  • The J of JAMstack is JavaScript.
  • The A of JAMstack is APIs.

They are sorta kinda the same thing. Your JavaScript files are statically hosted. They run, and they talk to APIs if they need to. A common example might be a GraphQL endpoint coughing up some content.

An interesting twist here is that you can half-and-half this stuff. In other words, you can pre-build some of the markup, and wait for JavaScript and API calls for other parts. Imagine an e-commerce site with a homepage and a dozen other pages you can pre-build entirely, but then a catalog of thousands of products that would be too impractical to statically generate (too slow). They are just a single scaffolded template that flesh themselves out with client-side API calls.

So, if we were to make a new acronym, perhaps we'd include Static Hosting in there and combine the JavaScript and APIs into just APIs, leaving us with...

Static Hosting, APIs, and Markup, or the SHAMstack. Errrrr &#x1f62c; maybe not.

The post JAMstack? More like SHAMstack. appeared first on CSS-Tricks.

Self-Host Your Static Assets

Css Tricks - Wed, 06/05/2019 - 5:30am

Harry Roberts digs into why hosting assets on someone else’s servers (including CDNs) is not such a great idea if we want our websites to be lightning fast.

Harry writes:

One of the quickest wins—and one of the first things I recommend my clients do—to make websites faster can at first seem counter-intuitive: you should self-host all of your static assets, forgoing others’ CDNs/infrastructure.

I think perhaps the most shocking example Harry shows is this one:

...on a reasonably fast connection, hosting these static assets off-site is 311ms, or 1.65×, slower than hosting them ourselves.

By linking to three different origins in order to serve static assets, we cumulatively lose a needless 805ms to network negotiation. Full test. Okay, so not exactly terrifying, but Trainline, a client of mine, found that by reducing latency by 300ms, customers spent an extra £8m a year. This is a pretty quick way to make eight mill.

It’s clear from Harry’s example (as well as the rest of the examples on WPO stats) every millisecond counts when it comes to performance. And, if we can alleviate even a third of a second of latency by moving our assets around, we should probably go do that.

Direct Link to ArticlePermalink

The post Self-Host Your Static Assets appeared first on CSS-Tricks.

Movin’ Modals Along a Path

Css Tricks - Tue, 06/04/2019 - 10:07am

Modals always be just appearin'. You might see one once in a while that slides in from one of the edges, or uses some kind of scale/opacity thing to appear from "above" or "below." But we can get weirder than that. Why not have them come in on an offset-path?

Just a swoopy arc is kinda fun.

See the Pen
Move Modal In on Path
by Chris Coyier (@chriscoyier)
on CodePen.

Or we could Mary Poppins it and have it come floating in from afar.

See the Pen
Move Modal In on Path: Mary Poppins Edition
by Chris Coyier (@chriscoyier)
on CodePen.

Or get straight up wiggly woggly.

See the Pen
Move Modal In on Path: Wackadoo
by Chris Coyier (@chriscoyier)
on CodePen.

That's all. I figured you were here for the CSS tricks, anyway. ;)

The post Movin’ Modals Along a Path appeared first on CSS-Tricks.

Creating Animations Using React Spring

Css Tricks - Tue, 06/04/2019 - 4:17am

Have you ever needed animation in your React application? Traditionally, implementing animation has not an easy feat to accomplish. But now, thanks to Paul Henschel, we there’s a new React tool just for that. react-spring inherits from animated and react-motion for interpolations, optimized performance, and a clean API.

In this tutorial, we will be looking at two of the five hooks included in react-spring, specifically useSpring and useTrail. The examples we’ll implement make use of both APIs.

If you want to follow along, install react-spring to kick things off:

## yarn yarn add react-spring ## npm npm install react-spring --save Spring

The Spring prop can be used for moving data from one state to another. We are provided with a from and to prop to help us define the animation’s starting and ending states. The from prop determines the initial state of the data during render, while we use to in stating where it should to be after the animation completes.

In the first example, we will make use of the render prop version of creating spring animation.

See the Pen
react spring 1
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

On initial render, we want to hide a box, and slide it down to the center of the page when a button is clicked. It’s possible to do this without making use of react-spring, of course, but we want to animate the entrance of the box in to view and only when the button is clicked.

class App extends React.Component { state = { content: false } displayContent = (e) => { e.preventDefault() this.setState({ content: !this.state.content }) } render() { return ( <div className="container"> // The button that toggles the animation <div className="button-container"> <button onClick={this.displayContent} className="button"> Toggle Content </button> </div> { !this.state.content ? ( // Content in the main container <div> No Content </div> ) : ( // We call Spring and define the from and to props <Spring from={{ // Start invisible and offscreen opacity: 0, marginTop: -1000, }} to={{ // End fully visible and in the middle of the screen opacity: 1, marginTop: 0, }} > { props => ( // The actual box that slides down <div className="box" style={ props }> <h1> This content slid down. Thanks to React Spring </h1> </div> )} </Spring> ) } </div> ) } }

Most of the code is basic React that you might already be used to seeing. We make use of react-spring in the section where we want to conditionally render the content after the value of content has been changed to true. In this example, we want the content to slide in from the top to the center of the page, so we make use of marginTop and set it to a value of -1000 to position it offscreen, then define an opacity of 0 as our values for the from prop. This means the box will initially come from the top of the page and be invisible.

Clicking the button after the component renders updates the state of the component and causes the content to slide down from the top of the page.

We can also implement the above example using the hooks API. For this, we’ll be making use of the useSpring and animated hooks, alongside React’s built-in hooks.

const App = () => { const [contentStatus, displayContent] = React.useState(false); // Here's our useSpring Hook to define start and end states const contentProps = useSpring({ opacity: contentStatus ? 1 : 0, marginTop: contentStatus ? 0 : -1000 }) return ( <div className="container"> <div className="button-container"> <button onClick={() => displayContent(a => !a)} className="button">Toggle Content</button> </div> { !contentStatus ? ( <div> No Content </div> ) : ( // Here's where the animated hook comes into play <animated.div className="box" style={ contentProps }> <h1> This content slid down. Thanks to React Spring </h1> </animated.div> ) } </div> ) }

First, we set up the state for the component. Then we make use of useSpring to set up the animations we need. When contentStatus is true, we want the values of marginTop and opacity to be 0 and 1, respectively. Else, they should be -1000 and 0. These values are assigned to contentProps which we then pass as props to animated.div.

When the value of contentStatus changes, as a result of clicking the button, the values of opacity and marginTop changes alongside. This cause the content to slide down.

See the Pen
react spring 2
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

Trail

The Trail prop animates a list of items. The animation is applied to the first item, then the siblings follow suit. To see how that works out, we’ll build a component that makes a GET request to fetch a list of users, then we will animate how they render. Like we did with Spring, we’ll see how to do this using both the render props and hooks API separately.

First, the render props.

class App extends React.Component { state = { isLoading: true, users: [], error: null }; // We're using the Fetch <abbr>API</abbr> to grab user data // https://css-tricks.com/using-data-in-react-with-the-fetch-api-and-axios/ fetchUsers() { fetch(`https://jsonplaceholder.typicode.com/users`) .then(response => response.json()) .then(data => // More on setState: https://css-tricks.com/understanding-react-setstate/ this.setState({ users: data, isLoading: false, }) ) .catch(error => this.setState({ error, isLoading: false })); } componentDidMount() { this.fetchUsers(); } render() { const { isLoading, users, error } = this.state; return ( <div> <h1>Random User</h1> {error ? <p>{error.message}</p> : null} {!isLoading ? ( // Let's define the items, keys and states using Trail <Trail items={users} keys={user => user.id} from={{ marginLeft: -20, opacity: 0, transform: 'translate3d(0,-40px,0)' }} to={{ marginLeft: 20, opacity: 1, transform: 'translate3d(0,0px,0)' }} > {user => props => ( <div style={props} className="box"> {user.username} </div> )} </Trail> ) : ( <h3>Loading...</h3> )} </div> ); } }

When the component mounts, we make a request to fetch some random users from a third-party API service. Then, we update this.state.users using the data the API returns. We could list the users without animation, and that will look like this:

users.map(user => { const { username, name, email } = user; return ( <div key={username}> <p>{username}</p> </div> ); })

But since we want to animate the list, we have to pass the items as props to the Trail component:

<Trail items={users} keys={user => user.id} from={{ marginLeft: -20, opacity: 0, transform: 'translate3d(0,-40px,0)' }} to={{ marginLeft: 20, opacity: 1, transform: 'translate3d(0,0px,0)' }} > {user => props => ( <div style={props} className="box"> {user.username} </div> )} </Trail>

We set the keys to the ID of each user. You can see we are also making use of the from and to props to determine where the animation should start and end.

Now our list of users slides in with a subtle animation:

See the Pen
React Spring - Trail 1
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

The hooks API gives us access to useTrail hook. Since we are not making use of a class component, we can make use of the useEffect hook (which is similar to componentDidMount and componentDidUpdate lifecycle methods) to fetch the users when the component mounts.

const App = () => { const [users, setUsers] = useState([]); useEffect(() => { fetch(`https://jsonplaceholder.typicode.com/users`) .then(response => response.json()) .then(data => setUsers(data) ) }, []) const trail = useTrail(users.length, { from: { marginLeft: -20, opacity: 0, transform: 'translate3d(0,-40px,0)' }, to: { marginLeft: 20, opacity: 1, transform: 'translate3d(0,0px,0)' } }) return ( <React.Fragment> <h1>Random User</h1> {trail.map((props, index) => { return ( <animated.div key={users[index]} style={props} className="box" > {users[index].username} </animated.div> ) })} </React.Fragment> ); }

We have the initial state of users set to an empty array. Using useEffect, we fetch the users from the API and set a new state using the setUsers method we created with help from the useState hook.

Using the useTrail hook, we create the animated style passing it values for from and to, and we also pass in the length of the items we want to animate. In the part where we want to render the list of users, we return the array containing the animated props.

See the Pen
React Spring -Trail 2
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

Go, spring into action!

Now you have a new and relatively easy way to work with animations in React. Try animating different aspects of your application where you see the need. Of course, be mindful of user preferences when it comes to animations because they can be detrimental to accessibility.

While you’re at it, ensure you check out the official website of react-spring because there are tons of demo to get your creative juices flowing with animation ideas.

The post Creating Animations Using React Spring appeared first on CSS-Tricks.

Do you need an ICON ONLY button without screwing up the accessibility?

Css Tricks - Mon, 06/03/2019 - 11:42am

The first consideration is: do you really? If you can, having text next to your icons is proven over and over again to be the most accessible and clearest UX (see Apple's latest blunder). But if you need to (and I get it, sometimes you need to), Sara Soueidan and Scott O'Hara have a pair of articles that nicely lay out all the options and present actual research on this topic.

If you just want to be told what to do, I'd go for the just use some text in the button approach:

<button aria-expanded="false" id="menu-trigger"> <svg viewBox="0 0 32 32" width="32px" height="32px" aria-hidden="true" focusable="false"> <!-- svg content --> </svg> Menu </button>

Sara says There is no One Way to Rule Them All, but it does seem like you really need to use actual text inside that button and either hide it or override it somehow. SVG alone has no rock solid way to provide an accessible name to a button or link.

Funny how long this has been a tricky pattern to get right.

The post Do you need an ICON ONLY button without screwing up the accessibility? appeared first on CSS-Tricks.

Qualitative Data: The Great Lost Metric For SaaS Companies [Sponsored]

Usability Geek - Mon, 06/03/2019 - 10:25am
Data doesn’t lie. That’s the general thinking in marketing and product development departments. That adage may be true, but it isn’t quite the whole truth. Data-driven...
Categories: Web Standards

Prevent Page Scrolling When a Modal is Open

Css Tricks - Mon, 06/03/2019 - 8:11am

Please stop me if you've heard this one before. You open a modal, scroll through it, close it, and wind up somewhere else on the page than you were when you opened the modal.

That's because modals are elements on a page just like any other. It may stay in place (assuming that's what it's meant to do) but the rest of page continues to behave as normal.

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

Sometimes this is a non-issue, like screens that are the exact height of the viewport. Anything else, though, we're looking at Scroll City. The good news is that we can prevent that with a sprinkle of CSS (and JavaScript) trickery.

Let's start with something simple

We can make a huge dent to open-modal-page-scrolling™ by setting the height of the entire body to the full height of the viewport and hiding vertical overflow when the modal is open:

body.modal-open { height: 100vh; overflow-y: hidden; }

That's good and all, but if we've scrolled through the <body> element before opening the modal, we get a little horizontal reflow. The width of the viewport is expanded about 15 pixels more, which is exactly the with of the scroll bar.

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

Let's adjust the right padding of the body a bit to avoid that.

body { height: 100vh; overflow-y: hidden; padding-right: 15px; /* Avoid width reflow */ }

Note that the modal needs to be shorter than the height of the viewport to make this work. Otherwise, the scroll bar on the body will be necessary.

Great, now what about mobile?

This solution works pretty great on desktop as well as Android Mobile. That said, Safari for iOS needs a little more love because the body still scrolls when a modal is open when tapping and moving about the touchscreen.

We can set the body to a fixed position as a workaround:

body { position: fixed; }

Works now! The body will not respond when the screen is touched. However, there's still a "small" problem here. Let's say the modal trigger is lower down the page and we click to open it up. Great! But now we're automatically scrolled back up to the top of the screen, which is just as disorientating as the scrolling behavior we're trying to resolve.

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

Boo!

That's why we've gotta turn to JavaScript

We can use JavaScript to avoid the touch event bubble. We all know there should be a backdrop layer when a modal is open. Unfortunately, stopPropagation is a little awkward with touch in iOS. But preventDefault works well. That means we have to add event listeners in every DOM node contained in the modal — not just on the backdrop or the modal box layer. The good news is, many JavaScript libraries can do this, including good ol' jQuery.

Oh, and one more thing: What if we need scrolling inside the modal? We still have to trigger a response for a touch event, but when reaching the top or bottom of the modal, we still need to prevent bubbling. Seems very complex, so we're not totally out of the woods here.

Let's enhance the fixed body approach

This is what we were working with:

body { position: fixed; }

If we know the top of the scroll location and add it to our CSS, then the body will not scroll back to the top of the screen, so problem solved. We can use JavaScript for this by calculating the scroll top, and add that value to the body styles:

// When the modal is shown, we want a fixed body document.body.style.position = 'fixed'; document.body.style.top = `-${window.scrollY}px`; // When the modal is hidden, we want to remain at the top of the scroll position document.body.style.position = ''; document.body.style.top = '';

This works, but there's still a little leakage here after the modal is closed. Specifically, it appears that the page already loses its scroll position when the modal is open and the body set to be fixed. So we have to retrieve the location. Let's modify our JavaScript to account for that.

// When the modal is hidden... const top = document.body.style.top; document.body.style.position = ''; document.body.style.top = ''; window.scrollTo(0, parseInt(scrollY || '0') * -1);

That does it! The body no longer scrolls when a modal is open and the scroll location is maintained both when the modal is open and when it is closed. Huzzah!

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

The post Prevent Page Scrolling When a Modal is Open appeared first on CSS-Tricks.

Material Theming: Making Material Your Own!

Css Tricks - Mon, 06/03/2019 - 4:15am

The web is a beautiful, expressive medium that’s evolved over time as trends and technology have changed. Moments of delight and flair are what set companies apart from one another. At the same time, today’s top products rely on scalable, component-based design systems to efficiently develop a coherent brand. And it’s more important than ever to have accessibility and a solid user experience baked in from the start! But these two worlds — creative web design and systematic web design — don’t need to be at arms. The beautiful gooey center of the web design world is where we can find a way to meld creative web design in with our systems, and luckily, you can have both!

One of those design systems is called Material Design (the team I just joined at Google!). Material is built on years of research and best practices to give designers and developers access to creating beautiful, accessible UIs with the least amount of work possible. But in its initial launch, one thing was missing from the equation: the ability to express a brand’s personality in an easy-to-implement way. The team heard two key pieces of feedback:

  1. Material wasn’t stylistically flexible enough to meet the needs of all products, brands, and users.
  2. It wasn’t easy enough to apply and build brand experiences systematically across products.

And as of last year (specifically, I/O 2018), Material announced new theming capabilities! Theming allows developers and designers to benefit from all the parts of Material that make it a world-class design system — and make it their own! In other words: You can customize the look and feel of Material Components by applying global changes to your product’s color, shape, and typography.

Material Components are built for multiple systems like Android, iOS, and Flutter, and we’re going to focus on the web for this post (this is CSS-Tricks after all). Let’s start off with a base login template using Material Components for the web to see how easy implementing a theme atop this will be:


About theming

The current theming implementations allow for color, typography, and shape adjustments that trickle down to every component in your product. These three subsystems may not sound like many options, but together they bring a big impact to the design, and are a great springboard to jump off of with more design changes on a more granular level.

Color

The first themable option is color. There’s a great color picker tool on Material.io for you to be able to see contrast and aid your color selection process. Since this is CSS-Tricks, let’s write some CSS (okay, more like SCSS), to get started with an example. In a few lines of code in our my-theme.scss file, we can entirely change the look and feel of this login screen:


We’ve set:

$mdc-theme-primary: #26418f; $mdc-theme-secondary: #d1c4e9; $mdc-theme-background: #fdf6f9;

Even though we have not specified a $mdc-theme-on-primary, the system knows to make this white now (using a Sass contrast function) to help us ensure accessible color contrast. We can also override the text color on the primary and secondary themes with $mdc-theme-on-primary and $mdc-theme-on-secondary. However, if no value is explicitly set, these will either be black or white based on the background. See the color picker for more information.

Typography

Material sets up a base typography scale, which can be customized with theming. You can adjust the typography for each individual headline level and apply it throughout your product in two ways:

  1. Using CSS classes to apply the styles. I.e. <h1 class="mdc-typography--headline1">
  2. Using mixins to extend the styles from a header component onto another (i.e. h1 {@include mdc-typography(headline1);}). You can see an example of this in our starter kit example on Glitch.

A quick way to change the typeface is by using Google Fonts — a really nice directory of free web fonts. We’re going to make this easy for ourselves and pick out a Google font called Josefin Sans. In order to use this in our project, we’ll need to import it, and then can set the base typography to use it:

@import url('https://fonts.googleapis.com/css?family=Josefin+Sans'); $mdc-typography-font-family: unquote("Josefin Sans, sans-serif");

We use unquote here because the typography in Material is set in a map. We can specify more styles like so:

$mdc-typography-styles-button: ( font-size: 14px, font-weight: 600, letter-spacing: 0.05em, );

Now our login page looks like this:


Shape

Shape is another way to be expressive with your code! What do I mean by shape? In Material, shape affects the corner radius of components, such as buttons, cards, and sheets. In product design, shape helps to define your brand. Is it angular and machine-like, or is it more rounded and organic? Changing shape trickles down through the rest of the system. Here are some examples of shape in Material:

The other cool thing about shape in Material Components is that you don’t have to have the same shape on each corner, or even the same component at different sizes. There are small, medium, and large components in Material, and you can apply different styles for these different component types, and you can mix it up and specify each corner, one-by-one, in a space-separated list of values just as you would with border-radius.

MDC Web does not currently support cut corners like the other platforms do since it is a non-trivial operation with current web standards. This is another reason I personally love Houdini and see a lot of impact for it in future CSS development!

In the example we’re working with, we have both large and small components. The large components are the text field inputs, and the small component is the “login” button. We can apply different shapes to these with:

$mdc-shape-small-component-radius: 12px 4px; $mdc-shape-large-component-radius: 8px;

And voilà! We have transformed our application in 12 lines of code.

Themes, themes, everywhere!

Now here’s the part where you get creative. There are so many ways to mix and match the elements of color, typography, and shape to really make your brand stand out. Here are four very distinct example apps that use color theory, typography, and shape to differentiate their products, each based on the baseline Material Components:

Themes IRL

Google itself customizes and extends upon the baseline Material Components with its own products. This is called the Google Material Theme, and it was defined by a number of product teams, including Gmail, Google News, Google Play, and Google Home:

But they are not the only company to use Material Design and its principles. A few companies have also extended Material Components in their own large-scale products.

Lyft, a ridesharing service, is just one example. They used an extended FAB component to highlight key actions, and designed it with a gradient to give it a unique feel that users were still familiar with. Lyft also leveraged Material’s elevation system in their own product.

Anchor, a free app that helps people record, distribute, and host podcasts, is another great example of making Material your own. They showcase their bold color palette, and integrate it with choice chips to delineate display options, a list of cards for content selection, and an extended FAB anchored to the bottom to remain persistently available for user actions.

Get started

Now you have everything you need to make own Material Theme with Material Components for the web. It’s easy to start building your web project with our Material Starter Kit, and exploring theming with the Build a Material theme Glitch project we’ve just released. Change around the variables in my-theme.scss to explore how they can customize the individual components. Then, you can open any template, paste those variables into the my-theme.scss, and start building.


TL;DR: If you thought that Material Design wasn’t for you in the past, it’s a great time to start exploring. Happy theming!

The post Material Theming: Making Material Your Own! appeared first on CSS-Tricks.

Implementing Private Variables In JavaScript

Css Tricks - Fri, 05/31/2019 - 1:07pm

JavaScript (or ECMAScript) is the programming language that powers the web. Created in May 1995 by Brendan Eich, it’s found its place as a widely-used and versatile technology. Despite its success, it’s been met with its fair share of criticism, especially for idiosyncrasies. Things like objects being casted to string form when used as indices, 1 == "1" returning true, or the notoriously confusing this keyword. A particularly interesting quirk though, is the existence of various techniques for variable privacy.

In its current state, there is no "direct” way to create a private variable in JavaScript. In other languages, you can use the private keyword or double-underscores and everything works, but variable privacy in JavaScript carries characteristics that make it seem more akin to an emergent trait of the language rather than an intended functionality. Let’s introduce some background to our problem.

The "var” keyword

Before 2015, there was essentially one way to create a variable, and that was the var keyword. var is function-scoped, meaning that variables instantiated with the keyword would only be accessible to code within the function. When outside of a function, or "global” essentially, the variable will be accessible to anything executed after the definition of the variable. If you try to access the variable in the same scope before its definition, you will get undefined rather than an error. This is due to the way the var keyword "hoists."

// Define "a" in global scope var a = 123; // Define "b" in function scope (function() { console.log(b); //=> Returns "undefined" instead of an error due to hoisting. var b = 456; })(); console.log(a); // => 123 console.log(b); // Throws "ReferenceError" exception, because "b" cannot be accessed from outside the function scope. The birth of ES6 variables

In 2015, ES6/ES2015 was made official, and with it came two new variable keywords: let and const. Both were block-scoped, meaning that variables created with the keywords would be accessible from anything within the same pair of braces. Same as with var, but the let and const variables could not be accessed outside of block scope with loops, functions, if statements, braces, etc.

const a = 123; // Block scope example #1 if (true) { const b = 345; } // Block scope example #2 { const c = 678; } console.log(a); // 123 console.log(b); // Throws "ReferenceError" because "b" cannot be accessed from outside the block scope. console.log(c); // Throws "ReferenceError" because "b" cannot be accessed from outside the block scope.

Since code outside of the scope cannot access the variables, we get an emergent trait of privacy. We’re going to cover some techniques for implementing it in different ways.

Using functions

Since functions in JavaScript also are blocks, all variable keywords work with them. In addition, we can implement a very useful design pattern called the "module.”

The Module Design Pattern

Google relies on the Oxford Dictionary to define a "module":

Any of a number of distinct but interrelated units from which a program may be built up or into which a complex activity may be analyzed.

—"Module" Definition 1.2

The module design pattern is very useful in JavaScript because it combines public and private components and it allows us to break a program into smaller components, only exposing what another part of the program should be able to access through a process called "encapsulation.” Through this method, we expose only what needs to be used and can hide the rest of the implementation that doesn’t need to be seen. We can take advantage of function scope to implement this.

const CarModule = () => { let milesDriven = 0; let speed = 0; const accelerate = (amount) => { speed += amount; milesDriven += speed; } const getMilesDriven = () => milesDriven; // Using the "return" keyword, you can control what gets // exposed and what gets hidden. In this case, we expose // only the accelerate() and getMilesDriven() function. return { accelerate, getMilesDriven } }; const testCarModule = CarModule(); testCarModule.accelerate(5); testCarModule.accelerate(4); console.log(testCarModule.getMilesDriven());

With this, we can get the number of miles driven, as well as the amount of acceleration, but since the user doesn’t need access to the speed in this case, we can hide it by only exposing the accelerate() and getMilesDriven() method. Essentially, speed is a private variable, as it is only accessible to code inside of the same block scope. The benefit to private variables begins to become clear in this situation. When you remove the ability to access a variable, function, or any other internal component, you reduce the surface area for errors resulting from someone else mistakenly using something that wasn’t meant to be.

The alternative way

In this second example, you’ll notice the addition of the this keyword. There’s a difference between the ES6 arrow function ( => ) and the traditional function(){}. With the function keyword, you can use this, which will be bound to the function itself, whereas arrow functions don’t allow any kind of use of the this keyword. Both are equally-valid ways to create the module. The core idea is to expose parts that should be accessed and leave other parts that should not be interacted with, hence both public and private data.

function CarModule() { let milesDriven = 0; let speed = 0; // In this case, we instead use the "this" keyword, // which refers to CarModule this.accelerate = (amount) => { speed += amount; milesDriven += speed; } this.getMilesDriven = () => milesDriven; } const testCarModule = new CarModule(); testCarModule.accelerate(5); testCarModule.accelerate(4); console.log(testCarModule.getMilesDriven()); Enter ES6 Classes

Classes were another addition that came with ES6. Classes are essentially syntactic sugar — in other words, still a function, but potentially "sweetening” it into a form that’s easier to express. With classes, variable privacy is (as of now) close to impossible without making some major changes to the code.

Let’s take a look at an example class.

class CarModule { /* milesDriven = 0; speed = 0; */ constructor() { this.milesDriven = 0; this.speed = 0; } accelerate(amount) { this.speed += amount; this.milesDriven += this.speed; } getMilesDriven() { return this.milesDriven; } } const testCarModule = new CarModule(); testCarModule.accelerate(5); testCarModule.accelerate(4); console.log(testCarModule.getMilesDriven());

One of the first things that stands out is that the milesDriven and speed variable are inside of a constructor() function. Note that you can also define the variables outside of the constructor (as shown in the code comment), but they are functionally the same regardless. The problem is that these variables will be public and accessible to elements outside of the class.

Let’s look at some ways to work around that.

Using an underscore

In cases where privacy is to prevent collaborators from making some catastrophic mistake, prefixing variables with an underscore (_), despite still being "visible” to the outside, can be sufficient to signal to a developer, "Don’t touch this variable.” So, for example, we now have the following:

// This is the new constructor for the class. Note that it could // also be expressed as the following outside of constructor(). /* _milesDriven = 0; _speed = 0; */ constructor() { this._milesDriven = 0; this._speed = 0; }

While this does work for its specific use case, it’s still safe to say that it’s less than ideal on many levels. You can still access the variable but you also have to modify the variable name on top of that.

Putting everything inside the constructor

Technically, there is a method for variable privacy in a class that you can use right now, and that’s placing all variables and methods inside the constructor() function. Let’s take a look.

class CarModule { constructor() { let milesDriven = 0; let speed = 0; this.accelerate = (amount) => { speed += amount; milesDriven += speed; } this.getMilesDriven = () => milesDriven; } } const testCarModule = new CarModule(); testCarModule.accelerate(5); testCarModule.accelerate(4); console.log(testCarModule.getMilesDriven()); console.log(testCarModule.speed); // undefined -- We have true variable privacy now.

This method accomplishes true variable privacy in the sense that there is no way to directly access any variables that aren’t intentionally exposed. The problem is that we now have, well, code that doesn’t look all that great compared to what we had before, in addition to the fact that it defeats the benefits of the syntactic sugar we had with classes. At this point, we might as well be using the function() method.

Using WeakMap

There’s another, more creative way to go about making a private variable, and that’s using WeakMap(). Although it may sound similar to Map, the two are very different. While maps can take any type of value as a key, a WeakMap only take objects and deletes the values in the WeakMap when the object key is garbage collected. In addition, a WeakMap cannot be iterated through, meaning that you must have access to the reference to an object key in order to access a value. This makes it rather useful for creating private variables, since the variables are effectively invisible.

class CarModule { constructor() { this.data = new WeakMap(); this.data.set(this, { milesDriven: 0, speed: 0 }); } accelerate(amount) { // In this version, we instead create a WeakMap and // use the "this" keyword as a key, which is not likely // to be used accidentally as a key to the WeakMap. const data = this.data.get(this); const speed = data.speed + amount; const milesDriven = data.milesDriven + data.speed; this.data.set({ speed, milesDriven }); } this.getMilesDriven = () => this.data.get(this).milesDriven; } const testCarModule = new CarModule(); testCarModule.accelerate(5); testCarModule.accelerate(4); console.log(testCarModule.getMilesDriven()); console.log(testCarModule.data); //=> WeakMap { [items unknown] } -- This data cannot be accessed easily from the outside!

This solution is good at preventing an accidental usage of the data, but it isn’t truly private, since it can still be accessed from outside the scope by substituting this with CarModule. In addition, it adds a fair amount of complexity to the mix and, therefore, isn’t the most elegant solution.

Using symbols to prevent collisions

If the intent is to prevent name collisions, there is a useful solution using Symbol. These are essentially instances that can behave as unique values that will never be equal to anything else, except its own unique instance. Here’s an example of it in action:

class CarModule { constructor() { this.speedKey = Symbol("speedKey"); this.milesDrivenKey = Symbol("milesDrivenKey"); this[this.speedKey] = 0; this[this.milesDrivenKey] = 0; } accelerate(amount) { // It's virtually impossible for this data to be // accidentally accessed. By no means is it private, // but it's well out of the way of anyone who would // be implementing this module. this[this.speedKey] += amount; this[this.milesDrivenKey] += this[this.speedKey]; } getMilesDriven() { return this[this.milesDrivenKey]; } } const testCarModule = new CarModule(); testCarModule.accelerate(5); testCarModule.accelerate(4); console.log(testCarModule.getMilesDriven()); console.log(testCarModule.speed); // => undefined -- we would need to access the internal keys to access the variable. Like the underscore solution, this method more or less relies on naming conventions to prevent confusion. TC39 private class field proposal

Recently, a new proposal was introduced that would introduce private variables to classes. It’s rather simple: put a # before the name of a variable, and it becomes private. No extra structural changes needed.

class CarModule { #speed = 0 #milesDriven = 0 accelerate(amount) { // It's virtually impossible for this data to be // accidentally accessed. this.#speed += amount; this.#milesDriven += speed; } getMilesDriven() { return this.#milesDriven; } } const testCarModule = new CarModule(); testCarModule.accelerate(5); testCarModule.accelerate(4); console.log(testCarModule.getMilesDriven()); console.log(testCarModule.speed); //=> undefined -- we would need to access the internal keys to access the variable.

The private class field proposal is not standard and cannot be done without using Babel as of this writing, so you’ll have to wait a bit for it to be usable on major browsers, Node, etc.

Conclusion

That sums up the various ways you can implement private variables in JavaScript. There isn’t a single "correct” way to do it. These will work for different needs, existing codebases, and other constraints. While each has advantages and disadvantages, ultimately, all methods are equally valid as long as they effectively solve your problem.

Thanks for reading! I hope this provides some insight into how scope and variable privacy can be applied to improve your JavaScript code. This is a powerful technique and can support so many different methods and make your code more usable and bug-free. Try out some new examples for yourself and get a better feel.

The post Implementing Private Variables In JavaScript appeared first on CSS-Tricks.

Weekly Platform News: Favicon Guidelines, Accessibility Testing, Web Almanac

Css Tricks - Fri, 05/31/2019 - 4:55am

Šime posts regular content for web developers on webplatform.news.

Google posts guidelines for defining favicons

Jamie Leach: Google Search now displays favicons in search results on mobile. Your favicon should be a multiple of 48×48 (Google will re-scale it to 16×16 for use in search results). If a website doesn’t have a favicon or Google deems the favicon inappropriate, a generic globe icon will be displayed instead.

Your favicon should be a visual representation of your website’s brand, in order to help users quickly identify your site when they scan through search results.

Top websites are surprisingly inconsistent in the way they declare icons (via <link> elements in the page’s head). Twitter and Pinterest, two relatively modern progressive web apps, provide icons in two sizes.

<!-- example --> <link rel="icon" href="/icon-32x32.png"> <link rel="apple-touch-icon" href="/icon-192x192.png"> The Paciello Group releases ARC Toolkit

In honor of Global Accessibility Awareness Day, TPG is releasing our professional-level accessibility testing tool to the public. Learn all about it at https://t.co/ol33pizq2v and download it from the Google Chrome store today. #GAAD

— The Paciello Group (@paciellogroup) May 16, 2019

The Paciello Group: ARC Toolkit, our professional-level accessibility testing tool, is now available as a Chrome DevTools extension. This tool detects issues related to the WCAG 2.1 guidelines. You can run the test on the entire page or just the node selected in the DevTools Elements panel.

Remember, automated accessibility tools are only able to find some accessibility issues, and manual testing is necessary to ensure full accessibility. Lighthouse (via the Audits panel) suggests manual checks after performing an accessibility audit.

Other news
  • Jeff Jaffe: W3C and WHATWG have reached an agreement to collaborate on the development of HTML. "W3C shall encourage the community ... to contribute directly to the WHATWG HTML and DOM repositories; raising issues, proposing solutions, commenting on proposed solutions, and indicating support or otherwise for proposals."
  • Paul Calvano: "There is a significant gap in the first- vs. third-party resource age of CSS and web fonts. 95% of first-party fonts are older than one week compared to 50% of third-party fonts ... This makes a strong case for self-hosting web fonts!"
  • Rachel Andrew: The CSS subgrid value is a relatively straightforward addition to grid layout. For example, if you have nested grids, and you apply grid-template-rows: subgrid to the child grid, then this grid will use the row tracks of the parent grid instead of creating its own row tracks. That’s all there is to it. (This feature is currently only supported in Firefox Nightly.)
  • GitHub Blog: GitHub can now generate automated security fixes for your dependencies with known security vulnerabilities. On GitHub’s website, check your repository’s Security tab for security alerts. If you open an alert and press the "Create automated security fix" button, GitHub will create an automated pull request that fixes the security vulnerability.
  • Rick Viscomi: HTTP Archive plans to release the first annual Web Almanac in November, a report of the state of the web with interesting insights written by different experts. About 50 volunteers from the web community are currently working on it, and they are looking for more contributors.

The post Weekly Platform News: Favicon Guidelines, Accessibility Testing, Web Almanac appeared first on CSS-Tricks.

Reducing motion with the picture element

Css Tricks - Fri, 05/31/2019 - 4:54am

Here’s a bonafide CSS/HTML trick from Brad Frost and Dave Rupert where they use the <picture> element to switch out a GIF file with an image if the user has reduced motion enabled. This is how Brad goes about implementing that:

<picture> <!-- This image will be loaded if the media query is true --> <source srcset="no-motion.jpg" media="(prefers-reduced-motion: reduce)"></source> <!-- Otherwise, load this gif --> <img srcset="animated.gif" alt="brick wall"/> </picture>

How nifty is this? It makes me wonder if there are other ways this image-switching technique can be used besides accessibility and responsive images...

Also, it’s worth noting that Eric Bailey wrote about the reduced motion media query a while back where he digs into its history and various approaches to use it.

Direct Link to ArticlePermalink

The post Reducing motion with the picture element appeared first on CSS-Tricks.

A Practical Use Case for Vue Render Functions: Building a Design System Typography Grid

Css Tricks - Thu, 05/30/2019 - 5:07am

This post covers how I built a typography grid for a design system using Vue render functions. Here’s the demo and the code. I used render functions because they allow you to create HTML with a greater level of control than regular Vue templates, yet surprisingly I couldn’t find very much when I web searched around for real-life, non-tutorial applications of them. I’m hoping this post will fill that void and provide a helpful and practical use case on using Vue render functions.

I’ve always found render functions to be a little out-of-character for Vue. While the rest of the framework emphasizes simplicity and separation of concerns, render functions are a strange and often difficult-to-read mix of HTML and JavaScript.

For example, to display:

<div class="container"> <p class="my-awesome-class">Some cool text</p> </div>

...you need:

render(createElement) { return createElement("div", { class: "container" }, [ createElement("p", { class: "my-awesome-class" }, "Some cool text") ]) }

I suspect that this syntax turns some people off, since ease-of-use is a key reason to reach for Vue in the first place. This is a shame because render functions and functional components are capable of some pretty cool, powerful stuff. In the spirit of demonstrating their value, here’s how they solved an actual business problem for me.

Quick disclaimer: It will be super helpful to have the demo open in another tab to reference throughout this post.

Defining criteria for a design system

My team wanted to include a page in our VuePress-powered design system showcasing different typography options. This is part of a mockup that I got from our designer.

And here’s a sample of some of the corresponding CSS:

h1, h2, h3, h4, h5, h6 { font-family: "balboa", sans-serif; font-weight: 300; margin: 0; } h4 { font-size: calc(1rem - 2px); } .body-text { font-family: "proxima-nova", sans-serif; } .body-text--lg { font-size: calc(1rem + 4px); } .body-text--md { font-size: 1rem; } .body-text--bold { font-weight: 700; } .body-text--semibold { font-weight: 600; }

Headings are targeted with tag names. Other items use class names, and there are separate classes for weight and size.

Before writing any code, I created some ground rules:

  • Since this is really a data visualization, the data should be stored in a separate file.
  • Headings should use semantic heading tags (e.g. <h1>, <h2>, etc.) instead of having to rely on a class.
  • Body content should use paragraph (<p>) tags with the class name (e.g. <p class="body-text--lg">).
  • Content types that have variations should be grouped together by wrapping them in the root paragraph tag, or corresponding root element, without a styling class. Children should be wrapped with <span> and the class name.
<p> <span class="body-text--lg">Thing 1</span> <span class="body-text--lg">Thing 2</span> </p>
  • Any content that’s not demonstrating special styling should use a paragraph tag with the correct class name and <span> for any child nodes.
<p class="body-text--semibold"> <span>Thing 1</span> <span>Thing 2</span> </p>
  • Class names should only need to be written once for each cell that's demonstrating styling.
Why render functions make sense

I considered a few options before starting:

Hardcoding

I like hardcoding when appropriate, but writing my HTML by hand would have meant typing out different combinations of the markup, which seemed unpleasant and repetitive. It also meant that data couldn’t be kept in a separate file, so I ruled out this approach.

Here’s what I mean:

<div class="row"> <h1>Heading 1</h1> <p class="body-text body-text--md body-text--semibold">h1</p> <p class="body-text body-text--md body-text--semibold">Balboa Light, 30px</p> <p class="group body-text body-text--md body-text--semibold"> <span>Product title (once on a page)</span> <span>Illustration headline</span> </p> </div> Using a traditional Vue template

This would normally be the go-to option. However, consider the following:

See the Pen
Different Styles Example
by Salomone Baquis (@soluhmin)
on CodePen.

In the first column, we have:

- An <h1>> tag rendered as-is.
- A <p> tag that groups some <span> children with text, each with a class (but no special class on the <p> tag).
- A <p> tag with a class and no children.

The result would have meant many instances of v-if and v-if-else, which I knew would get confusing fast. I also disliked all of that conditional logic inside the markup.

Because of these reasons, I chose render functions. Render functions use JavaScript to conditionally create child nodes based on all of the criteria that’s been defined, which seemed perfect for this situation.

Data model

As I mentioned earlier, I’d like to keep typography data in a separate JSON file so I can easily make changes later without touching markup. Here’s the raw data.

Each object in the file represents a different row.

{ "text": "Heading 1", "element": "h1", // Root wrapping element. "properties": "Balboa Light, 30px", // Third column text. "usage": ["Product title (once on a page)", "Illustration headline"] // Fourth column text. Each item is a child node. }

The object above renders the following HTML:

<div class="row"> <h1>Heading 1</h1> <p class="body-text body-text--md body-text--semibold">h1</p> <p class="body-text body-text--md body-text--semibold">Balboa Light, 30px</p> <p class="group body-text body-text--md body-text--semibold"> <span>Product title (once on a page)</span> <span>Illustration headline</span> </p> </div>

Let’s look at a more involved example. Arrays represent groups of children. A classes object can store classes. The base property contains classes that are common to every node in the cell grouping. Each class in variants is applied to a different item in the grouping.

{ "text": "Body Text - Large", "element": "p", "classes": { "base": "body-text body-text--lg", // Applied to every child node "variants": ["body-text--bold", "body-text--regular"] // Looped through, one class applied to each example. Each item in the array is its own node. }, "properties": "Proxima Nova Bold and Regular, 20px", "usage": ["Large button title", "Form label", "Large modal text"] }

Here’s how that renders:

<div class="row"> <!-- Column 1 --> <p class="group"> <span class="body-text body-text--lg body-text--bold">Body Text - Large</span> <span class="body-text body-text--lg body-text--regular">Body Text - Large</span> </p> <!-- Column 2 --> <p class="group body-text body-text--md body-text--semibold"> <span>body-text body-text--lg body-text--bold</span> <span>body-text body-text--lg body-text--regular</span> </p> <!-- Column 3 --> <p class="body-text body-text--md body-text--semibold">Proxima Nova Bold and Regular, 20px</p> <!-- Column 4 --> <p class="group body-text body-text--md body-text--semibold"> <span>Large button title</span> <span>Form label</span> <span>Large modal text</span> </p> </div> The basic setup

We have a parent component, TypographyTable.vue, which contains the markup for the wrapper table element, and a child component, TypographyRow.vue, which creates a row and contains our render function.

I loop through the row component, passing the row data as props.

<template> <section> <!-- Headers hardcoded for simplicity --> <div class="row"> <p class="body-text body-text--lg-bold heading">Hierarchy</p> <p class="body-text body-text--lg-bold heading">Element/Class</p> <p class="body-text body-text--lg-bold heading">Properties</p> <p class="body-text body-text--lg-bold heading">Usage</p> </div> <!-- Loop and pass our data as props to each row --> <typography-row v-for="(rowData, index) in $options.typographyData" :key="index" :row-data="rowData" /> </section> </template> <script> import TypographyData from "@/data/typography.json"; import TypographyRow from "./TypographyRow"; export default { // Our data is static so we don't need to make it reactive typographyData: TypographyData, name: "TypographyTable", components: { TypographyRow } }; </script>

One neat thing to point out: the typography data can be a property on the Vue instance and be accessed using $options.typographyData since it doesn’t change and doesn’t need to be reactive. (Hat tip to Anton Kosykh.)

Making a functional component

The TypographyRow component that passes data is a functional component. Functional components are stateless and instanceless, which means that they have no this and don’t have access to any Vue lifecycle methods.

The empty starting component looks like this:

// No <template> <script> export default { name: "TypographyRow", functional: true, // This property makes the component functional props: { rowData: { // A prop with row data type: Object } }, render(createElement, { props }) { // Markup gets rendered here } } </script>

The render method takes a context argument, which has a props property that’s de-structured and used as the second argument.

The first argument is createElement, which is a function that tells Vue what nodes to create. For brevity and convention, I’ll be abbreviating createElement as h. You can read about why I do that in Sarah’s post.

h takes three arguments:

  1. An HTML tag (e.g. div)
  2. A data object with template attributes (e.g. { class: 'something'})
  3. Text strings (if we’re just adding text) or child nodes built using h
render(h, { props }) { return h("div", { class: "example-class" }, "Here's my example text") }

OK, so to recap where we are at this point, we’ve covered creating:

  • a file with the data that’s going to be used in my visualization;
  • a regular Vue component where I’m importing the full data file; and
  • the beginning of a functional component that will display each row.

To create each row, the data from the JSON file needs to be passed into arguments for h. This could be done all at once, but that involves a lot of conditional logic and is confusing.

Instead, I decided to do it in two parts:

  1. Transform the data into a predictable format.
  2. Render the transformed data.
Transforming the common data

I wanted my data in a format that would match the arguments for h, but before doing this, I wrote out how I wanted things structured:

// One cell { tag: "", // HTML tag of current level cellClass: "", // Class of current level, null if no class exists for that level text: "", // Text to be displayed children: [] // Children each follow this data model, empty array if no child nodes }

Each object represents one cell, with four cells making up each row (an array).

// One row [ { cell1 }, { cell2 }, { cell3 }, { cell4 } ]

The entry point would be a function like:

function createRow(data) { // Pass in the full row data and construct each cell let { text, element, classes = null, properties, usage } = data; let row = []; row[0] = createCellData(data) // Transform our data using some shared function row[1] = createCellData(data) row[2] = createCellData(data) row[3] = createCellData(data) return row; }

Let’s take another look at our mockup.

The first column has styling variations, but the rest seem to follow the same pattern, so let’s start with those.

Again, the desired model for each cell is:

{ tag: "", cellClass: "", text: "", children: [] }

This gives us a tree-like structure for each cell since some cells have groups of children. Let’s use two functions to create the cells.

  • createNode takes each of our desired properties as arguments.
  • createCell wraps around createNode so that we can check if the text that we’re passing in is an array. If it is, we build up an array of child nodes.
// Model for each cell function createCellData(tag, text) { let children; // Base classes that get applied to every root cell tag const nodeClass = "body-text body-text--md body-text--semibold"; // If the text that we're passing in as an array, create child elements that are wrapped in spans. if (Array.isArray(text)) { children = text.map(child => createNode("span", null, child, children)); } return createNode(tag, nodeClass, text, children); } // Model for each node function createNode(tag, nodeClass, text, children = []) { return { tag: tag, cellClass: nodeClass, text: children.length ? null : text, children: children }; }

Now, we can do something like:

function createRow(data) { let { text, element, classes = null, properties, usage } = data; let row = []; row[0] = "" row[1] = createCellData("p", ?????) // Need to pass in class names as text row[2] = createCellData("p", properties) // Third column row[3] = createCellData("p", usage) // Fourth column return row; }

We pass properties and usage to the third and fourth columns as text arguments. However, the second column is a little different; there, we’re displaying the class names, which are stored in the data file like:

"classes": { "base": "body-text body-text--lg", "variants": ["body-text--bold", "body-text--regular"] },

Additionally, remember that headings don’t have classes, so we want to show the heading tag names for those rows (e.g. h1, h2, etc.).

Let’s create some helper functions to parse this data into a format that we can use for our text argument.

// Pass in the base tag and class names as arguments function displayClasses(element, classes) { // If there are no classes, return the base tag (appropriate for headings) return getClasses(classes) ? getClasses(classes) : element; } // Return the node class as a string (if there's one class), an array (if there are multiple classes), or null (if there are none.) // Ex. "body-text body-text--sm" or ["body-text body-text--sm body-text--bold", "body-text body-text--sm body-text--italic"] function getClasses(classes) { if (classes) { const { base, variants = null } = classes; if (variants) { // Concatenate each variant with the base classes return variants.map(variant => base.concat(`${variant}`)); } return base; } return classes; }

Now we can do this:

function createRow(data) { let { text, element, classes = null, properties, usage } = data; let row = []; row[0] = "" row[1] = createCellData("p", displayClasses(element, classes)) // Second column row[2] = createCellData("p", properties) // Third column row[3] = createCellData("p", usage) // Fourth column return row; } Transforming the demo data

This leaves the first column that demonstrates the styles. This column is different because we’re applying new tags and classes to each cell instead of using the class combination used by the rest of the columns:

<p class="body-text body-text--md body-text--semibold">

Rather than try to do this in createCellData or createNodeData, let’s make another function to sit on top of these base transformation functions and handle some of the new logic.

function createDemoCellData(data) { let children; const classes = getClasses(data.classes); // In cases where we're showing off multiple classes, we need to create children and apply each class to each child. if (Array.isArray(classes)) { children = classes.map(child => // We can use "data.text" since each node in a cell grouping has the same text createNode("span", child, data.text, children) ); } // Handle cases where we only have one class if (typeof classes === "string") { return createNode("p", classes, data.text, children); } // Handle cases where we have no classes (ie. headings) return createNode(data.element, null, data.text, children); }

Now we have the row data in a normalized format that we can pass to our render function:

function createRow(data) { let { text, element, classes = null, properties, usage } = data let row = [] row[0] = createDemoCellData(data) row[1] = createCellData("p", displayClasses(element, classes)) row[2] = createCellData("p", properties) row[3] = createCellData("p", usage) return row } Rendering the data

Here’s how we actually render the data to display:

// Access our data in the "props" object const rowData = props.rowData; // Pass it into our entry transformation function const row = createRow(rowData); // Create a root "div" node and handle each cell return h("div", { class: "row" }, row.map(cell => renderCells(cell))); // Traverse cell values function renderCells(data) { // Handle cells with multiple child nodes if (data.children.length) { return renderCell( data.tag, // Use the base cell tag { // Attributes in here class: { group: true, // Add a class of "group" since there are multiple nodes [data.cellClass]: data.cellClass // If the cell class isn't null, apply it to the node } }, // The node content data.children.map(child => { return renderCell( child.tag, { class: child.cellClass }, child.text ); }) ); } // If there are no children, render the base cell return renderCell(data.tag, { class: data.cellClass }, data.text); } // A wrapper function around "h" to improve readability function renderCell(tag, classArgs, text) { return h(tag, classArgs, text); }

And we get our final product! Here’s the source code again.

Wrapping up

It’s worth pointing out that this approach represents an experimental way of addressing a relatively trivial problem. I’m sure many people will argue that this solution is needlessly complicated and over-engineered. I’d probably agree.

Despite the up-front cost, however, the data is now fully separated from the presentation. Now, if my design team adds or removes rows, I don’t have to dig into messy HTML — I just update a couple of properties in the JSON file.

Is it worth it? Like everything else in programming, I guess it depends. I will say that this comic strip was in the back of my mind as I worked on this:

Source: https://xkcd.com/974

Maybe that’s an answer. I’d love to hear all of your (constructive) thoughts and suggestions, or if you’ve tried other ways of going about a similar task.

The post A Practical Use Case for Vue Render Functions: Building a Design System Typography Grid appeared first on CSS-Tricks.

Customer Satisfaction Surveys with Wufoo

Css Tricks - Thu, 05/30/2019 - 5:06am

I was once tasked to create a makeshift customer service survey that would allow an employee to receive a customer call and send a survey to the custom once the call ended. The goal was to track customer satisfaction, which is a totally legit thing to want.

There are some solutions out there that do this out of the box. The problem was that my client neither had the desire or budget to use them. They did, however already use Campaign Monitor for sending emails and Wufoo for embedded forms. I figured, hey, if MacGyver can create complex gadgets out of bubble gum and paper clips, then I can cobble something together with these two robust tools. Right?

Right!

Knowing the data

The biggest challenge for a phone call is that it's sometimes difficult to track down an email address during the call. Without that, there's nowhere to send the survey, so that's a big bummer. That means the employee needs to capture the address, whether it's getting a custom ID at the start of the call or straight up asking for it.

I decided I would spin up Wufoo to create an internal form that employees can use to capture the data. Nothing fancy, only the following fields:

  • Employee Name: Used to associate the employee with the call
  • Customer Name: Used to personalize the email sent containing the survey link
  • Customer Email: Used to send the survey link

Wufoo makes this trivial, of course. Create a new form, add a few text fields, copy and paste the snippet onto a page. Voilà! We have a form! We could make it a little simpler (and dummy-proof) by creating a select field containing all employee names so the data remains consistent. We can also make the fields required and use Wufoo's built-in validation to ensure the email address is properly formatted.

There's also a lot of flexibility with the styling to boot, meaning the form can look like a native part of the site.

The employee can now fill that out during the call and submit it once the call is done. Plus, the form is embedded on a private page that can't accidentally get out to others.

Sending the survey

Did you know Wufoo can auto-send emails anywhere once a form is completed? Well, now you do!

This is super handy for most cases and I really wanted to use it for this task, but decided to go with Campaign Monitor because there's one little snag which is...

Each employee needs a unique survey form

Yep, that's a thing. Otherwise, we'd have to ask the customer to identify the employee's name in the survey, which we can't expect them to know. Sure, we could use another select field, but that requires the customer to recall the name as well, and not having the employee name makes it difficult to associate customer satisfaction results with specific employees for tracking.

So, the email needs to contain a unique link that goes to a form that's associated with a specific employee. Again, there are solutions for this stuff, but we're MacGyver'ing this thing.

I'm so glad Wufoo makes building forms so simple. All I needed to do was create one form, duplicate it for each employee, and change the employee value in each one.

On that note, we don't necessarily need to display the employee's name in the survey form. Wufoo accepts custom CSS which means we can hide any field! Plus, it allows us to pre-populate a field, so that gives us hidden fields that already contains the values we need to associate the survey data with a specific employee and create a webpage containing the form for that employee. &#x1f4a5;

Hidden fields are, well...hidden!

Now that there's a survey for each employee, all I needed to do was create webpages where I could embed each employee form and use those as the survey links.

Here's the flow:

Auto-sending the survey link

Let's go back to the first form for a moment. Remember, that's the one an employee fills out and submits once the call has ended. This should send an email to the customer containing a link to the webpage that has the survey form for that employee.

Campaign Monitor can segment lists by custom variables. In other words, we can create one list that contains all of the customers who have called in and create sub-lists that are divided by employee since we have that as a value in the internal employee form. And, since Campaign Monitor and Wufoo play nice together, all of the data we capture is contained in both places.

The other thing Campaign Monitor can do is trigger emails to send based on conditions. So, if the employee submits the internal form, Campaign Monitor can be configured to send a specific email template/campaign to a new subscriber that is added to the list. If we set up a trigger to send an email to any new customer who is added to the list, we can personalize the email to contain the link for the employee who took the call.

Watch the data roll in!

Great! We have a form employees can use to send a survey, surveys set up on webpages for each employee, and an auto-triggered email that's sent to a customer containing the survey link for the employee who submitted the internal survey.

All that's left is to monitor the data and — wouldn't you know it — Wufoo has reporting built right into it where all of that can be accessed and monitored 24/7. Heck, it even permits us to create custom reporting dashboards on a per-survey basis.

Wrapping up

Was this the best way to hack things together? Probably not. Is it bulletproof from incorrect data or misuse? Not entirely. But the fact that Wufoo could intervene at all and is flexible enough to power this sort of thing is awesome. It's more than awesome; it's amazing. It sure wasn't intended to be used that way, but it did the trick anyway.

Thanks, Wufoo!

The post Customer Satisfaction Surveys with Wufoo appeared first on CSS-Tricks.

UX Design Career Track [Sponsored]

Usability Geek - Wed, 05/29/2019 - 9:52am
If you want to break into a new creative field, there has never been a better time to become a UX designer. And Springboard can help you make your move. Springboard is an online school for learning...
Categories: Web Standards

A Quick Look at the First Public Working Draft for Color Adjust Module 1

Css Tricks - Wed, 05/29/2019 - 8:04am

We've been talking a lot about Dark Mode around here ever since Apple released it as a system setting in MacOS 10.14 and subsequently as part of Safari. It's interesting because of both what it opens up as as far as design opportunities as well as tailoring user experience based on actual user preferences.

This week, we got an Editor's Draft for the Color Adjust Module Level 1 specification and the First Public Working Draft of it. All of this is a work-in-progress, but the progression of it has been interesting to track. The spec introduces three new CSS properties that help inform how much control the user agent should have when determining the visual appearance of a rendered page based on user preferences.

color-scheme is the first property defined in the spec and perhaps the centerpiece of it. It accepts light and dark values which — as you may have guessed — correspond to Light Mode and Dark Mode preferences for operating systems that support them. And, for what it's worth, we could be dealing with labels other than "Light" and "Dark" (e.g. "Day" and "Night") but what we're dealing with boils down to a light color scheme versus a dark one.

Source: developer.apple.com

This single property carries some important implications. For one, the idea is that it allows us to set styles based on a user's system preferences which gives us fine-grained control over that experience.

Another possible implication is that declaring the property at all enables the user agent to take some responsibility for determining an element's colors, where declaring light or dark informs the user agent that an element is "aware" of color schemes and should be styled according to a preference setting matching the value. On the other hand, we can give the browser full control to determine what color scheme to use based on the user's system preferences by using the auto value. That tells the browser that an element is "unaware" of color schemes and that the browser can determine how to proceed using the user preferences and a systems's default styling as a guide.

It's worth noting at this point that we may also have a prefers-color-scheme media feature (currently in the Editor's Draft for the Media Queries Level 5 specification) that also serves to let us detect a user's preference and help gives us greater control of the user experience based on system preferences. Robin has a nice overview of it. The Color Adjust Module Level 1 Working Draft also makes mention of possibly using a color scheme value in a <meta> element to indicate color scheme support.

There's more to the property, of course, including an only keyword, chaining values to indicate an order of preference, and even an open-ended custom ident keyword. So definitely dig in there because there's a lot to take in.

Pretty interesting, right? Hopefully you're starting to see how this draft could open up new possibilities and even impacts how we make design decisions. And that's only the start because there are two more properties!

  • forced-color-adjust: This is used when we want to support color schemes but override the user agent's default stylesheet with our own CSS. This includes a note about possibly merging this into color-adjust.
  • color-adjust: Unlike forcing CSS overrides onto the user agent, this property provides a hint to browsers that they can change color values based on the both the user's preferences and other factors, such as screen quality, bandwidth, or whatever is "deem[ed] necessary and prudent for the output device." Eric Bailey wrote up the possibilities this property could open up as far as use cases, enhanced accessibility, and general implementations.

The current draft is sure to expand but, hey, this is where we get to be aware of the awesome work that W3C authors are doing, gain context for the challenges they face, and even contribute to the work. (See Rachel Andrew's advice on making contributions.)

The post A Quick Look at the First Public Working Draft for Color Adjust Module 1 appeared first on CSS-Tricks.

The difference between keyboard and screen reader navigation

Css Tricks - Wed, 05/29/2019 - 8:02am

There are a few differences between keyboards and screen readers and Léonie Watson highlights of them:

When using the tab key, keyboard focus and screen reader focus are synchronised with each other. The rest of the time, screen reader users have an enormous range of commands at their disposal for reading and navigating content independently of keyboard focus. The commands vary between screen readers, but they all have one thing in common: they’re tied to different HTML elements.

This is also a good reminder that screen readers behave differently from one another. It’s worth doing some research to see how our sites work in all these environments. One thing is clear from this post though: writing semantic and concise HTML is the best way to improve accessibility for both users with keyboards and screen readers. For example, Scott O'Hara has this recent post on best practices using the tabindex attribute to ensure accessible navigation using the keyboard.

Direct Link to ArticlePermalink

The post The difference between keyboard and screen reader navigation appeared first on CSS-Tricks.

Creating Interactive Maps in WordPress with MapSVG

Css Tricks - Wed, 05/29/2019 - 4:53am

The MapSVG plugin for WordPress allows you to create feature-rich, interactive maps quickly and through a smart admin UI. Interactive maps are a common request for projects when you need to visualize impact over particular locations. If you are already on WordPress, this comprehensive plugin could be your solution for production-ready maps.

Think about the last time you implemented or scoped an interactive map. You may wind up estimating a significant amount of time for mapping your data from its original source into JSON to be hooked to a visualization framework, like D3. Then comes configuring how users interact with the map itself. These are already significant development lifts.

Next comes the question of how you will manage your map data. Did it live in an external file? Require regular API calls to fetch data? It would be a lot easier to manage this data directly within your site’s WordPress admin as you would all other site content. No need to open up a code editor and maintain the map separately!

These and many other common map functionalities come baked into the MapSVG plugin for you to create multiple unique maps to fit your visualization needs. We’re going to dig into the plugin a little bit and use it to build an interactive SVG-based map in WordPress

Options for creating new maps

Once installed, MapSVG gives you five options for creating a new map based on vector, image, or Google Maps features. For the sake of this article, I will be focusing on the SVG features.

Choose between SVG, flat images and Google Maps as the base for each new map.

Within that New SVG map option are nearly 200 geo-calibrated and un-calibrated vector maps of countries and regions. The free version of this plugin, MapSVG Lite, lets site administrators create interactive maps with tooltips, customizable detail views, and markers placed by latitude/longitude coordinates. Upgrading to the paid version ($46) provides support for: map directory, integrated search, location filters, a detailed view of a map region, integrations with WordPress posts and Advanced Custom Fields, custom tooltips, and choropleth maps, among other premium features.

Creating a new map

Right, so we’ve chosen to create a new SVG-based map. Select one of the options from the dropdown to create a vector map. Whenever possible, choose geo-calibrated maps over ones that are un-calibrated. Geo-calibrated maps are newer and have region titles. Plus, they allow you to add map markers by geo-coordinates (i.e. latitude and longitude), or by entering an address that automatically converts to coordinates.

If using your own custom SVG file, select the Upload SVG option. Once uploaded, your custom file will be available in the New SVG Map dropdown under user-uploads/your-file-name.svg. There are a few additional steps I recommend to optimize your file prior to uploading it to the plugin's map:

  1. Regions that contain multiple vector paths (e.g. Hawaii), need to be grouped as a compound path in Illustrator. In Illustrator, this can be done by selecting the relevant paths, then going to Object > Compound Path > Make (or CMD + 8).
  2. Optimized custom SVG map of U.S. + British Columbia

  3. Ensure your layers have clear, unique names. The layer name will be used as the region {{id}} for templating and organizational purposes.
  4. Next, open your SVG file in a text editor and give each path a title attribute. This will be used as the region {{title}} in the templates.

The id and title fields are default attributes pulled from the file to associate them with the individual paths. As of the latest release (currently 5.3.7) of the plugin, you can edit the SVG file directly in the WordPress admin to set the id and title values of each path, along with adjusting the path definition and drawing new paths. I personally prefer the control of editing in Illustrator and a code editor, but this is a nice option to have available to you.

Let’s proceed by creating a demo using the geo-calibrated maps provided by the plugin and using entries from https://confs.tech to visualize (some of) this year’s tech conference data from around the world.

Styling the map

Now that we’ve got our SVG file all set up and selected for use, the plugin interface opens to the settings panel. This is where we set the map name, define sizing dimensions, and enable tooltips, among other primary settings.

Alongside the settings tab, you will see tabs for controlling and setting specific map features. Switching over to the next tab, Colors, is where we set the map theme.

As you can see above, we can control the fill and stroke values of the map and the various active states of each path. A benefit of using a vector based map! For that reason, I prefer to leave the fill and stroke values undefined in Illustrator if I’m creating a custom map file. Stroke width, however, cannot be efficiently adjusted within the UI (because it would requires editing the SVG and changing the value for every single path), so it is best to set it in Illustrator and re-upload the file.

Further down are color options for the containers (e.g. directory, filters, sidebars, etc.) as well as the minimum and max colors values for a choropleth map (more on this later!). Container styles can also be set globally either in your theme’s stylesheet or in the setting's CSS tab.

Setting up map data

By default, the Regions tab will be pre-populated by regions based on the paths of the selected SVG, displaying their id and title values. You can edit and create your own region’s fields as needed. The same applies for the Database tab — where you enter your map data and associate it with the regions of the map.

For both region and database entries, you have the option of manually creating the fields and content in the UI or upload the data from a CSV file.

This conference_count custom field will be used for the choropleth feature to create a thematic map of countries that have technical conferences this year, from least to most. Populating the Conference Count region's custom field. The populated database entries and the overlay displaying the data in the detailed view template.

Notice the final dataset in the screenshot above, specifically the custom Regions fields for conference_details, conference details, and a field to upload images that display the flag of each country in the database. We can take this a step further by separating the content from the map itself and pulling it in as post data of any WordPress post type. That’s where Advanced Custom Fields can help to create fields for that data in the post editor and creating a relationship between the submitted data to populate the values in the map. Not required, of course, but it’s nice to have this option for the sake of separation of concerns.

Displaying map data

When showing information about a region or database object on a map, we have to set up a template in the plugin. There are five types of templates: popovers, tooltips, detail view, directory, and labels.

Templates accept plain text, HTML, and Handlebar markup to display region and database variable values. If pulling in post data via the Post database field, you will have access to the standard WordPress fields, post.id, post.post_title, post.post_content, post.url, along with any custom fields created with Advanced Custom Fields with this syntax: post.acf.my_field_name. Whenever you need to render a rich text field such as with
post.post_content, you have to use Handlebars' {{{triple-stash}}} syntax to output the rendered HTML.

Details View template showing Handlebars conditional content and default helper comments.

The use of Handlebar syntax also means we can build conditional logic into the templates to create dynamic template views based on region and database values. In MapSVG 5.0 and up, the template options come pre-populated with HTML comments and starter markup for the default region and database fields. Super helpful!

Adding a map to a page

MapSVG includes a shortcode used to embed a map on any page or post. Drop a Gutenberg shortcode block on the page and call MapSVG with the ID of the map to embed: [mapsvg id="418"].

SVG equals 418 inside of square brackets." />Embedding a map using the shortcode block in the Gutenberg editor.

For those working in the classic WordPress editor or with a plugin version that predates 5.0, a map icon will be added to the TinyMCE toolbar, which will inject the shortcode to your post content that takes the map ID. The map ID can be found in the MapSVG editor dashboard or in the top breadcrumbs of the active map. A handy Copy to clipboard button is included next to both instances shortcode to grab it for use in the post editor.

Demo

With data entry complete and a few toggles of additional MapSVG settings, we have a fully functional interactive and responsive map! And notice just how little code we had to touch along the way.

View Full Demo

Going beyond maps

The great thing about the SVG feature of the plugin is that, at it’s core, SVG can be whatever we want. You can create an interactive "map" from the vector paths of just about anything: a building floor plan, an infographic, or maybe an interactive timeline of your career? It’s more than just maps!

Not on WordPress? No problem. MapSVG also comes as a jQuery plugin that's equally worth trying for interactive maps outside of WordPress.

Resources

The post Creating Interactive Maps in WordPress with MapSVG appeared first on CSS-Tricks.

Color contrast accessibility tools

Css Tricks - Tue, 05/28/2019 - 1:02pm

Accessibility is all the rage these days, specifically when it comes to color contrast. I’ve stumbled upon a couple of tools this week that I think are pretty nifty for helping make sure that all of the text on our websites is legible regardless of what background color they might have.

First up is the Accessible Color Generator which happens to be a wonderful tool for picking alternative colors. Let’s say you’re working on a brand with color X. You can generate a host of other complimentary colors like this:

Next up is Contrast, a rather great MacOS app that sits in the menu bar at all times and helps identify accessible color pairings based on WCAG Guidelines. This one is particularly useful if you happen to be a designer:

This reminds me of a wonderful post about how the Lyft design team re-approached the way they use color in their app. Kevyn Arnott explains:

Color, at least on the surface, appears almost naively simple, yet as it scales across larger products it becomes unbelievably complex. You have thousands of people building products all at once, and those products are all heavily reliant on color. This puts a lot of pressure on the color system to ensure that all the products are being created consistently, but very hard to implement since it’s all too easy to apply colors on a one-off basis.

The team then went ahead and built ColorBox.io which lets you systematically build out a ton of colors for your design systems work. It’s pretty nifty!

Plus the folks over at GOV.UK made their own color accessibility tool called Contrast Checker which (as you have guessed by the name) helps check the contrast between the background of an element and the page itself:

And, of course, there's the trusty WebAIM contrast checker, which is a go-to for many developers out there.

So far, we've looked at tools that check contrast. But there is a class of tooling that can automate accessible contrasts during development. Josh Bader wrote up an approach that enforces high contrast by pairing CSS custom properties with the calc() function. Facundo Corradini did something similar that switches font color based on the background color behind it.

Oh! And we may have something to look forward to with the color-adjust property. It is proposed in the CSS Color Module Level 4 specification and could give browsers more control to adjust color values that are declared in the stylesheet. It's not really geared towards color contrast, but there's something interesting about handing off the responsibility of rendering color values to the browser based on certain conditions.

The post Color contrast accessibility tools appeared first on CSS-Tricks.

Using the Grid Shepherd Technique to Order Data with CSS

Css Tricks - Tue, 05/28/2019 - 5:08am

Shepherds are good at tending to their sheep, bringing order and structure to their herds. Even if there are hundreds of those wooly animals, a shepherd still herds them back to the farm at the end of the day.

When dealing with data, programmers often don't know if it is correctly filtered or sorted. This is especially painful when iterating over an array then displaying the data on a site without knowing the locations of each element receiving it. The Grid Shepherd is a technique that helps position and sort items where you want them to be, using CSS Grid instead of JavaScript.

That’s what we’re going to look at in this post. The Grid Shepherd technique can bring order and structure to the data we work with while giving us greater visibility to where and how it’s being used than we would be able to otherwise.

Let’s dig in.

Sorting with JavaScript

We’re going to start by iterating over an unordered array of farm animals. Imagine that cows and sheep are happily grazing the fields. They can be grouped together programmatically with the Array.prototype.sort method and listed on a page:

let animals = [ { name: 'Edna', animal: 'cow' }, { name: 'Liam', animal: 'sheep' }, { name: 'Fink', animal: 'sheep' }, { name: 'Olga', animal: 'cow' }, ] let sortedAnimals = animals.sort((a, b) => { if (a.animal < b.animal) return -1 if (a.animal > b.animal) return 1 return 0 }) console.log(sortedAnimals) /* Returns: [ { name: 'Elga', animal: 'cow' }, { name: 'Olga', animal: 'cow' }, { name: 'Liam', animal: 'sheep' }, { name: 'Fink', animal: 'sheep' } ] */ Meet the Grid Shepherd

The Grid Shepherd method makes sorting data possible without the use of JavaScript. Instead, we rely on CSS Grid to do the lifting for us.

The structure is exactly the same as the JavaScript array of objects above, only represented in DOM nodes instead.

<main> <div class="cow">Edna</div> <div class="sheep">Liam</div> <div class="sheep">Jenn</div> <div class="cow">Fink</div> </main>

See the Pen
1. Start
by David Bernegger (@Achilles_2)
on CodePen.

To herd the animals, we have to fence them into a common area, which is what we’re using the <main> element to do. By setting that fence with display: grid, we’re creating a grid formatting context where we can define the column (or row) each animal should occupy.

.sheep { grid-column: 1; } .cow { grid-column: 2; }

And with grid-auto-flow: dense, each animal orders itself into the first available spot of each defined area. This can also be used with as many different sort options as you want — simply define another column and the data will be shepherded magically into it.

main display: grid; grid-auto-flow: dense; } .sheep { grid-column: 1; } .cow { grid-column: 2; }

See the Pen
2. Final
by David Bernegger (@Achilles_2)
on CodePen.

Pro Shepherding

We can take our herding example further with CSS Counters. That way, we can count how many animals we have in each column and — applying Heydon Pickering's quantity queries from Lea Verou's Talk in 2011 — conditionally style the them depending on how many there are.

Quantity queries rely on some sort of selector for counting the classes — which would be great with the :nth-child(An+B [of S]?) pseudo-class notation, but it’s currently only available in Safari). That means we have to use the :nth-of-type() selector as a workaround.

We need some new element types for this to work. This could be realized through Web Components or renaming any HTML element to a custom name. This works even if these elements are not in the HTML spec, as browsers use HTMLUnknownElement for undefined tags which results in them behaving much like a div. The document looks now like this:

<fence> <sheep>Lisa</sheep> <sheep>Bonnie</sheep> <cow>Olaf</cow> <sheep>Jenn</sheep> </fence>

Now we can access our custom element types. Let’s apply a red background when the number of sheep or the cows is equal to or less than 10.

sheep:nth-last-of-type(n+10), sheep:nth-last-of-type(n+10) ~ sheep, cow:nth-last-of-type(n+10), cow:nth-last-of-type(n+10) ~ cow, { background-color: red; }

Additionally the the counters can be simply realized by using counter-reset: countsheep countcow; on the parent element and using the before selector to target each element and count up.

sheep::before { counter-increment: countsheep; content: counter(countsheep); }

Here, we’re going to reach for Vue to dynamically add and remove animals using Vue transitions with two different sort options. Watch as the animals naturally occupy the correct columns, even as more are added and some are removed:

See the Pen
3. Final with Vue Transitions
by David Bernegger (@Achilles_2)
on CodePen.

Grid Shepherd can also be used with any non-ordered data to:

  • separate and count voters in a poll (maybe as two sections with their corresponding profile picture) with live insertion;
  • group people / co-workers according to their position, age, height; and
  • create any hierarchical structure
Shepherding and accessibility

grid-auto-flow: dense does not change the DOM structure of the grid — it merely reorders the contained elements visually. A side effect can be seen in the last example when ordering alphabetically as the counter numbers get mixed up. Changing the DOM structure not only affects people who use screen readers, but also effects tab traversal.

Also note that a flat document structure might not be good for screen readers. Instead, I would treat these presentational grids as graphs and provide the information with a longer textual alternative.

Round ‘em up!

It’s pretty neat to see how a powerful CSS layout tool like grid can be leveraged for use cases that fall outside of traditional layouts needs and into things where we may have reached for other languages in the past. In this case, we can see how the layout benefits of CSS Grid and the dynamic data-handling capabilities of JavaScript overlap and how that gives us more choices — and power — to bend rendered data to our will.

The post Using the Grid Shepherd Technique to Order Data with CSS appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.