Archiwum kategorii: CSS

Production Progressive Web Apps with JavaScript Frameworks

Post pobrano z: Production Progressive Web Apps with JavaScript Frameworks

This last week at Google I/O, Addy Osmani announced some amazing developer resources for creating Progressive Web Applications (PWAs) that prioritize performance with JavaScript Frameworks.

This was truly a team effort- a lot of people worked on these projects to get them going, and it’s a really valuable contribution to the community. A lot of people want better performance for their framework of choice but can’t get buy-in for time and resources to devote to this kind of endeavor. The ability to start with a baseline of high performance and good lighthouse scores is incredibly valuable, allowing developers to enjoy both the productivity and ergonomics of exciting frameworks, without sacrificing speed and user experience.

Here are some of the highlights!

Addy created a site to explore some of the templates that they built out with the different PWA solutions, as a successor to the very popular TodoMVC, called HN PWA. You can explore all of the demos and the GitHub repo here. He then went through some major company implementations of each of the frameworks rebuilt as PWAs. Throughout a lot of the case studies that Addy features, the heavy-hitters in building for better web experiences lied in link rel=preload, requestIdleCallback(), and HTTP2 Server Push. There were many mentions the PRPL pattern, in essence prioritizing what you’re going to use first, by Pushing critical resources for the initial URL route, Rendering the initial route, Pre-caching remaining routes, and Lazy-loading and create remaining routes on demand. A lot of the performance wins were framed within the ability to be interactive on mobile within 5 seconds and trying to lower the overhead of the framework itself so that you had more time in that 5 seconds for your own application code.

React

React announced that Create React App will now be a PWA by default! This is a big win here. They now employ service workers with an offline-first caching strategy, code-splitting with dynamic import(), helpful overlays for errors, and it gives you 1.5s of headroom for your application code. More information on the release here.

Preact

Now has a CLI! Announced at the event, this is a pretty amazing development worth playing around with. You can find the project here. Among other really nice features you can read through in the readme, it has a 100/100 Lighthouse score out of the box, as well as a whopping 3s of headroom to work on your own application code.

If you’re not familiar with Preact, it’s an extremely fast 3kb React alternative with the same API, including the use of components & virtual DOM. It’s similar to React, but the small filesize is central to the software design. The only caveat mentioned is that due to its emphasis on slim builds, there may be offerings in the React ecosystem that still need work for seamless integration. That said, Preact was the clear winner in performance here, so I wouldn’t be surprised to see the community rally around this solution.

Vue

Vue announced a PWA template, offered directly from Vue-cli, which you can access easily with vue init pwa.

vue init pwa from within vue-cli

Among a lot of great offerings, it gives you two 2s of headroom for application code on mobile, code-splitting with dynamic import(), service worker for offline caching, and JS chunks are preloaded or prefetched.

If you’re not familiar with Vue, I’ve written up a guide here. I think Vue is an amazing piece of software, and the ability to strike all of the lighthouse credentials out of the gate is pretty incredible. This workflow makes it so easy to create beautiful and complex apps.

There are many more details that I didn’t get to in this post, and Addy is a great speaker. He even created a video game for his talk. It’s a worthwhile watch the whole way through, you can view it here:


Production Progressive Web Apps with JavaScript Frameworks is a post from CSS-Tricks

A Unified Styling Language

Post pobrano z: A Unified Styling Language

This article by Mark Dalgleish will go down as one of the most important front-end development articles of 2017.

It’s about the hot topic that is „CSS in JavaScript”. Mark walks us through how that’s actually not a simple and singular idea, but a continuum of concepts and implementations. There are lots of projects that all approach it in different ways. It’s likely that the best ways are the projects that actually generate real CSS. These things are a far cry from „inline styles”.

Regular ol’ CSS isn’t going anywhere, but these CSS in JS ideas aren’t either. There is some serious benefits to them for a lot of projects. Scoped styles preventing styling mistakes. Performance gains through critical styles. Only shipping the minimum amount of styles needed. Stylesheets that nobody is afraid of and don’t become the proverbial „append only” stylesheets. Not to mention that if you are going to be styling in a JavaScript environment, you get the possibility of dynamic styles and porting those styles to other platforms and such.

Direct Link to ArticlePermalink


A Unified Styling Language is a post from CSS-Tricks

Snap Animation States

Post pobrano z: Snap Animation States

There are many ways to make icons for a website. Inline SVG is scalable, easy to modify with CSS, and can even be animated. If you’re interested in learning more about the merits of using inline SVG, I recommend reading Inline SVG vs Icon Fonts. With ever increasing browser support, there’s never been a better time to start working with SVGs. Snap Animation States is a JavaScript plugin built around Snap.svg to help create and extend icon libraries with scaleable, editable SVG icons. Snap Animation States makes it easy to load and animate those SVGs with a simple schema.

Getting Started

Lets start with a basic SVG hamburger menu. This one was made using Affinity Designer, but there are many other free (Inkscape) and paid for (Adobe Illustrator) options available for making vector images.

<svg width="100%" height="100%" viewBox="0 0 65 60" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:square;stroke-miterlimit:1.5;"  fill="none" stroke="#000" stroke-width="10">
   <g>
      <path class="hamburger-top" d="m 5,10 55,0" />
      <path class="hamburger-middle" d="m 5,30 55,0" />
   </g>
   <path class="hamburger-bottom" d="m 5,50 55,0" />
</svg>

Although this is a pretty basic SVG, it still takes up multiple lines in an HTML document. This can be a pain to write if you want to use the SVG in multiple locations across several different web pages. And what if you have to modify your SVG? Then you’re scrambling to remember all the places you used the SVG so you can update it. It’s not very clean or reusable. This is what Snap Animation States is all about solving.

Let’s continue to use the same SVG, but this time we’ll use the plugin to load it to the DOM. The schema for the plugin requires at least two properties: selector: ".some-css-selector", and svg: "svg string". Check out the following demo:

See the Pen Lydgoo by Briant Diehl (@bkdiehl) on CodePen.

You’ll notice in the Pen above that I call icon-hamburger just like I would call a font icon. Just remember that the selector property needs a CSS selector as its value.

There’s more we can do since this plugin is an extension of Snap.svg, a JavaScript library used to create and animate SVGs. So let’s see what’s needed to give this hamburger icon some basic animation.

When I created my SVG, I added classes to the elements I knew I would be animating.

<g>
   <path class="hamburger-top" d="m 5,10 55,0" />
   <path class="hamburger-middle" d="m 5,30 55,0" />
</g>
<path class="hamburger-bottom" d="m 5,50 55,0" />

In my schema, I can start to include the properties needed for animation, and I start by giving it transitionTime: 250. The transition time is applied to each step in the transform chain and can be overridden later by an individual transform.

Now it’s time to include my animation states. I start by setting the property states:{}. The property names for this object should correlate to the state the animation will lead to. In this case I’m going to name my properties open and closed. The property values for this object are arrays of transform objects. So far, the additions to the schema should look like this:

transitionTime: 250,
states: {
  open:[],
  closed: []
}

Next, we need to include the transform objects that define how the SVG elements are to be transformed.

open:[
  { id: "top-lower", element: ".hamburger-top", y:20 },
  { id: "bottom-raise", element: ".hamburger-bottom", y:-20 },
  { waitFor: "top-lower", element: "g", r:45 },
  { waitFor: "bottom-raise", element: ".hamburger-bottom", r:-45},
]

Each transform object has either an id, a waitFor, or a combination of the two. Each id needs to be unique. Objects with an id represent a link in a chain of animations. waitFor always needs to reference a link id that precedes it. In this case there’s an object with id:"top-lower" and an object with waitFor:"top-lower". When the animation starts, id:top-lower will be the first link in the chain, and it will run for 250ms. When it has finished, waitFor:"top-lower" will run for 250ms.

