Archiwum kategorii: CSS

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

Simplifying CSS Cubes with Custom Properties

Post pobrano z: Simplifying CSS Cubes with Custom Properties

I know there are a ton of pure CSS cube tutorials out there. I’ve done a few myself. But for mid-2017, when CSS Custom Properties are supported in all major desktop browsers, they all feel… outdated and very WET. I thought I should do something to fix this problem, so this article was born. It’s going to show you the most efficient path towards building a CSS cube that’s possible today, while also explaining what common, but less than ideal cube coding patterns you should steer clear of. So let’s get started!

HTML structure

The HTML structure is the following: a .cube element with .cube__face children (6 of them). We’re using Haml so that we write the least amount of code possible:

.cube
  - 6.times do
    .cube__face

We’re not using .front, .back and classes like that. They’re not useful because they bloat the code and make it less logical. Instead, we’ll use :nth-child() to target the faces. We don’t need to worry about browser support for that, since we’re building something with 3D transforms here, which assumes much newer browser support!

Basic styles

All these elements are absolutely positioned:

[class*='cube'] { position: absolute }

The .cube is the child of a scene element which is the body in our case because we want to keep things as simple as possible. If we had multiple 3D shapes within the scene and we wanted them to interact in a 3D manner, then our cube would have been a child of that assembly and the assembly would have been a child of the scene.

We make the body cover the entire viewport and set a perspective on it so that whatever is closer looks bigger and whatever is further away looks smaller.

body {
  height: 100vh;
  perspective: 25em
}

Something else that I often like to do when the full-height body is the scene is to set the font-size on the .cube such that it depends on the minimum viewport dimension. This makes our whole cube scale nicely with the viewport if I then set the cube dimensions in em units.

.cube { font-size: 8vmin }

The reason why I’m not setting the cube dimensions directly in vmin units is an Edge bug.

We then give the .cube element a transform-style of preserve-3d so that its cube children don’t get flattened into its plane in case we decide to animate it and we put it in the middle of the scene using top and left offsets. This is the initial positioning of the cube and it’s best to use offsets, not a translate() transform for this. I’ve seen that sometimes people get confused about this because they’ve heard that, for performance reasons, it’s better to use transforms, not offsets… that’s true, but it applies for animating the position, not for the initial positioning. The very simple rule here is: use offsets or margins, whichever is more convenient at that point for initial positioning, use transforms from animating the position starting from that initial position.

.cube {
  top: 50%; left: 50%;
  transform-style: preserve-3d;
}

We then pick a cube edge length and set it as the width and height of the cube faces. We also give the faces a negative margin of minus half the cube edge so that they’re dead in the middle. Again, this is related to the initial positioning the cube faces. We also give them a box-shadow just so that we can see them.

$cube-edge: 8em;

.cube__face {
  margin: -.5*$cube-edge;
  width: $cube-edge; height: $cube-edge;
  box-shadow: 0 0 0 2px;
}

I often see code where transform-style: preserve-3d has been set on everything. That’s unnecessary and a misunderstanding of how preserve-3d works. It’s only necessary to set it on something that’s going to have a 3D transform applied (right away, following user interaction, via an auto-running animation… doesn’t matter how) and has 3D transformed children. In our particular case, that’s just the .cube element. The scene doesn’t get transformed in 3D and the .cube__face elements don’t have children.

Another unnecessary thing I see is setting explicit dimensions on the .cube element. This element isn’t visible. We don’t have any text directly in it, we’re not setting and backgrounds, borders or shadows on it. Its only purpose here is to serve as a container whose position we can animate in order to easily move all its face children at once, in the same way. Not setting any dimensions on this absolutely positioned .cube element means that its dimensions are computed to 0x0, so it’s also pointless to set any %-value offsets on its face children. top: 0 is the exact same thing as top: 50% or as any other percent value for an element whose parent has 0x0 dimensions. The same is valid for all the other offsets (right, bottom, left).