Every transform object must reference an element. The element value can be either a css selector or a direct element reference. For example, one element property has the value of "g" referencing the <g> element in the SVG, while another has the value of ".hamburger-bottom", referencing the class I added to the <path> element.

Now that we know the order of animation and the elements that need to be transformed, we just need to define the transform objects. For those of you unfamiliar with how SVG transforms work, you could start with Transforms on SVG Elements. Otherwise, simply put, imagine that the SVG element you are manipulating starts at the points [0, 0] on an x/y axis. Something else to remember is that x goes left to right, while y goes from top to bottom. In the example above, we see:

{ id: "top-lower", element: ".hamburger-top", y:20 },

This transform object is referring to the top line of the hamburger menu. y: 20 is telling the plugin that, starting at the element’s point of origin [0, 0], I want to move the top line down 20px. The reverse is true for:

{ id: "bottom-raise", element: ".hamburger-bottom", y:-20 },

Here I’m telling the plugin to move my element up by 20px. The same principle applies to the rotations:

{ waitFor: "top-lower", element: "g", r:45 },
{ waitFor: "bottom-raise", element: ".hamburger-bottom", r:-45}

The element that’s being rotated starts at a rotation of 0 degrees. r: 45 is telling the plugin to rotate from 0 degrees to 45 degrees and vice versa for r: -45.

Our second state in the states object looks like this:

closed: [
  { id: "top-angle", element: "g", r: 0 },
  { id: "bottom-angle", element: ".hamburger-bottom", r: 0 },                   
  { waitFor: "top-angle", element: ".hamburger-top", y: 0 },
  { waitFor: "bottom-angle", element: ".hamburger-bottom", y: 0 }
]

You’ll notice that for all of the elements being transformed, their y and r values are set to 0. This is because this state’s purpose is to return the SVG elements to their original state. Since 0 was the point of origin, we’re just performing a transform on each of the elements that will return them to their origin.

We’re almost done. Now that the animation states are defined, I have to decide what’s going to initiate these animations. This requires one more property on the schema: events. events takes an array of objects, since you may want to initiate your animation with more than one event. For the hamburger icon, it’s going to look like this:

events: [
  { event: "click", state: ["open", "closed"] }
]

The object in the array may include the following properties:

  1. event: designed to listen for javascript events. The hamburger icon listens for a ‚click’ event on <i class="icon-hamburger"</i> since that’s what the selector in the schema references.
  2. state: takes either a string or an array. If the state here is "open", then when <i class="icon-hamburger"></i> is clicked, only the „open” animation would run on a click event. Since the value of state is an array, the click event will actually toggle between the „open” and „closed” animations. The array is only designed to take two values and enable toggling.
  3. The last property is optional: selector. By default this value is your schema selector + „animate”. In this case it would be icon-hamburger-animate. You can change the selector if you want by declaring it here. It’s purpose is to enable the javascript events to be tied to either a parent or sibling element of your SVG. For example, if I had an SVG that I wanted to animate inside of a button when the button was clicked, I would need to do this:
<button class="icon-hamburger-animate">
  <i class="icon-hamburger"></i>
</button>

Whew, we made it. Now it’s time to see the final product.

See the Pen bWwQJZ by Briant Diehl (@bkdiehl) on CodePen.

Was it worth it? You may be thinking, that’s a lot of work to just have a single icon. And I would agree with you. Which is why I created a Gulp plugin to help with the heavy lifting.

Gulp Animation States

So far, we have a single icon that we can use wherever I’ve included the schema. Ideally, the schema for icon-hamburger would be saved to a js file that gets bundled up and included site-wide, which means that I could call icon-hamburger wherever I want. What if this js file was autogenerated and contained the schema and plugin call for as many SVG icons as you had access to? You could have easy access library of SVG icons! That’s the purpose of Gulp Animation States. Make sure to check out the documentation here.

Let’s begin with the file structure. Say I went to IcoMoon and generated all the SVG files I needed for my new project. I would want to drop all these newly generated files into a folder in my project. Let’s call that folder `svg`. My file structure would look something like this:

svg
|-- icon-folder.svg
|-- icon-hamburger.svg
|-- icon-mic.svg
|-- icon-wall.svg
|-- icon-wrench.svg

Using Gulp Animation States I can combine all the SVG files in my `svg` folder into a single js file with the selector for each icon set according to the file name of the SVG. The file contents would look something like this:

var iconFolder = {"selector": ".icon-folder","svg": "<svg>Content</svg>"};
SnapStates(iconFolder);
var iconHamburger= {"selector": ".icon-hamburger","svg": "<svg>Content</svg>"};
SnapStates(iconHamburger);
var iconMic= {"selector": ".icon-mic","svg": "<svg>Content</svg>"};
SnapStates(iconMic);
var iconWall= {"selector": ".icon-wall","svg": "<svg>Content</svg>"};
SnapStates(iconWall);
var iconWrench= {"selector": ".icon-wrench","svg": "<svg>Content</svg>"};
SnapStates(iconWrench);

This file could be bundled up with the rest of a website’s key JavaScript, enabling SVG icon usage wherever it’s wanted. But what about the animations? How do they get included in this JavaScript file?

We already have the animation for the hamburger icon, so we’ll use that. In the `svg` folder, we need to create a new file called `icon-hamburger.js`. Note that it has the same name as it’s corresponding SVG file. Here is the new file structure:

svg
|-- icon-folder.svg
|-- icon-hamburger.svg
|-- icon-hamburger.js
|-- icon-mic.svg
|-- icon-wall.svg
|-- icon-wrench.svg

And the contents of `icon-hamburger.js` would be:

{
  transitionTime: 250,
  states: {
    open:[
      { id: "top-lower", element: ".hamburger-top", y:20 },
      { id: "bottom-raise", element: ".hamburger-bottom", y:-20 },
      { waitFor: "top-lower", element: "g", r:45 },
      { waitFor: "top-lower", element: ".hamburger-bottom", r:-45},
    ],
    closed: [
      { id: "top-angle", element: "g", r: 0 },
      { id: "bottom-angle", element: ".hamburger-bottom", r: 0 },                   
      { waitFor: "top-angle", element: ".hamburger-top", y: 0 },
      { waitFor: "bottom-angle", element: ".hamburger-bottom", y: 0 },
    ]
  },
  events: [
    { event: "click", state: ["open", "closed"] }
  ]
}

The Gulp plugin will look for js files with the same name as the SVG file it’s creating a schema for. Demonstrating the output again with the animation states:

var iconFolder = {"selector": ".icon-folder","svg": "<svg>Content</svg>"};
SnapStates(iconFolder);
var iconHamburger= {"selector": ".icon-hamburger","svg": "<svg>Content</svg>", "transitionTime":250,"states":{"open":[{"id":"top-lower","element":".hamburger-top","y":20},{"id":"bottom-raise","element":".hamburger-bottom","y":-20},{"waitFor":"top-lower","element":"g","r":45},{"waitFor":"top-lower","element":".hamburger-bottom","r":-45}],"closed":[{"id":"top-angle","element":"g","r":0},{"id":"bottom-angle","element":".hamburger-bottom","r":0},{"waitFor":"top-angle","element":".hamburger-top","y":0},{"waitFor":"bottom-angle","element":".hamburger-bottom","y":0}]},"events":[{"event":"click","state":["open","closed"]}};
SnapStates(iconHamburger);
var iconMic= {"selector": ".icon-mic","svg": "<svg>Content</svg>"};
SnapStates(iconMic);
var iconWall= {"selector": ".icon-wall","svg": "<svg>Content</svg>"};
SnapStates(iconWall);
var iconWrench= {"selector": ".icon-wrench","svg": "<svg>Content</svg>"};
SnapStates(iconWrench);

Using Gulp Animation States, you manage to retain smaller, bite-sized files that you can easily edit when you need to change something. Those bite-sized pieces compile nicely into a single file that can be bundled with other key components of your site, allowing quick and easy calls to include an SVG in your HTML document.

Further Examples

The hamburger icon was fairly simple, so let’s look at a few more complex icons. We’ll start with a speaker icon.

See the Pen WjoOoy by Briant Diehl (@bkdiehl) on CodePen.

You’ll notice that, overall, the schema is mostly the same. You’ll notice the property easing is new. easing has a default value of easeinout. Besides that, the only changes worth noticing are in my transform objects.

{ id: "waveline1", element: ".wave-line-1", x:-10, s:0.1, attr:{ opacity:.8 }, transitionTime: 250 },
{ id: "waveline2", element: ".wave-line-2", x:-16, s:0.1, attr:{ opacity:.8 }, transitionTime: 300 },
{ id: "waveline3", element: ".wave-line-3", x:-22, s:0.1, attr:{ opacity:.8 }, transitionTime: 350 }

s is for scale, and just like in css, an object’s scale always starts at 1. The attr property allows you to modify any attribute on an SVG element, in this case, the opacity. Finally, remember in the beginning of the article how I mentioned that transitionTime can be overridden by an individual transform? Well, here is how it’s done. I didn’t even declare transitionTime in the main schema. That’s because I wanted each transform to have a unique transition time.

Next, let’s look at a line drawing animation.

See the Pen OmbxVV by Briant Diehl (@bkdiehl) on CodePen.

The first major difference I want you to see is that I’m not declaring svg in the schema. The SVG is inside the <i class="icon-new-document"></i>. This is mostly for demo purposes, so as not to bloat the schema that I want you to be viewing. However, the plugin does allow for this functionality. The use case is for those users who only have a few SVG icons that they need in their document and don’t want to use the gulp plugin.

The transform objects are what I really want to focus on here. There’s a lot of new stuff going on here.

{ id: 'line1-init', element: ".new-document-line1", drawPath: { min: 25, max: 75 }, transitionTime: { min: 500, max: 1000 }, repeat: {times:1} },        
{ id: 'line2-init', element: ".new-document-line2", drawPath: { min: 25, max: 75 }, transitionTime: { min: 500, max: 1000 }, repeat: {times:1} },
{ id: 'line3-init', element: ".new-document-line3", drawPath: { min: 25, max: 75 }, transitionTime: { min: 500, max: 1000 }, repeat: {times:1} },
{ id: 'line4-init', element: ".new-document-line4", drawPath: { min: 25, max: 75 }, transitionTime: { min: 500, max: 1000 }, repeat: {times:1} },
{ id: 'line5-init', element: ".new-document-line5", drawPath: { min: 25, max: 75 }, transitionTime: { min: 500, max: 1000 }, repeat: {times:1} },
{ waitFor: 'line1-init', element: ".new-document-line1", drawPath: 100, transitionTime: { min: 500, max: 1000 } },
{ waitFor: 'line2-init', element: ".new-document-line2", drawPath: 100, transitionTime: { min: 500, max: 1000 } },
{ waitFor: 'line3-init', element: ".new-document-line3", drawPath: 100, transitionTime: { min: 500, max: 1000 } },
{ waitFor: 'line4-init', element: ".new-document-line4", drawPath: 100, transitionTime: { min: 500, max: 1000 } },
{ waitFor: 'line5-init', element: ".new-document-line5", drawPath: 100, transitionTime: { min: 500, max: 1000 } },

If you’ve looked at the Pen, you’ll have noticed that hovering over the new document icon causes the lines to shrink and grow. Each of those lines is a path, and a path can be drawn. The first transform object above includes drawPath. drawpath takes either a number or an object with properties min and max. The number represents a percentage. Let’s say that the transform object had drawPath: 0. That would mean that I want the current path to be drawn to 0% of its length. The transform object really has drawPath: { min: 25, max: 75 }. When the value of drawpath is an object, I’m telling my plugin that I want the path to be drawn to a random percentage between the min and the max. In this case it would be a random number between 25 and 75. If you hover over the icon again, you can see that the line length changes each time the animation occurs. The same principle of setting a random number with min and max applies to transitionTime.

The last newcomer to this animation schema is repeat. repeat takes an object with four valid properties.

  1. loop: takes a Boolean value. If set to true, the animation and all of the transforms further down the chain will repeat until told otherwise. In order to break out of a loop you must either set a loopDuration or change to another animation state.
  2. loopDuration: takes an integer. If I set loop to true and loopDuration to 5000, then the animation chain will repeat itself for 5000ms. If the duration of the animation loop isn’t exactly 5000ms, then the loop will continue its final animation past the set time.
  3. times: takes an integer. If I set times to 2, then my animation will run a total of 3 times. Once because the animation always runs at least once and then 2 more times.
  4. delay: takes an integer. Represents the amount of time you want between the end of the animation and the beginning of the repeat loop.

Next, I want to illustrate a longer animation chain.

See the Pen KmNXdW by Briant Diehl (@bkdiehl) on CodePen.

Take a look at the shake state. The first and last transform objects have either an id or a waitFor property. Every other transform object has both an id and a waitFor property.

shake: [
  { id: "shake-right", element: '.wrench', r: 10 },
  { id: "shake-left", waitFor: 'shake-right', element: '.wrench', r: -10 },
  { id: "back-to-right", waitFor: 'shake-left', element: '.wrench', r: 10 },
  { id: "back-to-left", waitFor: 'back-to-right', element: '.wrench', r: -10 },
  { waitFor: 'back-to-left', element: '.wrench', r: 0 }
]

Each of the three middle transform objects is referencing the id of the preceding transform object with their waitFor. The first animation starts a chain that leads to the reset value r:0 at the very end.

Finally, I want to demonstrate how we would draw lines by setting stroke-dashoffset and stroke-dasharray.

See the Pen rmWzyW by Briant Diehl (@bkdiehl) on CodePen.

First, I want you to notice that on many of my path elements that I include stroke-dashoffset:1000; stroke-dasharray:1000, 1000;

<path class="right-upper-branch" d="M45.998,21.196C43.207,23.292 44.195,27.857 47.629,28.59C48.006,28.671 48.399,28.699 48.784,28.672C49.659,28.611 50.276,28.34 50.994,27.849C51.413,27.563 51.839,27.05 52.092,26.616C53.906,23.507 50.981,19.611 47.489,20.486C46.946,20.622 46.446,20.86 45.998,21.196L41.015,14.571" style="fill:none;stroke:#fff;stroke-width:1.7px;stroke-dashoffset:1000; stroke-dasharray:1000, 1000;"/>

For a more detailed explanation of stroke-dasharray, view stroke-dasharray. For my purposes, let’s say that stroke-dasharray is basically setting the length of the path that I don’t want to show. Now, my path certainly isn’t 1000px long. It’s a bit of an exaggeration, but it’s an exaggeration that makes sure that no portion of my path is shown prematurely. The path is drawn to completion in the following transform.

{ id:["right-upper-branch", 600], element: ".right-upper-branch", drawPath:100  },

When I set drawPath back to 0 it will adjust the stroke-dasharray and stroke-dashoffset accordingly. The last thing I want to point out about this line is the id. It’s an array instead of a string. The first value in the array is the name of the id. The second value will always be an integer representing a timeout. If I only used this transform object in the animation I would only see a path being drawn 600ms after the mouseover event.

For more examples and further documentation you can check out my demo page.

Conclusion

There may be many of you that are still on the fence about whether switching your icon system to something new is a good thing. There are pros and cons to the different icon systems currently available. I’ve tried to create a simple way for you to make the move to SVG icons. I hope you find it useful.


Snap Animation States is a post from CSS-Tricks

Full Page Background Video Styles

Post pobrano z: Full Page Background Video Styles

Making a full page background video is slightly trickier than a full page background image. Over on the Media Temple blog, I take a look at how that’s done, but then also what the design patterns are once you’ve done it. You likely need text over top the video, so do you center it? Do you let the page scroll and cover the video? Do you get fancy and fade out the header as you scroll?

Direct Link to ArticlePermalink


Full Page Background Video Styles is a post from CSS-Tricks

Solving the Last Item Problem for a Circular Distribution with Partially Overlapping Items

Post pobrano z: Solving the Last Item Problem for a Circular Distribution with Partially Overlapping Items

Let’s say we wanted to have something like this:

Clockwise circular (cyclic) distribution with twelve partially overlapping square items. Every item's top left corner is underneath the previous item's bottom left corner
Clockwise circular (cyclic) distribution with partially overlapping items.

At first, this doesn’t seem too complicated. We start with 12 numbered items:

- 12.times do |i|
  .item #{i}

We give these items dimensions, position them absolutely in the middle of their container, give them a background, a box-shadow (or a border) and tweak the text-related properties a bit so that everything looks nice.

$d: 2em;

.item {
  position: absolute;
  margin: calc(50vh - #{.5*$d}) 0 0 calc(50vw - #{.5*$d});
  width: $d; height: $d;
  box-shadow: inset 0 0 0 4px;
  background: gainsboro;
  font: 900 2em/ #{$d} trebuchet ms, tahoma, verdana, sans-serif;
  text-align: center;
}

So far, so good:

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

Now all that’s left is to distribute them on a circle, right? We get a base angle $ba for our distribution, we rotate each item by its index times this $ba angle and then translate it along its x axis:

$n: 12;
$ba: 360deg/$n;

.item {
  transform: rotate(var(--a, 0deg)) translate(1.5*$d);
	
  @for $i from 1 to $n { &:nth-child(#{$i + 1}) { --a: $i*$ba } }
}

The result seems fine at first:

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

However, on closer inspection, we notice that we have a problem: item 11 is above both item 0 and item 10, while item 0 is below both item 1 and 11:

Highlighting the issue we encounter with our circular distribution using the above code. The last item (11), ends up both over one before it (10) and over the one after (0), while the first item (0) is both under the one before it (11) and under the one after it (1).
Highlighting the issue we encounter with our circular distribution.

There are a number of ways to get around this, but they feel kind of hacky and tedious because they involve either duplicating elements, cutting corners with clip-path, adding pseudo-elements to cover the corners or cut them out via overflow. Some of these are particularly inefficient if we also need to animate the position of the items or if we want the items to be semi transparent.

So, what’s the best solution then?

3D to the rescue! A really neat thing we can do in this case is to rotate these items in 3D such that their top part goes towards the back (behind the plane of the screen) and their bottom part comes forward (in front of the plane of the screen). We do this by chaining a third transform function – a rotateX():

transform: rotate(var(--a, 0deg)) translate(1.5*$d) rotateX(40deg)

At this point, nothing seems to have changed for the better – we still have the same problem as before and, in addition to that, our items appear to have shrunk along their y axes, which isn’t something we wanted.

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

Let’s tackle these issues one by one. First off, we need to make all our items belong to the same 3D rendering context and we do this by setting transform-style: preserve-3d on their parent (which in this case happens to be the body element).

The result after ensuring all our items are within the same 3D rendering context: they are all in the correct order, with every item's top left corner underneath the bottom left corner of the previous item.
The result after ensuring all our items are within the same 3D rendering context (live demo).

Those on current Firefox may have noticed we have a different kind of issue now. Item 8 appears both above the previous one (7) and above the next one (9), while item 7 appears both below the previous one (6) and below the next one (8).

Screenshot illustrating the Firefox issue described above.
Screenshot illustrating the Firefox issue.

This doesn’t happen in Chrome or in Edge and it’s due to a known Firefox bug where 3D transformed elements are not always rendered in the correct 3D order. Fortunately, this is now fixed in Nightly (55).

Now let’s move on to the issue of the shrinking height. If we look at the first item from the side after the last rotation, this is what we see:

Geometric illustration. First item and its projection onto the plane of the screen, side view from the + of the x axis. From this point, we see these as two lines, AB and CD, which intersect in the middle, this intersection being the point O. The angle between them is the angle of rotation of each item around its own x axis, 40° in this case.
First item and its projection onto the plane of the screen, side view.

The AB line, rotated at 40° away from the vertical is the actual height of our item (h). The CD line is the projection of this AB line onto the plane of the screen. This is the size we perceive our item’s height to be after the rotation. We want this to be equal to d, which is also equal to the other dimension of our item (its width).

We draw a rectangle whose left edge is this projection (CD) and whose top right corner is the A point. Since the opposing edges in a rectangle are equal, the right edge AF of this rectangle equals the projection d. Since the opposing edges of a rectangle are also parallel, we also get that the ∠OAF (or ∠BAF, same thing) angle equals the ∠AOC angle (they’re alternate angles).

Geometric illustration. We draw a rectangle whose left edge is the CD projection and whose top right corner is the A point.
Creating the CDFA rectangle.

Now let’s remove everything but the right triangle AFB. In this triangle, the AB hypotenuse has a length of h, the ∠BAF angle is a 40° one and the AF cathetus is d.

Geometric illustration focused on the right triangle AFB
The right triangle AFB

From here, we have that the cosine of the ∠BAF angle is d/h:

cos(40°) = d/h → h = d/cos(40°)

So the first thing that comes to mind is that, if we want the projection of our items to look as tall as it is wide, we need to give it a height of $d/cos(40deg). However, this doesn’t fix the squished text or any squished backgrounds, so it’s a better idea to leave it with its initial height: $d and to chain another transform – a scaleY() using a factor of 1/cos(40deg). Even better, we can store the rotation angle into a variable $ax and then we have:

$d: 2em;
$ax: 40deg;

.item {
  transform: rotate(var(--a, 0deg)) translate(1.5*$d) rotateX($ax) scaleY(1/cos($ax));
}

The above changes give us the desired result (well, in browsers that support CSS variables and don’t have 3D order issues):

The final result after fixing the height issue: all items are square again and they are all in the correct order, with every item's top left corner underneath the bottom left corner of the previous item.
The final result after fixing the height issue (live demo).

This method is really convenient because it doesn’t require us to do anything different for any one item in particular and it works nicely, without any other extra tweaks needed, in the case of semitransparent items. However, the above demo isn’t too exciting, so let’s take a look at a few slightly more interesting use cases.

Note that the following demos only work in WebKit browsers, but this is not something related to the method presented in the article, it’s just a result of the currently poor support of calc() for anything other than length values.

The first is a tic toc loader, which is a pure CSS recreation of a gif from the Geometric Animations tumblr. The animation is pretty fast in this case, so it may be a bit hard hard to notice the effect here. It only works in WebKit browsers as Firefox and Edge don’t support calc() as an animation-delay value and Firefox doesn’t support calc() in rgb() either.

Animated gif showing a tic toc loader. Eighteen bars are distributed on a circle, all pointing towards the origin. Every two opposing bars animate at the same time, rotating by half a turn around their own central points. Once they are done, the next pair of opposing bars starts animating.
Tic toc loader (see the live demo, WebKit only)

The second is a sea shell loader, also a pure CSS recreation of a gif from the same Tumblr and also WebKit only for the same reasons as the previous one.

Animated gif showing a sea shell loader. There are two layers, with eighteen bars distributed on identical circles on each layer. All the bars rotate around their own central points at the same time, with those on the layer behind being 90 degrees away from those on the layer in front at all times.
Sea shell loader (see the live demo, WebKit only)

The third demo is a diagram. It only works in WebKit browsers because Firefox and Edge don’t support calc() values inside rotate() functions and Firefox doesn’t support calc() inside hsl() either:

Diagram showing five discs distributed clockwise on a circle, partly overlapping, with each of the discs partly underneath the disc following it.
Diagram (see the live demo, WebKit only)

The fourth is a circular image gallery, WebKit only for the same reason as the diagram above.

Circular image gallery. Image thumbnails are distributed in a similar fashion to the discs in the previous demo, on a circle around the current image. Clicking on a thumbnail selects that image and moves it in the middle where it grows to its natural size, while the previously selected image shrinks and moves back in place on the circle. All images show pictures of Amur leopards.
Circular image gallery (see the live demo, WebKit only)

The fifth and last is another loading animation, this time inspired by the Disc Buddies .gif by Dave Whyte.

Animated gif. 12 discs are distributed on a circle in a similar fashion to the previous demos. The ones on odd positions shift out on another outer layer. The two layers rotate in opposite directions, then the items on the outer layer shift back on the inner layer and then the animation repeats itself.
Disc Buddies loading animation (see the live demo, WebKit only)

Solving the Last Item Problem for a Circular Distribution with Partially Overlapping Items is a post from CSS-Tricks

User Facing State

Post pobrano z: User Facing State

Let’s talk about state. Communicating state to the user that is, not application stores state in JavaScript objects, or localStorage. We’re going to be talking about how to let our users know about state (think: whether a button is disabled or not, or if a panel is active or not), and how we can use CSS for that. We’re not going to be using inline styles, or, as much as can be helped, class selectors, for reasons that will become clear as we go.

Still here? Cool. Let’s do this.

All dynamic components of an application have a default user-facing state, and that state needs to be stored and updated as users interact with these components.

For example, when a button is pressed, things happen (that’s what buttons are for). When these things happen, they are typically represented in a visual manner in the interface. The button’s background may change to indicate it was pressed. If the button controls other components in the interface, those components likely visually change in style, or in some cases their visibility is toggled. An item gets deleted, a notification pops up, an error style is applied, etc.

You may have noticed that we’ve been mentioning the „visual” state of components quite a bit. That’s exactly the kind of problem I’ve been finding with a lot of tutorials, articles and general talking about state.

More often than not, developers are using „stateful” classes to manage a component’s state. But this is sorely inadequate, as a component is composed of more than just how it looks. There are underlying semantics that need to be managed along with the component’s visual representation. The failure to manage those underlying semantics becomes apparent as soon as you interact with it via keyboard and/or screen reader.

This is an article about appropriately conveying state so that users, beyond sighted, mouse-using users, can interact with our interfaces.

State is more than just how it looks

Outside of using CSS to appropriately hide content from sighted users and assistive technologies, CSS doesn’t have many intentional effects on an element’s semantics or accessible state. What I mean by that is outside of properties like the unsupported ‚speak’, before/after pseudo content, and media queries to specifically restyle components based on user preferences, like the Reduced Motion Media Query and other proposed User Queries, CSS alone is not meant to change an element’s semantics, content or appropriately convey the state of an element in a meaningful way.

Why do I bring all this up? Because managing state with CSS classes alone is, mostly, inadequate for conveying state to all users. Being a language for presentational purposes, giving an input a class of .has-error to change the border color to a shade of red, has no semantic value to it. For all CSS cares, „That’s how you wanted to style that input. Cool. I got your back! Just don’t ask me to style upwards in the DOM. I draw the line there, buddy…”

Instead, to manage and convey state, we should be updating attributes on the appropriate elements. And no, I don’t mean data-attributes. Those don’t mean anything either. If we take this approach, in many cases we won’t even need stateful classes, outside of classes that toggle an element’s display.

Did we forget we can style with attribute selectors?

HTML and ARIA have a whole bunch of attributes that should be used to appropriately convey the current state of a component.

Thinking about using an .is-disabled class on your <button></button> or <input type="text" />? That’s only going to visually disable it. You’re still going to have to programmatically turn off click and keyboard events to that element. Instead use the [disabled] attribute and you’ll have yourself a CSS selector to style your element, and the browser will do all the appropriate work to disable that element for you!

So instead of:

input.is-disabled { 
  opacity: .65; 
}

Which only visually modifies an input, use:

input[disabled] { 
  opacity: .65; 
}

This achieves the same visual effect as using the .is-disabled class, but instead we’re utilizing the attribute selector from the attribute we need to set to convey the current state to the browser and users. All while not having to do any of the aforementioned extra work, with JavaScript, to disable the input, if we were simply toggling a class.

Example: Being „Active”

To provide some deeper context, let’s look at a situation where you might use an .is-active class. For different components, being „active” can mean completely different things, which is why I can appreciate wanting to use a single, reusable class name, instead of determining which attribute needs to be managed to appropriately convey state. But making state management easier for developers doesn’t necessarily help users, so let’s do this the right way.

Active Navigation Links

First let’s look at declaring the currently active link in a navigation. The following Pen has two examples. The first using an .is-active class to indicate the current navigation item. The second uses aria-current="page".

See the Pen .is-active vs aria-current=’page’ by Scott (@scottohara) on CodePen.

While they both look exactly the same, if you use either Jaws 18, Voice Over, or NVDA 2017.2 (when it’s released) when navigating the example, you’ll hear something like: „Features, current page.” when interacting with the example using aria-current. Check out Léonie Watson’s article on [aria-current] for many other examples of where one could use this attribute for styling, in place of an .is-active class.

Active Buttons

Depending on the purpose of the button, the active state of the button may need to be augmented for screen reader users via one of the following ARIA attributes:

  • aria-expanded – indicates that the button controls another component in the interface, and relays that component’s current state.
  • aria-pressed – indicates that the button behaves similarly to a checkbox, in that it has its state toggles between being pressed or unpressed.

Without using one of the above attributes, a button has no inherent way of communicating whether it had been interacted with or not. That is totally fine if a situation doesn’t require it, but if you do need to communicate a button has been activated, then here’s how we can do that using aria-pressed:

See the Pen Toggle Button Example by Scott (@scottohara) on CodePen.

In the above example, we have a button that can be interacted with to add an item to a shopping cart. To indicate when an item has been added, instead of using a class, we’re instead toggling the boolean value of the aria-pressed attribute, and using the [aria-pressed="true"] as our styling hook to visually convey the active state. When interacting with the button via a screen reader, it will be announced as „checked” or „unchecked”, add to cart, toggle button.

For a deep dive into the considerations, one should take when developing accessible toggle buttons, one need look no further than Heydon Pickering’s Toggle Buttons article. Heydon outlines, in great detail, why it’s not a good idea to change the visible label of the button, and even brings to light that you may not actually want a toggle button, but instead should consider using a switch.

Managing Accordion State

For our final example, let’s take a look at how we’d manage state in an accordion component:

See the Pen ARIA Accordion Example by Scott (@scottohara) on CodePen.

If you read through the comments in the CSS and JavaScript, you’ll note that this demo is doing a few things.

First, the markup pattern of the accordion is built in a way so that if JavaScript ever becomes disabled for any reason, none of the content will be inaccessible to those users, as the panels are only hidden if the .js class is present.

Second, to circumvent the need for actual <button></button> elements within each accordion panel heading, we’re instead converting their nested s into „buttons”, by applying the ARIA role="button", and then adding in all the expected keyboard functionality via the keydown event listener. Additionally, to ensure the „button” can be accessed by keyboard users, a tabindex="0" has been set to each of the ARIA buttons.

Finally, here we use the aria-expanded attribute to communicate the current state of the accordion panel, so when a user focuses on the accordion trigger with a screen reader, it will announce „Accordion Heading, collapsed (or expanded) button”.

You will notice that the accordion panels are utilizing an .is-active class to toggle their visible state. Egads! But wait, this is the one thing we can count on CSS alone to help us with. If we take a closer look at the selectors at work here:

.js .accordion__panel {
  border-bottom: 1px solid;
  overflow: hidden;
  padding: 0 1em;
  max-height: 0px;
  transition:
    max-height .2s ease-in-out,
    visibility .2s ease-in-out;
  visibility: hidden;
}

.js .accordion__panel.is-active { 
  max-height: 100vh;
  visibility: visible;
}

The first selector, the one contingent on JavaScript being available, utilizes visibility: hidden to inclusively hide the panel’s contents from both sighted users and users of assistive technologies. The overflow, max-height, and transition properties are then set to collapse the panel, and prepare it to grow into it’s expanded form, once the .is-active class is added to the accordion panel. I could have toggled display: none or programmatically added and removed the hidden attribute from the panels, instead, but we would have lost out on the ability to transition the panel open. And everyone likes a good transition, right?

In Closing

The main thing I want you to take away from all of this is that if you are only toggling classes to visually manage state of your components, you are likely not appropriately conveying that state to users of assistive technologies.

You need to be using the appropriate elements (<button></button>s are your friend!), and managing the appropriate attributes and their values to make truly accessible user experiences. Sure, you could to do those things and continue to toggle stateful classes to control your styling. But if we have to update attributes and their values, and those are also valid CSS selectors, then why would we do more work than needed by toggling classes too?

 

 


User Facing State is a post from CSS-Tricks

React Forms: Using Refs

Post pobrano z: React Forms: Using Refs

React provides two standard ways to grab values from <form> elements. The first method is to implement what are called controlled components (see my blog post on the topic) and the second is to use React’s ref property.

Controlled components are heavy duty. The defining characteristic of a controlled component is the displayed value is bound to component state. To update the value, you execute a function attached to the onChange event handler on the form element. The onChange function updates the state property, which in turn updates the form element’s value.

(Before we get too far, if you just want to see the code samples for this article: here you go!)

Here’s an example of a controlled component:

import React, { Component } from 'react';

class ControlledCompExample extends Component {
  constructor() {
    super();
    this.state = {
      fullName: ''
    }
  }
  handleFullNameChange = (e) => {
    this.setState({
      fullName: e.target.value
    })
  }
  handleSubmit = (e) => {
    e.preventDefault();
    console.log(this.state.fullName)
  }
  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <label htmlFor="fullName">Full Name</label>
            <input
              type="text"
              value={this.state.fullName}
              onChange={this.handleFullNameChange}
              name="fullName" />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default ControlledCompExample;

The value of the input is this.state.fullName (lines 7 and 26). The onChange function is handleFullNameChange (lines 10 – 14, and line 27).

The main advantages of controlled components are:

  1. You are set up to easily validate user input.
  2. You can dynamically render other components based on the value of the controlled component. For example, the value a user selects from a dropdown (e.g. ‚dog’ or ‚cat’) can control which other form components (e.g. a checkbox set of breeds) are rendered in the form.

The downside to controlled components is the amount of code you have to write. You need a state property to pass to the form element as props, and you need a function to update the value of this property.

For one form element this isn’t an issue – but if you have a large, complex form (that doesn’t need dynamic rendering or real-time validation), you’ll find yourself writing a ton of code if you overuse controlled components.

An easier and less labor-intensive way to grab values from a form element is to use the ref property. Different form elements and component compositions require different strategies, so the rest of this post is divided into the following sections.

  1. Text inputs, number inputs, and selects
  2. Passing props from child to parent
  3. Radio sets
  4. Checkbox sets

1. Text inputs, number inputs, and selects

Text and number inputs provide the most straightforward example of using refs. In the ref attribute of the input, add an arrow function that takes the input as an argument. I tend to name the argument the same as the element itself as seen on line 3 below:

<input
  type="text"
  ref={input => this.fullName = input} />

Since it’s an alias for the input element itself, you can name the argument whatever you’d like:

<input
  type="number"
  ref={cashMoney => this.amount = cashMoney} />

You then take the argument and assign it to a property attached to the class’s this keyword. The inputs (i.e. the DOM node) are now accessible as this.fullName and this.amount. The values of the inputs are accessible as this.fullName.value and this.amount.value.
The same strategy works for select elements (i.e. dropdowns).

<select
  ref={select => this.petType = select}
  name="petType">
  <option value="cat">Cat</option>
  <option value="dog">Dog</option>
  <option value="ferret">Ferret</option>
</select>

The value selected is accessible as this.petType.value.

2. Passing props from child to parent

With a controlled component, getting the value from a child component to a parent is straightforward – the value already lives in the parent! It’s passed down to the child. An onChange function is also passed down and updates the value as the user interacts with the UI.

You can see this at work in the controlled component examples in my previous post.

While the value already lives in the parent’s state in controlled components, this is not so when using refs. With refs, the value resides in the DOM node itself, and must be communicated up to the parent.

To pass this value from child to parent, the parent needs to pass down a ‚hook’, if you will, to the child. The child then attaches a node to the ‚hook’ so the parent has access to it.

Let’s look at some code before discussing this further.

import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();
    console.log('first name:', this.firstName.value);
    this.firstName.value = 'Got ya!';
  }
  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <CustomInput
            label={'Name'}
            firstName={input => this.firstName = input} />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

function CustomInput(props) {
  return (
    <div>
      <label>{props.label}:</label>
      <input type="text" ref={props.firstName}/>
    </div>
  );
}

export default RefsForm;

Above you see a form component RefForm, and an input component called CustomInput. Usually, the arrow function is on the input itself, but here it’s being passed down as a prop (see lines 15 and 27). Since the arrow function resides in the parent, the this of this.firstName lives in the parent.

The value of the child input is being assigned to the this.firstName property of the parent, so the child’s value is available to the parent. Now, in the parent, this.firstName refers to a DOM node in the child component (i.e. the input in CustomInput).

Not only can the DOM node of the input be accessed by the parent, but the value of the node can also be assigned from within the parent. This is demonstrated on line 7 above. Once the form is submitted, the value of the input is set to ‚Got ya!’.

This pattern is a bit mind bending, so stare at it for a while and play around with the code until it sinks in.

You may be better off making radios and checkboxes controlled components, but if you really want to use refs the next two sections are for you.

3. Radio sets

Unlike text and number input elements, radios come in sets. Each element in a set has the same name attribute, like so:

<form>
  <label>
    Cat
    <input type="radio" value="cat" name="pet" />
  </label>
  <label>
    Dog
    <input type="radio" value="dog" name="pet" />
  </label>
  <label>
    Ferret
    <input type="radio" value="ferret" name="pet" />
  </label>
  <input type="submit" value="Submit" />
</form>

There are three options in the „pet” radio set – „cat”, „dog”, and „ferret”.

Since the whole set is the object of our concern, setting a ref on each radio input is not ideal. And, unfortunately, there’s no DOM node that encapsulates a set of radios.

Retrieving the value of the radio set can be obtained through three steps:

  1. Set a ref on the <form> tag (line 20 below).
  2. Extract the set of radios from the form. In this case, it is the pet set (line 9 below).
    • A node list and a value is returned here. In this case, this node list includes three input nodes, and the value selected.
    • Keep in mind that a node list looks like an array but is not, and lacks array methods. There’s more on this topic in the next section.
  3. Grab the value of the set using dot notation (line 13 below).
import React, { Component } from 'react';

class RefsForm extends Component {

  handleSubmit = (e) => {
    e.preventDefault();

    //  extract the node list from the form
    //  it looks like an array, but lacks array methods
    const { pet } = this.form;

    // a set of radios has value property
    // checkout out the log for proof
    console.log(pet, pet.value);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <label>
            Cat
            <input type="radio" value="cat" name="pet" />
          </label>
          <label>
            Dog
            <input type="radio" value="dog" name="pet" />
          </label>
          <label>
            Ferret
            <input type="radio" value="ferret" name="pet" />
          </label>
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default RefsForm;

This works even if you are composing a form from children components. Although there’s more logic in the components, the technique for getting the value from the radio set remains the same.

import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();

    //  extract the node list from the form
    //  it looks like an array, but lacks array methods
    const { pet } = this.form;

    // a set of radios has value property
    // checkout out the log for proof
    console.log(pet, pet.value);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <RadioSet
            setName={'pet'}
            setOptions={['cat', 'dog', 'ferret']} />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

function RadioSet(props) {
  return (
    <div>
      {props.setOptions.map(option => {
        return (
          <label
            key={option}
            style={{textTransform: 'capitalize'}}>
            {option}
            <input
              type="radio"
              value={option}
              name={props.setName} />
          </label>
        )
      })}
    </div>
  );
}

export default RefsForm;

4. Checkbox sets

Unlike a radio set, a checkbox set may have multiple values selected. This makes extracting these values a little more complicated than extracting the value of a radio set.

Retrieving the selected values of the checkbox set can be done through these five steps:

  1. Set a ref on the <form> tag (line 27 below).
  2. Extract the set of checkboxes from the form. In this case, it is the pet set (line 9).
    • A node list and a value is returned here.
    • Keep in mind that a node list looks like an array but is not, and lacks array methods, which takes us to the next step…
  3. Convert the node list to an array, so array methods are available (checkboxArray on line 12).
  4. Use Array.filter() to grab only the checked checkboxes (checkedCheckboxes on line 15).
  5. Use Array.map() to keep only the values of the checked checkboxes (checkedCheckboxesValues on line 19).
import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();

    //  extract the node list from the form
    //  it looks like an array, but lacks array methods
    const { pet } = this.form;

    // convert node list to an array
    const checkboxArray = Array.prototype.slice.call(pet);

    // extract only the checked checkboxes
    const checkedCheckboxes = checkboxArray.filter(input => input.checked);
    console.log('checked array:', checkedCheckboxes);

    // use .map() to extract the value from each checked checkbox
    const checkedCheckboxesValues = checkedCheckboxes.map(input => input.value);
    console.log('checked array values:', checkedCheckboxesValues);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <label>
            Cat
            <input type="checkbox" value="cat" name="pet" />
          </label>
          <label>
            Dog
            <input type="checkbox" value="dog" name="pet" />
          </label>
          <label>
            Ferret
            <input type="checkbox" value="ferret" name="pet" />
          </label>
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default RefsForm;

Using a checkbox set child component works just like the radio set example in the previous section.

import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();

    //  extract the node list from the form
    //  it looks like an array, but lacks array methods
    const { pet } = this.form;

    // convert node list to an array
    const checkboxArray = Array.prototype.slice.call(pet);

    // extract only the checked checkboxes
    const checkedCheckboxes = checkboxArray.filter(input => input.checked);
    console.log('checked array:', checkedCheckboxes);

    // use .map() to extract the value from each checked checkbox
    const checkedCheckboxesValues = checkedCheckboxes.map(input => input.value);
    console.log('checked array values:', checkedCheckboxesValues);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <CheckboxSet
            setName={'pet'}
            setOptions={['cat', 'dog', 'ferret']} />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

function CheckboxSet(props) {
  return (
    <div>
      {props.setOptions.map(option => {
        return (
          <label
            key={option}
            style={{textTransform: 'capitalize'}}>
            {option}
            <input
              type="checkbox"
              value={option}
              name={props.setName} />
          </label>
        )
      })}
    </div>
  );
}

export default RefsForm;

Conclusion

If you don’t need to:

  1. monitor the value of a form element in real-time (e.g. in order to render subsequent components based on user input), or
  2. perform custom validation in real-time,

then using refs to grab data from form elements is a good bet.

The primary value of using refs over controlled component is that, in most cases, you will write less code. The exceptional case is that of checkbox sets (and radios to a lesser degree). For checkbox sets, the amount of code you save by using refs is minimal, so it’s less clear whether to use a controlled component or refs.


React Forms: Using Refs is a post from CSS-Tricks

Are we making the web too complicated?

Post pobrano z: Are we making the web too complicated?

Exactly as I did the other week, Laurie Voss saw a tweet about the complication of front-end development and responded.

From the outside, front end development in 2017 looks pathologically overcomplicated. Is this a fair perception? If so, why is it happening?

— Pinboard (@Pinboard) May 21, 2017

The replies to Maciej’s tweet are interesting to read. They fall roughly into two camps:

  1. Older/not front-end developers: because the web is shit!
  2. Current front-end developers: because shit is hard!

As is often the case, both camps are correct! The web is a shitshow of wheel reinvention and bad APIs. It’s also a blizzard of innovation.

Expectations for what a website should be able to do have evolved enormously. Users expect snappy, desktop-like responsiveness and rich presentation in web apps. They also expect those same web apps to work equally well on mobile devices. And they expect these apps to load basically instantly.

Direct Link to ArticlePermalink


Are we making the web too complicated? is a post from CSS-Tricks

Combine Webpack with Gulp 4

Post pobrano z: Combine Webpack with Gulp 4

Webpack is so hot right now! Webpack is great when it comes to module bundling and working with frameworks like Vue or React, but it is a bit more awkward when handling static assets (like CSS). You might be more used to handling your static assets with something like Gulp, and there are some pretty good reasons for that.

Still, the amount of JavaScript in our static projects is growing, so to compensate, let’s make use of Webpack, while remaining in Gulp. In this article, specifically, Gulp 4. We’ll use modern techniques to build an easily maintainable workflow, including the powerful and useful Hot Module Reloading (HMR).

You May Want To Start Here

This article isn’t quite for beginners. If you are new to Webpack or Gulp, perhaps start with these tutorials.

Gulp Tutorials

Webpack Tutorials

Demo

Check the demo repo on GitHub. The branch „hmr” shows how to set up Hot Module Reloading.

Prerequisites

Run the following to install necessary packages:

npm install babel-core \
            babel-preset-es2015 \
            browser-sync \
            gulpjs/gulp#4.0 \
            webpack \
            webpack-dev-middleware \
            webpack-hot-middleware -D

As of Node v7.9.0, ES6 modules are not supported, that is why we install Babel to make use of import statements and other cutting edge JS features in our tasks.

If you don’t need HMR, feel free to leave Hot Middleware out of the packages listed above. The Dev Middleware does not depend on it.

Starting Points

Let’s get started! Create a tasks folder in your project root with three files: index.js, webpack.js and server.js. We have less clutter in our project root since the index file acts like gulpfile.js and the webpack file as webpack.config.js .

The site folder holds all your site’s assets:

╔ site
║   ╚═══ main.js
╠ tasks
║   ╠═══ index.js
║   ╠═══ server.js
║   ╚═══ webpack.js
╚ package.json

To tell Gulp where the tasks are located, we need to add flags in our `package.json`:

"scripts": {
  "dev": "gulp --require babel-register --gulpfile tasks",
  "build": "NODE_ENV=production gulp build --require babel-register --gulpfile tasks"
}

The babel-register command processes the import statements and the --gulpfile flag defines the path to gulpfile.js or, in our case, index.js . We only need to reference the tasks folder because like in HTML the file named index marks the entry point.

Set up a basic Webpack config

In `webpack.js`:

import path from 'path'
import webpack from 'webpack'

let config = {
    entry: './main.js',
    output: {
        filename: './bundle.js',
        path: path.resolve(__dirname, '../site')
    },
    context: path.resolve(__dirname, '../site')
}

function scripts() {

    return new Promise(resolve => webpack(config, (err, stats) => {

        if (err) console.log('Webpack', err)

        console.log(stats.toString({ /* stats options */ }))

        resolve()
    }))
}

module.exports = { config, scripts }

Notice how we don’t export the object directly like many tutorials show but put it into a variable first. This is necessary so we can use the configuration in the Gulp task scripts below as well as in the server middleware in the next step.

Context

The config.context setup is necessary to set all paths relative to our site folder. Otherwise they would start from the tasks folder which could lead to confusion down the road.

Separate config and task

If you have a very long Webpack config, you can also split it and the task into two files.

// webpack.js
export let config = { /* ... */ }
// scripts.js
import { config } from './webpack'
export function scripts() { /* ... */ }

Hot Module Reloading

Here’s how to make HMR work. Change the entry and plugins:

entry: {
  main: [
    './main.js',
    'webpack/hot/dev-server',
    'webpack-hot-middleware/client'
  ]
},

/* ... */

plugins: [
  new webpack.HotModuleReplacementPlugin()
]

Make sure to disable the extra entries and the HMR plugin for production. The package Webpack Merge helps setting up different environments for development and production.

BrowserSync

Now a BrowserSync task setup:

import gulp from 'gulp'
import Browser from 'browser-sync'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'

import { config as webpackConfig } from './webpack'

const browser = Browser.create()
const bundler = webpack(webpackConfig)

export function server() {

    let config = {
        server: 'site',
        middleware: [
            webpackDevMiddleware(bundler, { /* options */ }),
            webpackHotMiddleware(bundler)
        ],
    }

    browser.init(config)

    gulp.watch('site/*.js').on('change', () => browser.reload())
}

The Dev Middleware enables BrowserSync to process what was defined as entry in webpack.js. To give it this information we import the config module. Hot Middlware on the other hand checks for changes in app components like `.vue` files for Vue.js to inject.

Since we cannot hot reload files like main.js, we watch them and reload the window on change. Again, if you don’t need HMR, remove webpackHotMiddleware.

Import all Tasks

The `index.js` file includes all tasks:

import gulp from 'gulp'

import { scripts } from './webpack'
import { server }  from './server'

export const dev   = gulp.series( server )
export const build = gulp.series( scripts )

export default dev

The exported variables define what tasks to run under which command. The default export runs with gulp.

If you separate development and production environments for Webpack, you might want to run a gulp build task which makes use of production options. For that, we import the scripts tasks on its own since we don’t need to start the server here.

During development, Webpack is run by BrowserSync so putting the scripts task in the dev command is not necessary.

Running Tasks

To start developing you cannot just run gulp or gulp build since it will look for a gulpfile.js in the project root. We have to run the npm commands npm run dev and npm run build to make use of the defined flags.

Expanding

Now you can imagine how easy it is to expand and write more tasks. Export a task in one file and import it in `index.js`. Clean and easy to maintain!

To give you an idea of how to set up your project folder, here is my personal setup:

╔ build
╠ src
╠ tasks
║   ╠═══ config.js => project wide
║   ╠═══ icons.js  => optimize/concat SVG
║   ╠═══ images.js => optimize images
║   ╠═══ index.js  => run tasks
║   ╠═══ misc.js   => copy, delete
║   ╠═══ server.js => start dev server
║   ╠═══ styles.js => CSS + preprocessor
║   ╚═══ webpack.js
╚ package.json

Again, why use both Webpack and Gulp?

Static File Handling

Gulp can handle static assets better than Webpack. The Copy Webpack Plugin can also copy files from your source to your build folder but when it comes to watching file deletion or changes like overriding an image, gulp.watch is a safer bet.

Server Environment

Webpack also comes with a local server environment via Webpack Dev Server but using BrowserSync has some features you might not want to miss:

  • CSS/HTML/image injection for non-app projects
  • multiple device testing out of the box
  • includes an admin panel for more control
  • bandwidth throttling for speed and loading tests

Compilation Time

As seen in this post on GitHub Sass gets processed by node-sass much quicker than by Webpack’s combination of sass-loader, css-loader and extract-text-webpack-plugin.

Convenience

In Webpack, you have to import your CSS and SVG files for instance into JavaScript to process them which can be quite tricky and confusing sometimes. With Gulp, you don’t need to adjust your workflow.


Combine Webpack with Gulp 4 is a post from CSS-Tricks

5 Awesome Sublime Plugins you Won’t Find in Top Plugin Posts

Post pobrano z: 5 Awesome Sublime Plugins you Won’t Find in Top Plugin Posts

I am a huge fan of Sublime text editor and whenever I go and try other text editors I come back to Sublime crying: „Forgive me I’ll never, ever, leave you again!” But I’m not here to praise Sublime. In this post I’m rather going to share some of the Sublime plugins I’ve been using a lot and which are really helpful and fun to work with. You may find them for your favorite text editor as well.

Let’s dive into the first one.

1) Text Pastry

How many times have you had a markup and all you wanted to do was to add incremental numbers to it? For example if you have a list with a heavy content, of course you can’t use Emmet or similar tools to add those incremental numbers because the markup is already there, unless you use some tricks. However there is a faster way to get there.

With Text Pastry plugin we can extend the power of multiple selections in Sublime and do lots of awesome things.

Here is the basic usage of this plugin:

Sometimes you even have a range of numbers in mind and, as you can see in the video, you will be able to put numbers in a specific range and you can even specify the steps.

Pretty cool, huh?

This plugin can do more than what I have just shown you. You can find more information and examples on GitHub.

If you are using Atom you can find the Text Pastry plugin here.

2) Super Calculator

Once I needed a component, but since I didn’t have much time, writing it from scratch was not ideal. Fortunately I could find that component on the web; however the developer used pxs for all the properties and sizes. So for making that component responsive I was supposed to change all the pxs to em or rem, and, as you know, doing that is just a pain in the ass. I used Cmd/Ctrl+D to see all the pxs units and then I stared at the screen wishing I had a magic wand to turn all those pxs units into a relative unit.

It turned out that magic existed and I did find it after 5 minutes of Googling.

Super Calculator is just amazing, all you have to do is press Alt+C and Super Calculator will select the mathematical expression closest to the cursor position so that you can review what is going to be calculated. If you press Alt+C for a second time, it will calculate the result and insert it into your code right away, or if you select a mathematical expression and hit Alt+C, the magic will happen all the same.

3) InstaGoogling

I think I found this one on Twitter and it’s just brilliant.

When we code we usually love to make our text editor fullscreen so that we can concentrate at our best. But sometimes we get to this point where we need to find something on the web, maybe a piece of code or maybe a wired syntax, hence we have to get out of that fullscreen mode.

InstaGoogling plugin will help you to Google something without losing the full-screen mode. All you have to do is hit f1 and you will have a nice Google window popping up on your screen.

After installing this plugin you will need to add its extension to Chrome as well.

As you can see from the video, I’m going through my search result by using the tab key, I hit enter for opening the page and I use Ctrl+W to close the window, so that I don’t have to move my hands away from the keyboard.

Another great feature of InstaGoogling is that you can select a piece of code, then hit f1 and the plugin will search that on Google automatically and it will insert the language at the end of that piece in order to have a better result.

Unfortunately there isn’t yet a version of plugin for Mac, but I hope it will come out soon, as it seems to be in the making.

4) Open-Include

To me this plugin is the most handy one.

Usually in a project you have a lot of files and you wanna be able to easily move back and forth from one file to another. Imagine you are looking at your Sass index file and you see a lot of imports and paths. if you want to open one of them you can move the cursor on that path and just simply hit Alt+D and boom, you will be in that file.

What I love about Open-Include is that it doesn’t matter what that path is and where it goes, Open-Include will just open it for you. You can be dealing with a JavaScript module or a file on a CDN or an image, this plugin will do its job in any case.

Unfortunately this plugin was removed from packagecontrol.io. As a consequence, you can’t install it as you normally would, but you can go to its Github page, download the entire set of files and install the plugin manually by pasting all files in your package folder.

5) Console Wrap

I have a colleague who, from time to time, comes to me bad mouthing another colleague of ours: „Why does he never remove his console.log lines?”

Console Wrap can help us removing those lines my colleague hates so much:

If you use Atom try this plugin.

How can we find awesome plugins on our own?

To be honest when I discussed with Chris the possibility of writing this post I only had four plugins in my mind, so I said to myself: ‚I’m not gonna write this post with a title like „4 Plugins…” that is so lame!’ So I went to packagecontrol.io, to the trending section in the hope of finding something useful, and I immediately spotted Console Wrap plugin shining there and it turned out I really needed this plugin.

So, from time to time do go to this page. You may find something you didn’t know you needed which will make your life so much easier!


5 Awesome Sublime Plugins you Won’t Find in Top Plugin Posts is a post from CSS-Tricks