I’ve been asked why not set top and left for the .cube to calc(50% - #{.5*$cube-edge}) and remove the margin from the .cube__face altogether if I care about compacting code so much. Well, that’s because the two don’t really produce the same result, even though the .cube__face elements do end up in the middle of the screen in both cases. To illustrate this, let’s give our .cube element a red box-shadow just so that we can see it and check out the two cases side by side:

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

In the above demo, our .cube element is positioned differently in the two cases. When using the calc() value for its offsets and skipping the margin on its children, its position doesn’t coincide with the middle of the scene anymore, but with the top left corner of its face children. So what? It’s not going to be visible in our actual demo anyway…

While that’s true, a different position also means a different transform-origin. And that changes things if we decide to rotate or scale our .cube (and that’s something we decided we’d do). So consider the following keyframe animation for our cube:

@keyframes rot { to { transform: rotateY(1turn) } }

This is a rotation around the cube’s y axis. The result is not the same for the two cases:

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

In both cases, the faces rotate around the y axis of their parent cube, but the position of this y axis relative to the faces is different. It coincides with the faces’ y axes in the initial case, and with the faces’ left edges in the second case. This is the reason why I’m not bringing the negative margin of the cube faces into the offsets of the parent cube: it would impact animating the cube in 3D.

Building the cube with transforms

What we have in the demos above isn’t a cube yet. In order to do that, we need to position the faces in 3D. There are multiple transform combinations that achieve the same effect, but the most efficient and logical one is to start by rotating the first four faces in increments of 90° around one of the axes in their plane (x or y) and the remaining two faces by ±90° around the other axis in the same plane. Then we chain a translation of half the cube edge length along the axis that’s perpendicular onto their plane (their z) axis.

A very detailed explanation of how translations and rotations work as well as how we get the transform chains for creating a cuboid can be found in this older article. The case of a cube is a simplified version where all dimensions along the three axes are equal.

Considering we choose to rotate the first four faces around their y axes, our transform chains look as follows:

.cube__face:nth-child(1) {
  transform: rotateY(  0deg) translateZ(.5*$cube-edge)
}
.cube__face:nth-child(2) {
  transform: rotateY( 90deg) translateZ(.5*$cube-edge)
}
.cube__face:nth-child(3) {
  transform: rotateY(180deg) translateZ(.5*$cube-edge)
}
.cube__face:nth-child(4) {
  transform: rotateY(270deg) translateZ(.5*$cube-edge)
}
.cube__face:nth-child(5) {
  transform: rotateX( 90deg) translateZ(.5*$cube-edge)
}
.cube__face:nth-child(6) {
  transform: rotateX(-90deg) translateZ(.5*$cube-edge)
}

Now we replace the rotateY(ay) and rotateX(ax) components with their rotate3d(i, j, k, a) equivalents. The i, j and k in the rotate3d() function are the components of the unit vector of the rotation axis along the x, y and z axes of coordinates, while a is the rotation angle around that rotation axis.

Since the rotation axis in the case of a rotateY() is the y axis, the components of the unit vector along the other two axes (i along the x axis and k along the z axis) are 0, while the component along the y axis (j) is 1. Also, a is ay in this case.

Similarly, in the case of a rotateX(), we have that i is 1, j and k are 0 and a is ax. So our equivalent chains using rotate3d would be:

.cube__face:nth-child(1) {
  transform: rotate3d(0 /* i */, 1 /* j */, 0 /* k */,   0deg /*  0*90° */) 
    translateZ(.5*$cube-edge)
}
.cube__face:nth-child(2) {
  transform: rotate3d(0 /* i */, 1 /* j */, 0 /* k */,  90deg /*  1*90° */) 
    translateZ(.5*$cube-edge)
}
.cube__face:nth-child(3) {
  transform: rotate3d(0 /* i */, 1 /* j */, 0 /* k */, 180deg /*  2*90° */) 
    translateZ(.5*$cube-edge)
}
.cube__face:nth-child(4) {
  transform: rotate3d(0 /* i */, 1 /* j */, 0 /* k */, 270deg /*  3*90° */) 
    translateZ(.5*$cube-edge)
}
.cube__face:nth-child(5) {
  transform: rotate3d(1 /* i */, 0 /* j */, 0 /* k */,  90deg /*  1*90° */) 
    translateZ(.5*$cube-edge)
}
.cube__face:nth-child(6) {
  transform: rotate3d(1 /* i */, 0 /* j */, 0 /* k */, -90deg /* -1*90° */) 
    translateZ(.5*$cube-edge)
}

We notice a few things in the code above. First of all, the k component is always 0. Then, the i component is 0 for the first four faces and 1 for the remaining two, while the j component is 1 for the first four faces and 0 for the last two. Finally, the angle value can always be written as a multiplier times 90°.

This means we can introduce CSS variables into our code so we don’t have to repeat those transform functions:

.cube__face {
  transform: rotate3d(var(--i), var(--j), 0, calc(var(--m)*90deg)) 
    translateZ(.5*$cube-edge);
	
  &:nth-child(1) { --i: 0; --j: 1; --m:  0; }
  &:nth-child(2) { --i: 0; --j: 1; --m:  1; }
  &:nth-child(3) { --i: 0; --j: 1; --m:  2; }
  &:nth-child(4) { --i: 0; --j: 1; --m:  3; }
  &:nth-child(5) { --i: 1; --j: 0; --m:  1; }
  &:nth-child(6) { --i: 1; --j: 0; --m: -1; }
}

Since both --i and --j each keep the same value for the first four faces and get a different one only for the last two, we can set their defaults to be 0 and 1 respectively and then switch them to 1 and 0 respectively for faces 5 and 6. These two faces can be selected by :nth-child(n + 5). Also, we can set the default for --m to be 0 and thus completely eliminate the need for the :nth-child(1) rule.

.cube__face {
  transform: rotate3d(var(--i, 0), var(--j, 1), 0, calc(var(--m, 0)*90deg)) 
    translateZ(.5*$cube-edge);
	
  &:nth-child(n + 5) { --i: 1; --j: 0 }

  &:nth-child(2 /* 2 = 1 + 1 */) { --m:  1 }
  &:nth-child(3 /* 3 = 2 + 1 */) { --m:  2 }
  &:nth-child(4 /* 4 = 3 + 1 */) { --m:  3 }
  &:nth-child(5 /* 5 = 4 + 1 */) { --m:  1 /*  1 = pow(-1, 4) */ }
  &:nth-child(6 /* 6 = 5 + 1 */) { --m: -1 /* -1 = pow(-1, 5) */ }
}

Pushing things a bit further, we notice that, whether it’s 1 or 0, --j can be replaced with calc(1 - var(--i)) and that --m is either the face index for the first four faces or -1 raised to the face index for the last two faces. This allows us to eliminate the --j variable and set the multiplier --m within a loop:

.cube__face {
  --i: 0;
  transform: rotate3d(var(--i), calc(1 - var(--i)), 0, calc(var(--m, 0)*90deg)) 
    translateZ(.5*$cube-edge);
  
  &:nth-child(n + 5) { --i: 1 }
  
  @for $f from 1 to 6 {
    &:nth-child(#{$f + 1}) { --m: if($f < 4, $f, pow(-1, $f)) }
  }
}

The result can be seen below:

Black cube wireframe.
The static cube (live demo).

The biggest difference here is when it comes to the compiled code. With this CSS variables method we only write the transform functions once:

.cube__face {
  --i: 0;
  transform: rotate3d(var(--i), calc(1 - var(--i)), 0, calc(var(--m, 0)*90deg)) 
    translateZ(4em);
}

.cube__face:nth-child(n + 5) { --i: 1 }

.cube__face:nth-child(2) { --m: 1 }
.cube__face:nth-child(3) { --m: 2 }
.cube__face:nth-child(4) { --m: 3 }
.cube__face:nth-child(5) { --m: 1 }
.cube__face:nth-child(6) { --m: -1 }

Without CSS variables, the best we could have done still involved repeating the transform functions for each and every face:

.cube__face:nth-child(1) {
  transform: rotateY(0deg) translateZ(4em)
}
.cube__face:nth-child(2) {
  transform: rotateY(90deg) translateZ(4em)
}
.cube__face:nth-child(3) {
  transform: rotateY(180deg) translateZ(4em)
}
.cube__face:nth-child(4) {
  transform: rotateY(270deg) translateZ(4em)
}
.cube__face:nth-child(5) {
  transform: rotateX(90deg) translateZ(4em)
}
.cube__face:nth-child(6) {
  transform: rotateX(-90deg) translateZ(4em)
}

Animating the cube

We can add a keyframe animation to our .cube element:

.cube { animation: ani 2s ease-in-out infinite }

@keyframes ani {
  50% { transform: rotateY(90deg) rotateX(90deg) scale3d(.5, .5, .5) }
  100% { transform: rotateY(180deg) rotateX(180deg) }
}

The result can be seen below:

Animated gif. Black cube wireframe, scaling down and then back up as it rotates around its vertical axis.
The animated cube (live demo).

Current support status and cross-browser version

Those of you not using a WebKit browser may have noticed that the above demos don’t work. This is because, currently, Firefox and Edge don’t support using calc() values in place of much else other than length values. This includes the unitless and angle values within rotate3d(). A way to make things cross-browser would be not to replace --j with the calc(1 - var(--i)) equivalent and use an angle --a custom property instead of the calc(var(--m)*90deg):

.cube__face {
  transform: rotate3d(var(--i, 0), var(--j, 1), 0, var(--a)) 
    translateZ(.5*$cube-edge);
  
  &:nth-child(n + 5) { --i: 1; --j: 0 }
  
  @for $f from 1 to 6 {
    &:nth-child(#{$f + 1}) { --a: if($f < 4, $f, pow(-1, $f))*90deg }
  }
}

This does mean we now have a bit of redundancy, but it’s not that bad and our result is now cross-browser.

Adding text and backgrounds

Next, we can add text to the cube faces. Either the same for all of them:

.cube
  - 6.times do
    .cube__face Boo!

… or a different one for each (we’re switching to Pug here because it allows us to write a bit less code than Haml would in this case):

- var txt = ['ginger', 'anise', 'nutmeg', 'cinnamon', 'vanilla', 'cloves'];
- var n = txt.length;

.cube
  while n--
    .cube__face #{txt[n]}

In this case, we also set text-align: center, the line-height to $cube-edge and tweak the $cube-edge and the font-size values for the best text fit:

$cube-edge: 5em;

.cube {
 font: 8vmin/ #{$cube-edge} cookie, cursive;
 text-align: center;
}

We get the following result:

Black cube wireframe rotated in 3D with text on every one of the cube faces.
The cube with text (live demo, animated).

We could also give our faces some pastel gradient backgrounds:

$pastels: (#feffaa, #b2ff90) (#fbc2eb, #a6c1ee) (#84fab0, #8fd3f4) (#a1c4fd, #c2e9fb) 
  (#f6d365, #fda085) (#ffecd2, #fcb69f);

.cube__face {
  background: linear-gradient(var(--ga), var(--gs));
  
  @for $f from 0 to 6 {
    &:nth-child(#{$i + 1}) {
      --ga: random(360)*1deg; /* gradient angle */
      --gs: nth($pastels, $f + 1); /* gradient stops */
    }
  }
}

The above gives us a nice pastel cube:

Cube rotated in 3D with a different pastel gradient background for each of its faces.
The pastel cube (live demo, animated).

A use case

I’ve used this method of creating cuboids in a demo inspired by an animation loop by Dave Whyte.

Animated gif. Cuboidal bricks are falling one by one to form the uppermost circular ring on top of a structure
Build the factories (live demo, WebKit only)

Rotating the cube on drag

After this, there’s one more itch to scratch: what about not having the cube auto-animated using CSS keyframes, but instead rotated on drag? Let’s see how we can do that!

We start by selecting our .cube element and we establish what happens during the stages of the drag. On mousedown/ touchstart, we lock everything into place for the cube rotation. This means setting a drag flag to true and reading the coordinates of the point where this happens, which are also the coordinates where the first movement detected by mousemove/ touchmove is going to start. On mousemove/ touchmove, if the drag flag is true, we rotate our cube. On mouseup/ touchend and again, only if the drag flag is true, we perform a release-like action: we set the drag flag to false again and we clear the initial coordinates.

const _C = document.querySelector('.cube');

let drag = false, x0 = null, y0 = null;

/* helper function to handle both mouse and touch */
function getE(ev) { return ev.touches ? ev.touches[0] : ev };

function lock(ev) {
  let e = getE(ev);
      drag = true;
      x0 = e.clientX;
      y0 = e.clientY;
};

function rotate(ev) {
  if(drag) { /* rotation happens here */ }
};

function release(ev) {
  if(drag) {
    drag = false;
    x0 = y0 = null;
  }
};

addEventListener('mousedown', lock, false);
addEventListener('touchstart', lock, false);

addEventListener('mousemove', rotate, false);
addEventListener('touchmove', rotate, false);

addEventListener('mouseup', release, false);
addEventListener('touchend', release, false);

Now all that’s left to do is fill up the contents of the rotate() function!

For every little movement caught by the mousemove/ touchmove listeners, we have a start point and an end point. The coordinates of the end point (x,y) are those we read via clientX and clientY every time the mousemove/ touchmove fires. The coordinates of the start point (x0,y0) are either the same as those of the end point of the previous little movement or, if there was no previous movement, those of the point where mousedown/ touchstart fired. This means that, after doing everything else we need to do within the rotate() function, we set x0 to x and y0 to y:

function rotate(ev) {
  if(drag) {
    let e = getE(ev), 
        x = e.clientX, y = e.clientY;
    
    /* rotation code here */
    	
    x0 = x;
    y0 = y;
  }
};

Next, we compute the coordinate differences between the end point and the start point of the current little movement along the two axes (dx and dy), as well as diagonally (d). If d is 0, then we haven’t really moved (and maybe nothing should fire, but just in case), so we just exit the function without doing anything else, not even setting x0 and y0 to x and y respectively – they’re the same in this case anyway.

function rotate(ev) {
  if(drag) {
    let e = getE(ev), 
        x = e.clientX, y = e.clientY, 
        dx = x - x0, dy = y - y0, 
        d = Math.hypot(dx, dy);
		
    if(d) {
      /* actual rotation happens here */
      
      x0 = x;
      y0 = y;
    }
  }
};

The way we handle rotation on drag starting from the previous state which may be transformed in some way is the following: we chain a rotate3d() corresponding to the current little movement to the computed transform value of our cube at the start of the current little movement. That is, unless the computed transform value is none, in which case we chain it to nothing. We could write this whole transform chain into a stylesheet or as an inline style or… we could again use CSS variables!

In the CSS, we set the transform property of the .cube element to a rotate3d(var(--i), var(--j), 0, var(--a)) chained to a previous value of the transform chain var(--p). In order to simplify things, we keep the component of the unit vector of the axis of rotation along the z axis fixed to 0.

.cube {
  transform: rotate3d(var(--i), var(--j), 0, var(--a)) var(--p);
}

Because we’ve done the above and CSS variables are inherited, we now need to explicitly set --i and --j for the .cube__face elements to 0 and 1 respectively. Otherwise, the values inherited from the .cube element get applied, not the defaults specified within var().

.cube__face {
  --i: 0; --j: 1;
  transform: rotate3d(var(--i), var(--j), 0, var(--a)) 
    translateZ(.5*$cube-edge);
}

Going back to the JavaScript, we read the computed transform value and set it to the --p variable. The angle of rotation depends on the distance d between the start and end points of our current little movement and a constant A. We limit this result to two decimals. For a direction of motion towards the top, in the negative direction of the y axis, we rotate the cube clockwise around the x axis. This means we take the --i component to be -dy. For a direction of motion towards the right, in the positive direction of the x axis, we rotate the cube clockwise around the y axis, which means we take the --j component to be dx.

const A = .2;

function rotate(ev) {
  if(drag) {
    let e = getE(ev), 
        x = e.clientX, y = e.clientY, 
        dx = x - x0, dy = y - y0, 
        d = Math.hypot(dx, dy);
		
    if(d) {
      _C.style.setProperty('--p', getComputedStyle(_C).transform.replace('none', ''));
      _C.style.setProperty('--a', `${+(A*d).toFixed(2)}deg`);
      _C.style.setProperty('--i', +(-dy).toFixed(2));
      _C.style.setProperty('--j', +(dx).toFixed(2));
      
      x0 = x;
      y0 = y;
    }
  }
};

Finally, we can set some arbitrary defaults for these custom properties such that the initial position of our cube makes it look a bit more 3D than viewing it right from the front would.

.cube {
  transform: rotate3d(var(--i, -7), var(--j, 8), 0, var(--a, 47deg)) 
    var(--p, unquote(' '));
}

The unquote(' ') value is due to using Sass. While an empty space is a perfectly valid value for a CSS custom property in plain CSS, Sass throws an error when seeing stuff like var(--p, ), so we need to introduce that „no value” default using unquote().

The result of all the above is a cube we can drag using both mouse and touch:

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


Simplifying CSS Cubes with Custom Properties is a post from CSS-Tricks

Enforcing CSS Syntax Style (and more!)

Post pobrano z: Enforcing CSS Syntax Style (and more!)

I bet you have a style that you write CSS in, for the most part. You like 4-spaces, say. You always have a space after braces and colons. You always put a space after rulesets. You only ever put one declaration on a line, and the only declarations that can be multi-line are when they are big blocks like a gradient or a comma-separated box-shadow.

You might take this a little further and codify this. Perhaps you have a team meeting about it and decide on how you want to style code. You write up a guide and make it available for everybody on the team to see.

GitHub’s Primer contains „code guidelines” like this.

Clean code is important, you say. While style differences in code don’t actually matter in the final output (most of us have build processes in place that compress the code anyway), it matters for day to day work. A messy inconsistent codebase is hard to look at and hard to reason about. Jumping into clean code makes it quicker to stay in the right frame of mind and get to working on the problem at hand, not waste cycles being frustrated by the mess.

Harry Roberts recently even called it an litmus test for developers:

[Tidy code] seems like a very superficial thing to worry about, but to my mind, tidy code signals something more important: I would assume that a tidy developer has better attention to detail, is more likely to follow process, and is more likely to spot mistakes. Rightly or wrongly, I see it as a litmus test for more general approaches and attitudes.

Automated Style Checking/Warning

A step beyond just agreeing on standards is having your computer actually help you make sure you’re doing it right.

I’d wager this is a far more common thing for JavaScript or server-side language programmers. For example, ESLint is very popular. You configure it with loads of rules based on what your team decides is good syntax.

ESLint running in Sublime Text through SublimeLinter

ESLint goes a litttttle further than just style checking, in that, for example, it knows if you use a function or not, or try to use a variable that is undefined. Tools like Rubocop for Ruby code are simliar. You can use them for style checking, but do more.

Style checking doesn’t have to happen in code editor itself. It’s pretty useful if it is, so you can fix problems immediately as you are authoring, but it doesn’t have to be. It might be more practical for a large and technologically-diverse team to make style checking part of the task running / build process setup.

For example, ESlint can be integrated into Grunt or Gulp, so when JavaScript files are processed, you see error output:

So there are multiple ways to incorporate style checking:

  • Within a local IDE
  • As part of a local task runner setup
  • As part of automated testing
  • Some combination of these

And you can take it even further. For example, treating linting errors like failing tests and preventing git workflow stuff. Like you can’t complete a merge request until everything passes.

Wait! We’re talking about CSS here!

Indeed. As far as I know, stylelint is the big player here. David Clark wrote all about it here on CSS-Tricks last year.

stylelint is very much like ESlint. You can incorporate it in the same ways: like as part of a task runner workflow, or right in your code editor.

Command line output for stylelint.
Example of stylelint working in side Atom.

At the moment I’m using Sublime Text, and here’s me using stylelint with SublimeLinter, the same exact linter UI thing I use for ESlint:

You’ll also probably do well by starting with a standard config.

What about opinionated CSS choices?

You could say that stylelint (and ESlint) are unopinionated. They are intentionally super flexible. You can incorporate whatever rules you want to (or leave out rules), and even when you add rules, they are designed to be flexible by either enforcing the rule one way or another and even allowing exceptions.

More importantly, I’d call them unopinionated because they aren’t exactly passing judgment on your code. But what if you want a tool to pass judgment on your code?

„Hey, you’re using too many floats!”

„Hey, that property isn’t particularly well supported!”

„Hey, @import is pretty bad for performance!”

That’s more like CSSLint territory, which has a variety of fairly opinionated rules.

Example rules of CSS Lint, like disallowing ID and disallowing too many web fonts.

There is some crossover for sure. CSSLint, for example, can check for duplicate properties just like stylelint can.

Can you use them together? Probably. Certainly, at the command line / task runner level you can. I’m not entirely sure how it would work to integrate them both into an IDE linter at the same time. Try it!

Maybe a comparison is helpful to wrap this part up:

Can’t these things be actually automated? Like actually fix the problems for me?

This is what got me thinking about this stuff in the first place. I like IDE-level linting quite a bit, but I think I like the idea of the automated fixing of style even more.

We’re essentially talking about „prettifying” here (also known as „code tidying” or „beautifying”).

The new super popular kid on the block for JavaScript is Prettier, which I’d say is a good choice. But that doesn’t help us with CSS.

There is another one, JS Beautifier, that does work with CSS (and HTML!)

Example of CSS options for JS Beautify

CSS Comb is another tool right up this alley. It is has far fewer options than stylelint (your call if that’s good or bad), and has a cool config builder for setting those rules. CSS Comb looks quite popular and well done, but I’m not going to recommend it any further, as it looks like they have stepped away from the project:

The tool is no longer being developed though we may still fix parsing errors and critical bugs. That means that you should not expect any new features or options.

CSS is changing plenty fast these days, so I’d be nervous incorporating a tool that won’t be changed. Kind of a bummer, because CSS Comb can do some things that others can’t, like re-ordering properties how you want them, which is pretty cool (although as always, there are options).

There might be a better option than these two…

stylefmt

Since the best bet for CSS style checking is stylelint, why not use the exact stylelint config for actually fixing the CSS! (Well, almost exact.)

That’s what stylefmt does. And, like most of these other tools that we’ve talked about, it can be integrated at the on-demand IDE level, or as part of task runners / build processes.

Here’s an example of me in Sublime Text with a SCSS file that has stylelint errors, and them being fixed with stylefmt:

Niiice.

stylefmt isn’t the only option, there is also perfectionist.

In Closing

Style checking is pretty cool. Not only can it be done, it can be highly customized to your liking. It can be incorporated anyplace into your process that works best for you and your team. For CSS, you’ll do well with stylelint. You can even automatically fix problems with tools like stylefmt. You can get pretty good coverage across your entire codebase as well, with things like ESlint for JavaScript and Rubocop for Ruby.


Enforcing CSS Syntax Style (and more!) is a post from CSS-Tricks

Easing Linear Gradients

Post pobrano z: Easing Linear Gradients

Linear gradients are easy to create in CSS and are extremely useful. As we’ll go through in this article, we can make them visually much smoother by creating them with non-linear gradients. Well, non-linear in the easing sense, anyway!

Here’s an example that shows how harsh a standard linear-gradient() can be compared to how smooth we can make it by easing it:

Screencap from „The Good, the Bad and the Ugly” with gradients overlaid.
  • Il buono (the good): Smooth gradients in CSS that blends into their context.
  • Il cattivo (the bad): No text protection (bad accessibility).
  • Il brutto (the ugly): Standard linear gradients with sharp edges.

In this article, we’ll focus on how we can turn Il brutto into Il buono.

The Frustrating Sharp Edges of background: linear-gradient()

Lately, I’ve been fiddling with gradients at work. I got frustrated with plain linear gradients because they looked like Il cattivo above.

/* Sharp edges :( */
.image__text {
  background-image: linear-gradient(
    hsla(0, 0%, 0%, 0.6),
    transparent;
  );
}

I started looking into creating consistently more visually appealing gradients. More accurately, I quickly eyeballed some prettier-looking gradients as one-offs and then started tinkering when I got home.

Inspiration: Math and Physics

Since a gradient is a transition of color, I got inspired by how we approach transitions elsewhere.

I’ve always been fascinated by the The Euler (or Cornu) Spiral, which has a curvature that increases linearly with the curve length, i.e., as we walk along the line from (0, 0) the radius decreases linearly with how far we walk (since the curvature is the reciprocal of the radius).

The end result is a curve that transitions as smoothly as possible from a straight line to a curve. (Side note: straight lines in Euclidian space are curves with an infinite radius!)

Euler Spiral by AdiJapan, CC BY-SA 3.0

This type of curve is called a transition curve and is used in the real word. Next time when you exit a well-built highway, then notice how gradually you turn the steering wheel. We can thank Euler for keeping sudden changes in centripetal acceleration to an absolute minimum, i.e., his math is the reason the car doesn’t flip over just as we exit the highway even at the highway speed limit.

The image below is an example of how gradual changes the changes are in the curvature of highways.

Intersection outside of Sagamihara, Japan by @digitalanthill

Inspiration: Typography

Type designers throughout history have been obsessed with smooth curves. We’ve done so because we don’t want the letters and numbers to look like a combination of different shapes but in itself form a coherent shape.

It’s why I’ve made the transition from a straight line to the circle in the „9” below as smooth as possible. It makes the number 9 read as a single shape and not a line plus a circle.

As type designers we have tools to help us achieve this. FontForge, an open source font editor, even has a Spiro/Euler drawing mode. One of the most popular type design extensions is Speed Punk, which visualizes the curvature.

Spiro mode in FontForge on the left and Speed Punk visualisation inside Glyphs on the right.

Inspiration: Design

Apple uses this approach to line-curve transitions heavily in both digital and hardware design departments. (See Apple’s Icons Have That Shape for a Very Good Reason). When Apple launched iOS7, the icon masks were updated to have a much smoother transition from straight line to rounded corners.

Visualisation of the curvature of the iOS6 and iOS7 app icons.

(Side note: The iOS7 shape above is taken directly from Apple HIG, which unfortunately has some minor imperfections especially where the horizontal lines start curving. It’s also sometimes known as a „Squircle”.)

Inspiration: Web Design

In web design, we’ve been limited in some cases by what we’re able to do. For example, border-radius doesn’t offer any way to make a squircle like the iOS7 icon. Similarly with linear-gradient, there is no natural easings available.

However, we do have easings and bezier curves available in animations! They have enabled us to make animations look more natural, smooth, and subtle.

Screenshot from easings.net

Gradient Implications

Most times, in web design, we want the gradient to blend in as much as possible. When we have a text protection gradient like Il buono, we don’t want the user to pay attention to the gradient itself. It should be rather invisible, thus, allowing the reader to focus on the image and text.

Scrim

In Material Design style guidelines for images, the designers at Google talk about text protection gradients. They call them a scrim. They recommend:

[the] gradient should be long… with the center point about 3/10 towards the darker side of the gradient. This gives the gradient a natural falloff and avoids a sharp edge.

A scrim according to Material Design guidelines

We can’t create exactly that with linear gradients, but we can (and will) create a „low poly” approximation with more color stops.

A scrim with 5 color stops to show the principle

Using only 5 color stops (like in the illustration above) would create some serious banding. Adding more stops makes the gradient a lot smoother. This is exactly what I’ve done in the demo you saw in the first image in this article. Il buono has a 13 color-stop gradient, which makes it blend nicer into the image.

See the Pen The Good, The Bad & The Ugly – correct text by Andreas Larsen (@larsenwork) on CodePen.

Compared to the Material Design scrim, I’ve tweaked it to be a bit more linear in the beginning to achieve higher text contrast and gave it a smoother fade out.

Comparison between the Material Design scrim and mine drawn using 13 color stops.

If we compare the Material Design scrim to a plain linear gradient, then it will have to be ~60% longer to achieve the same half way contrast whereas my attempt only has to be ~30% longer. The idea is to avoid darkening more of the image than necessary but still blend in smoothly with it.

The two scrims compared to a plain linear gradient

I’ve chosen not to include the Material Design scrim as it’s almost identical to the prettier easeOutSine. We can compare how linear-gradient , my scrim-gradient and ease-out-sine-gradient looks here:

Blending Both Ends

In the scrim example, we only need to blend one end as the other ends with the image. Sometimes, we need to blend in at both ends, and that’s where the easing functions, such as easeInOutSine comes in handy.

Linear-gradient vs. ease-in-out-sine approximation.

Using an easeInOut function, we make sure that both the transition from colorA to gradient and gradient to colorB is as smooth as possible. The same principle is illustrated in this Pen:

See the Pen.

How to Draw the Gradients

On YouTube, there’s a gradient behind the controls when you hover over a video. It’s created using a base64 PNG. This technique also works really well, but you can’t really automate it or easily tweak it.

Screenshot from YouTube (artist is Wintergatan).

Most other places use a linear-gradient(hsla(0, 0%, 0%, 0.8), transparent) where the start alpha most times is between 0.6-0.8. This solves the issue of making the text readable, but the resulting gradient is very prominent. An example of this is BBC where I tried using the scrim-gradient instead:

Screenshots from BBC with linear-gradient (left) and scrim-gradient (right).

PostCSS to the Rescue

I created a plugin that creates these gradients for me. Here’s the syntax:

scrim-gradient(
  black,
  transparent
);

becomes:

linear-gradient(
  hsl(0, 0%, 0%) 0%,
  hsla(0, 0%, 0%, 0.738) 19%,
  hsla(0, 0%, 0%, 0.541) 34%,
  hsla(0, 0%, 0%, 0.382) 47%,
  hsla(0, 0%, 0%, 0.278) 56.5%,
  hsla(0, 0%, 0%, 0.194) 65%,
  hsla(0, 0%, 0%, 0.126) 73%,
  hsla(0, 0%, 0%, 0.075) 80.2%,
  hsla(0, 0%, 0%, 0.042) 86.1%,
  hsla(0, 0%, 0%, 0.021) 91%,
  hsla(0, 0%, 0%, 0.008) 95.2%,
  hsla(0, 0%, 0%, 0.002) 98.2%,
  hsla(0, 0%, 0%, 0) 100%
);

The underlying principle is the one we’ve gone through: combining easing functions and multiple color stops to create approximations that look smoother than plain linear-gradients.

Actually, the scrim-gradient above is generated using a custom set of coordinates but if we look at the easing gradients such as ease-in-out-sine-gradient the steps are:

  1. Run through the .css (or .pcss) and find it.
  2. Generate evenly distributed coordinates along the ease-in-out-sine curve.
  3. Use these coordinates to create color stops. The x-coordinate determines the color mixing ratio, and the y-coordinate determines the color stop position.
  4. Replace the easing-gradient with the generated linear-gradient.
Ease-in-out-sine coordinate values generated in step 2.

The plugin currently has two optional settings:

  • precision — correlates to number of color stops generated
  • alphaDecimals — sets the number of decimals used in the hsla() alpha values

The Plugin: postcss-easing-gradients

Overall, I’m fairly happy with the output. Things I’m considering to add:

  • Sass version? I’m not using it anymore. Perhaps, someone else would like to write one?
  • The coordinates used to mix the colors for the color stops are distributed evenly over the easing curves. Ideally, the distance between the color stops would be relatively shorter where the delta change in curvature is biggest.
  • Maybe you folks have some ideas?

You can find it on GitHub, NPM and as a template on CodePen. Go play around with it! Your contributions and suggestions are very welcome.

CSS

Preferably, I’d like to be able to write something like ease-in-out-gradient(#bada55, transparent) and have the browser understand it without having to do any custom CSS processing.

References/Further Reading


Easing Linear Gradients is a post from CSS-Tricks

Mobile, Small, Portrait, Slow, Interlace, Monochrome, Coarse, Non-Hover, First

Post pobrano z: Mobile, Small, Portrait, Slow, Interlace, Monochrome, Coarse, Non-Hover, First

A month ago I explored the importance of relying on Interaction Media Features to identify the user’s ability to hover over elements or to detect the accuracy of their pointing device, meaning a fine pointer like a mouse or a coarse one like a finger.

But it goes beyond the input devices or the ability to hover; the screen refresh rate, the color of the screen, or the orientation. Making assumptions about these factors based on the width of the viewport is not reliable and can lead to a broken interface.

I’ll take you on a journey through the land of Media Query Level 4 and explore the opportunities that the W3C CSS WG has drafted to help us deal with all the device fruit salad madness.

Media queries

Media queries, in a nutshell, inform us about the context in which our content is being displayed, allowing us to scope and optimize our styles. Meaning, we can display the same content in different ways depending on the context.

The Media Queries Level 4 spec answers two questions:

  • What is the device viewport size and resolution?
  • What is the device capable of doing?

We can detect the device type where the document is being displayed using the media type keywords all, print, screen or speech or you can get more granular using Media Features.

Media Features

Each Media Feature tests a single, specific feature of the device. There are five types:

We can use these features on their own or combine them using the keyword and or a comma to mean „or”. It’s also possible to negate them with the keyword not.

For example:

@media screen and ((min-width: 50em) and (orientation: landscape)), print and (not(color)) {
  ...
}

Scopes the styles to landscape orientated screens that are less than or equal to 50em wide, or monochrome print outputs.

The best way to understand something is by actually doing it. Let’s delve into the corner cases of a navigation bar to test these concepts.

The Unnecessarily Complicated Navbar

One of the best pieces of advice that Brad Frost gave us on „7 Habits of Highly Effective Media Queries” is not to go overboard.

The more complex we make our interfaces the more we have to think in order to properly maintain them. Brad Frost

And that’s exactly what I’m about to do. Let’s go overboard!

Be aware that the following demo was designed as an example to understand what each Media Feature does: if you want to use it (and maintain it), do it at your own risk (and let me know!).

With that in mind, let’s start with the less capable smaller experience, also know as „The mobile, small, portrait, slow, interlace, monochrome, coarse, non-hover first” approach.

The HTML structure

To test the media query features, I started with a very simple structure. On one side: a header with an h1 for a brand name and a nav with an unordered list. On the other side: a main area with a placeholder title and text.

See the Pen Part 1: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Default your CSS for less capable devices and smaller viewport

As I mentioned before, we are thinking of the less capable smaller devices first. Even though we are not scoping styles yet, I am considering an experience that is:

  • max-width: 45em small viewport, less than or equal to 45em wide
  • orientation: portrait portrait viewport, height is larger than width
  • update: slow the output device is not able to render or display changes quickly enough for them to be perceived as a smooth animation.
  • monochrome all monochrome devices
  • pointer: coarse the primary input mechanism has limited accuracy, like a finger
  • hover: none indicates that the primary pointing system can’t hover

Let’s take care of positioning. For portrait, small, touchscreen devices, I want to pin the menu at the bottom of the viewport so users have comfortable access to the menu with their thumbs.

nav {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
}

Since we are targeting touchscreen devices, it is important to increase the touch target. On Inclusive Design Patterns, Heydon Pickering mentions that it’s still unclear what the magical size of a touch area is, different vendors recommend different sizes.

Pickering mentions Anthony Thomas’s article about finger-friendly experiences and Patrick H Lauke research for The W3C Mobile Accessibility Taskforce into touch / pointer target size, and the main takeaway is, „…to make each link larger than the diameter of an adult finger pad”.

That’s why I’ve increased the height of the menu items to 4em. Since this is not scoped, it’ll be applied to any viewport size, so both large touchscreen devices like an iPad Pro and tiny smartphones alike will have comfortable touch targets.

li a {
  min-height: 4em;
}

To help readability on monochromatic or slow devices, like a Kindle, I haven’t removed the underlines from links or added animations. I’ll do that later on.

See the Pen Part 2: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Small landscape viewports, vertical large displays, or mouse pointers

For landscape viewports orientation: landscape, large portrait viewports like vertical monitors or tablets min-width: 45em, or small portrait devices with fine pointers like a stylus pointer: fine, users will no longer be using their thumbs on a handheld device; that’s why I unpinned the menu and put it at the top right of the header.

@media (orientation: landscape), (pointer: fine), (min-width: 45em) {
  main {
    padding-bottom: 1em;
    padding-top: 1em;
  }
  h1, nav {
    position: static;
  }
}

Since the menu and the brand name are already flexed and stretched, then they’ll accommodate themselves nicely.

For users that have a fine pointer like a mouse or a stylus, we want to decrease the hit target to gain the real estate on the main area:

@media (pointer: fine) {
  h1, li a {
    min-height: 2.5em;
  }
}

See the Pen Part 3: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Vertical nav for large landscape viewports

Vertical navigations are great for large landscape viewports (orientation: landscape) and (min-width: 45em), like a tablet or a computer display. To do that I’ll flex the container:

@media (orientation: landscape) and (min-width: 45em) {
  .container {
    display: flex;
  }
  ...
}

Notice that hit targets have nothing to do with the size of the viewport or style of navigation. If the user is on a large touchscreen device with a vertical tab, they’ll see larger targets regardless of the size of the width of the screen.

See the Pen Part 4: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Animations, decorations and edge cases

Animations are a great way to enhance interactions and help users achieve their goals quickly and easily. But some devices are incapable of producing smooth animations – like e-readers. That’s why I am limiting animations to devices that are capable of generating a good experience (update: fast), (scan: progressive), (hover: hover).

@media (update: fast), (scan: progressive), (hover: hover) {
  li a {
    transition: all 0.3s ease-in-out;
  }
}

I am also removing the text decoration on color devices:

@media (color) {
  li a { text-decoration: none; }
}

Removing underlines (via text-decoration) is tricky territory. Our accessibility consultant Marcy Sutton put it well:

Some users really benefit from link underlines, especially in body copy. But since these particular links are part of the navigation with a distinct design treatment, the link color just needs adequate contrast from the background color for users with low vision or color blindness.

We made sure the colors had enough color contrast to pass WCAG AAA.

I’m also increasing the border width to 2px to avoid „twitter” (real term!) on interlace devices like plasma TVs:

@media (scan: interlace) {
  li a, li:first-child a {
    border-width: 2px;
  }
}

And here is the final result:

See the Pen Part 5: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Test it out

Testing all this may not be that easy!. This example relies on flexbox, and some browsers have limited support for other modern CSS features. A Kindle, for example, won’t read @media, @support, or flexbox properties.

I’ve added float fallbacks here:

See the Pen Part 6: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

You can open the full page example in different devices, landscape, or portrait and test it out!

How soon will we realistically be able to use all these features?

Now! That is, if you are ok offering different experiences on different browsers.

Today, Firefox doesn’t support Interaction Media Queries. A Firefox user with a fine pointer mechanism, like a mouse, will see large hit areas reducing the main area real estate.

Browser support for most of these features is already available and support for Interaction Media Features, support isn’t bad! I am sure that we will see it supported across the board soon.

Remember to test as much as you can and don’t assume that any of this will just work, especially in less capable or older devices.

There is more!

I’ve covered some of the Media Features along the example, but I left others behind. For example the Resolution Media Feature that describes the resolution of the output device.

My goal is to make you think beyond your almighty MacBook or iPhone with a retina display. The web is so much more and it’s everywhere. We have the tools to create the most amazing, flexible, inclusive, and adaptable experiences; let’s use them.


Mobile, Small, Portrait, Slow, Interlace, Monochrome, Coarse, Non-Hover, First is a post from CSS-Tricks