Archiwum kategorii: CSS

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

Combining Fonts

Post pobrano z: Combining Fonts

Another one from Jake Archibald!

This one is using two @font-face sets for the same font-family name. The second overrides the first, but only select characters of it, thanks to unicode-range.

You know how designers love ampersands? It’s a thing. Dan Cederholm once pointed out some advice from Robert Bringhurst:

Since the ampersand is more often used in display work than in ordinary text, the more creative versions are often the more useful. There is rarely any reason not to borrow the italic ampersand for use with roman text.

Then Drew McLellan showed how to do that (without a <span>), using unicode-range.

Direct Link to Article — Permalink


Combining Fonts is a post from CSS-Tricks

Methods for Contrasting Text Against Backgrounds

Post pobrano z: Methods for Contrasting Text Against Backgrounds

It started with seeing a recent Pen of Mandy Michael’s text effects demos. I’m a very visual creature, so the first thing I noticed was the effect, not the title (which clearly states how the effect was achieved). Instantly, my mind went „blend modes!”, which turned out to be wrong.

The demo actually uses clip-path. First of all, the text is duplicated. We have black text below as the actual text content of the element and the white text above as the value of the content property (taken from a data attribute which gets updated via JS). These two are stacked one on top of each other (they completely overlap). Then the pseudo-element with the white text above gets clipped to the shape of the black dress.

However, this means we need to change the clipping path if we change the image and, at this point, it’s anything but easy to figure out polygonal clipping paths with a lot of points via dev tools (which is why having something like Benett Feely’s Clippy with two-way editing directly in dev tools would be immensely useful). So I decided to give my initial idea – blend modes – a try.

Let’s say we have a heading in a contentEditable1 container with a black and white image (well, grayscale) background. The HTML structure is as follows:

<header>
  <h2 contentEditable role='textbox' aria-multiline='true'>And stay alive</h2>
</header>

We set the background-image on the header container, we give the h2 white text and set its mix-blend-mode to difference or exclusion. The relevant CSS is below:

header { background: url(black-and-white-image.jpg) }

h2 {
  color: white;
  mix-blend-mode: difference;
}

I can’t really understand blend modes or normally see a difference between difference and exclusion, but according to MDN, they’re pretty much the same, with exclusion having less contrast. What I can understand in this situation is that having white text over the image gives us a result that’s the image inverted where the text overlaps it. For simple black and white images, black in the original image becomes white where we have white text above it and white in the original image becomes black where we have white text above it.

The result can be seen in the following Pen:

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

Mission accomplished! Both the text and the image can be changed and the effect is preserved without the need for any JavaScript or for any changes to the CSS.

But I instantly found that there was another itch to scratch: what happens if the image isn’t just black and white? Well, let’s try that! Turns out the result actually looks pretty good:

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

However, the text isn’t grayscale anymore and setting filter: grayscale(1) doesn’t change anything. Does any filter value work? Well, tried drop-shadow() next to try to find an answer to this question. And the answer is that, yes, drop-shadow() works, but the way it works – the shadow being blended with the header background2 – provides a clue about why grayscale() didn’t change a thing: filters are applied before blending, our text is white and the output of grayscale() in this case is identical to its input (white in, white out). And, since nothing changes before the blending, its result is the same.

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

This probably shouldn’t have been a surprise. I’ve ran into issues caused by the order in which properties are applied before.

For example, filter is also applied before clip-path, so if we clip an element to a non-rectangular shape and we want to have a drop shadow on it, tough luck, setting the filter on the same element doesn’t give the expected result. This is because the rectangular element gets the filter applied, so we have a drop shadow around its rectangular box and only after that gets clipped to the shape specified via clip-path. This is always the order these two get applied in, regardless of the order you set them in the CSS.

Diagram. A box representing an element (left) 
has a CSS filter applied to become a box with a box-shadow (center) then has a clip-path applied to 
become a star with no shadow (right).
Diagram of how browsers apply filter and clip-path when they’re set on the same element.

The way to solve the filter + clip-path problem is to set the filter on a parent element with nothing visible except the clipped child. The „nothing visible” part is important because, if the parent has some visible text or borders, they’ll get the drop shadow as well, while if it has a background, then the whole background area gets the shadow.

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

However, this solution doesn’t work for the filter + mix-blend-mode problem as well. Wrapping our h2 into a div and setting filter on that div breaks the blending effect.

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

What’s worse is that I can’t seem to think of anything I could do to get around this problem. There might be a way of doing it by duplicating the text and using a luminosity blend mode, but, as mentioned before, I don’t really understand blend modes and I haven’t been able to get that right.

But maybe we could try a different approach altogether, one that doesn’t use blending. All the playing with filters gave me the idea that we could apply the image to the text, then apply an invert() filter, to which we could chain grayscale(), contrast() and more.

With this method using background-clip: text, we also have the advantage of a cross-browser solution, since Firefox and Edge have now implemented this too.

The way we go about this is the following: we make sure the header and the h2 have identical backgrounds and that these backgrounds perfectly overlap. Then we set color: transparent on the h2 and clip its background to text. The final step is to set filter: invert(1) on the h2. The relevant CSS3 is as follows:

h2 {
  background: inherit;
  background-clip: text;
  color: transparent;
  filter: invert(1);
}

The result can be seen in the following Pen:

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

It looks like before, except it’s using a different method and now we can chain more functions to the filter property. For example, we can make the text grayscale and up its contrast:

filter: invert(1) grayscale(1) contrast(9)

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

Tweaking the filter value is also how we add a text shadow. While in the first case (using mix-blend-mode) we can simply set the text-shadow property (and the shadow also gets blended with the background), doing so in the second case breaks things:

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

Fortunately, we can chain drop-shadow() to our filter.

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

The Pen below shows the two methods described in this article. On the left, we have the mix-blend-mode method and on the right, we have the background-clip and filter method (with the extra grayscale and contrast components). The text is editable and the thumbnails allow for changing the background-image:

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

So, if we pit these methods against each other, which is better?

When don’t go into aesthetics because it’s a subjective matter and it probably differs from case to case and even from mood to mood.

As far as basic support is concerned, the last method gets an advantage since it’s supported in Edge, while mix-blend-mode isn’t (but if you want it in Edge, please vote for it because your feedback does matter). Mandy’s original example uses clip-path, another very useful feature, which sadly doesn’t work in Edge either (you can vote for it here).

When it comes to selecting text, the mix-blend-mode method works perfectly and looks the best across the browsers it’s supported.

The editable text, made to contrast with the background image using the mix-blend-mode method, shown selected in its entirety. The selection background is blended with the image underneath.
Selecting text when using the mix-blend-mode method

Using the clip-path method, the selection looks clean and the text remains readable, but it seemed to stumble in Firefox while I was over the pseudo-element text. Fortunately, this problem turned out to have an easy fix: setting pointer-events: none on the pseudo-element.

Animated gif. The editable text, made to contrast with the background image using the clip-path method, gets selected in Firefox. The selection stumbles where the copy of this text, generated via a pseudo-element, overlaps the original. Setting pointer-events: none on the pseudo-element fixes this problem.
Selecting text in Firefox when using the clip-path method

As for the last method, the selection can look ugly and can make the text harder to read. Not to mention that the drop shadow ends up being applied to the whole selection rectangle in this case, not just to the actual text.

The editable text, made to contrast with the background image using the background-clip: text + filter method, shown selected in its entirety. The whole selection box has the filter effect applied, not just the text, so the selection background is grayscale and the drop-shadow is now on the selection box, not just on the text itself.
Selecting text when using the background-clip: text + filter method

Changing the text also gets awkward in Firefox with the last method, the screen getting „dirty” as I type new text.

Animated gif. The editable text, made to contrast with the background image using the background-clip: text + filter method, gets edited in Firefox. As you write, the text becomes clipped and garbled, overlapping itself.
Changing text in Firefox when using the background-clip: text + filter method

The clip-path method also had a problem with changing text in Firefox at first: trying to start editing from the middle of the pseudo-element text didn’t work. Fortunately, setting pointer-events: none on the pseudo-element fixes this as well.

Animated gif. The editable text, made to contrast with the background image using the clip-path method, gets edited in Firefox. The cursor cannot be placed to start editing from the part where the copy of this text, generated via a pseudo-element, overlaps the original. Setting pointer-events: none on the pseudo-element fixes this problem.
Changing text in Firefox when using the clip-path method

As far as flexibility in terms of how we can alter the text goes, the last method fares best because chaining filter functions can take us a long way.

At the end of the day, which is better ends up depending on the particular use case. What browsers should be supported? Does the image change? Does the text change? How should the text be visually altered?


1 contentEditable isn’t accessible in all browsers by default, so we need to provide semantics to fix that.

2 When experimenting with blend modes, be aware of the legibility issues they can produce, particularly regarding contrast. WCAG 2.0 states that, unless the text forms part of purely decorative imagery, it should pass a minimum contrast threshold. Tools like Color ContrastAnalyzer can help you meet that requirement.

3 Prefixes are omitted for brevity, but background-clip still needs the -webkit- prefix for WebKit browsers (Firefox and Edge have implemented it unprefixed, though they both support it with the -webkit- prefix as well, probably because it has already been used to death only with that prefix) and this prefix needs to be added manually/ via a preprocessor mixin, which is something that I normally don’t encourage, but, in this particular case, auto-prefixing via Autoprefixer or Prefixfree doesn’t happen (Prefixfree works via feature detection, which doesn’t catch properties such as background-clip, filter or clip-path and this is the Autoprefixer issue). As for filter, it’s now supported unprefixed in all current desktop browsers and Autoprefixer can prefix it anyway.


Methods for Contrasting Text Against Backgrounds is a post from CSS-Tricks

Ordered Lists with Unicode Symbols

Post pobrano z: Ordered Lists with Unicode Symbols

Ordered lists are among the oldest and most semantically rich elements in HTML. Anytime you need to communicate sequence or ranking, the <ol> tag is there to help. The default appearance of the <ol> tag presents numbers next to each item in the list. You can use the list-style-type property in CSS to change the default to use Roman numerals or the letters of the alphabet. If you are feeling exotic, you can even use numbering from other cultures like Hebrew or Greek. The full list of available values is well-documented and easy to use.

Recently, I saw an opportunity to use dice in place of numbers for several ordered lists explaining the features of an HTML5 game I created called Triple Score Bopzee. To accomplish my goal, I first experimented with a now-familiar technique for using a small image file as the background for the li::before selector in a list. One change I made to the usual procedure is that I decided to avoid list-style-type: none in favor of using list-style-type: decimal and setting list-style-image to a 1×1 transparent GIF. That small change helps the page pass accessibility tests because screen readers will still see the list as a valid numbered list.

I created a Pen to demonstrate this classic technique using GIFs of numbers that contain the balls used in four major sports.

See the Pen Ordered List with Images by Steven Estrella (@sgestrella) on CodePen.

This technique would have worked for my needs on the bopzee web site but I got curious about how I could do it without using any images. The answer was to use the Unicode symbols \2680 through \2685 for the six dice. I created a class selector called „dicey” and used the nth-child and before pseudo selectors to position and choose the Unicode character for each list item. I added a link to the Normalize.css library to smooth out the subtle browser differences.

Here is the Pen for the completed dice list:

See the Pen Ordered Lists with Unicode Dice by Steven Estrella (@sgestrella) on CodePen.

So for a list like this:

<ol class="dicey">
  <li>I rolled a one.</li>
  <li>I rolled a two.</li>
  <li>I rolled a three.</li>
  <li>I rolled a four.</li>
  <li>I rolled a five.</li>
  <li>I rolled a six.</li>
</ol>

This was the trick:

/* Still use a decimal based list for a11y */
ol {
  margin-left:40px;
  list-style:decimal url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}

.dicey li:nth-child(1n):before {position:absolute;left:-1em;}

/* Actually set markers with pseudo element unicode */
.dicey li:nth-child(1):before {content: "\2680";}
.dicey li:nth-child(2):before {content: "\2681";}
.dicey li:nth-child(3):before {content: "\2682";}
.dicey li:nth-child(4):before {content: "\2683";}
.dicey li:nth-child(5):before {content: "\2684";}
.dicey li:nth-child(6):before {content: "\2685";}

Initially, I did not specify the font that would display the Unicode symbols. The result was not bad because today every modern web browser and web enabled device has access to at least one font that contains the necessary symbols from the Unicode block called „Miscellaneous Symbols.” There was some variation in appearance but it was quite tolerable. But I knew that if I wanted real control, I would have to find a free web font. I identified a font called DejaVu that would work by looking through the supported fonts list in the table of glyphs for the Miscellaneous Symbols block.

Once I knew the font name, I was able to create a WebFont kit at Font Squirrel. When creating a WebFont kit, it is important to choose the „No subsetting” option to be sure the fonts contain all the Unicode goodness you need for your icons. Or if you are concerned about file size, you can download the original TrueType or OpenType font, then use Font Squirrel’s WebFont generator in expert mode to include only the Unicode range 2600 to 26FF which captures all characters in the Unicode block called „Miscellaneous Symbols.”

Once you get started with Unicode, the fun never stops. I spent way too much time exploring the many icons that are part of the DejaVu font (complete list). There I found icons for playing card suits, astrological signs, arrows, bullets, musical symbols, geometric shapes, and a whole host of squiggles I can’t begin to name. So I took some of my favorites and created a Pen containing several different kinds of lists.

The complete Pen:

See the Pen Ordered Lists with Unicode Symbols by Steven Estrella (@sgestrella) on CodePen.

What about unordered lists?

You can give your <ul> elements the same great Unicode love using a modified form of this technique. Here is a Pen to get you started:

See the Pen Unordered List with Unicode Bullets by Steven Estrella (@sgestrella) on CodePen.

What about the future?

There is a new CSS rule called @counter-style which will allow us more easily to create custom counter styles for ordered lists, specifying the symbols to be used, the range of the list, and lots of other options. The CSS Counter Styles Level 3 specification is now a Candidate Recommendation at the W3C but as of May 2017 only FireFox supports it (with some issues). I would expect that Chrome, Edge, and Safari will add support sometime soon but the final version of Internet Explorer (version 11) will likely never have it. So if you have to support that browser, you will be stuck with tricks like the one described on this post until people stop using IE11 (perhaps the year 2020?).

Note that the @counter-style rule does not provide any way to style the counter symbol using CSS. So even when it is adopted by all browsers, there may be use cases for alternative solutions like the one presented here. You can read more about @counter-style on MDN. Here is a pen with a demonstration.

Be sure to use FireFox to see the effect:

See the Pen @counter-style demo (FireFox only as of May 2017) by Steven Estrella (@sgestrella) on CodePen.

On the shoulders of giants

We all learn from the work of others and I wish to credit the work of several writers whose articles I found informative when preparing this post.

Here is a Pen with the unordered list above using several different icon styles!

See the Pen List of Credits with Unicode Bullets by Steven Estrella (@sgestrella) on CodePen.


Ordered Lists with Unicode Symbols is a post from CSS-Tricks

CSS Custom Properties and Theming

Post pobrano z: CSS Custom Properties and Theming

We posted not long ago about the difference between native CSS variables (custom properties) and preprocessor variables. There are a few esoteric things preprocessor variables can do that native variables cannot, but for the most part, native variables can do the same things. But, they are more powerful because of how they are live-interpolated. Should their values ever change (e.g. JavaScript, media query hits, etc) the change triggers immediate change on the site.

Cool, right? But still, how actually useful is that? What are the major use cases? I think we’re still seeing those shake out.

One use case, it occurred to me, would be theming of a site (think: custom colors for elements around a site). Rather than writing different CSS for a bunch of different themes, or writing JavaScript that targets all the elements we intend to change and changing them), we just write one base set of CSS that utilizes variables and set those variables to the theme colors.

Imagine we allow the header and footer background of our site to be customized.

header {
  background: var(--mainColor);
}

...

footer {
  background: var(--mainColor);
}

Maybe there is a subheader with a darker variation of that color. Here’s a little trick to lay a transparent layer of color over another:

.subheader {
  background: 
    /* Make a bit darker */
    linear-gradient(
      to top,
      rgba(0, 0, 0, 0.25),
      rgba(0, 0, 0, 0.25)
    )
    var(--mainColor);
}

Where does --mainColor come from?

With theming, the idea is that you ask the user for it. Fortunately we have color inputs:

<input type="color" />

And you could store that value in a database or any other storage mechanism you want. Here’s a little demo where the value is stored in localStorage:

See the Pen Theming a site with CSS Custom Properties by Chris Coyier (@chriscoyier) on CodePen.

The value is plucked out of localStorage and used when the page loads. A default value is also set (in CSS), in case that doesn’t exist.

What makes the above demo so compelling, to me, is how little code it is. Maintaining this as a a feature on a site is largely a CSS endeavour and seems flexible enough to stand the test of time (probably).

Not unusually, I was way behind on this one.

Lots of people think of theming as one of the major use-cases for CSS Custom Properties. Let’s look at some other folks examples.

Giacomo Zinetti has the same kind of color-picker implementation

On his site:

Examples and advice from Harry Roberts

He wrote „Pragmatic, Practical, and Progressive Theming with Custom Properties”, in which he pointed to apps like Twitter and Trello that offer theming directly to users:

Harry does a lot of consulting, and to my surprise, finds himself working with companies that want to do this a lot. He warns:

Theming, the vast majority of the time, is a complete nice-to-have. It is not business critical or usually even important. If you are asked to provide such theming, do not do so at the expense of performance or code quality.

In Sass / In React

In a real-world application of theming through Custom Properties, Dan Bahrami recounts how they did it on Geckoboard, the product he works on:

It’s a React product, but they aren’t using any styles-in-JavaScript stuff, so they opted to do the theming with Custom Properties, through Sass.

@mixin variable($property, $variable, $fallback) {
  #{$property}: $fallback;
  #{$property}: var($variable);
}

So they can do:

.dashboard {
  @include variable(background, --theme-primary-color, blue);
}

Which compiles to having a fallback:

.dashboard {
  background: blue;
  background: var(--theme-primary-color);
}

They also created react-custom-properties which all about applying Custom Properties to components, taking advantage of the fact that you can set Custom Properties as inline styles:

<div style="--theme-primary-color: blue;">

</div>

More than one color and property

It’s not only colors that can change, a Custom Property can be any valid value. Here’s Keith Clark with a demo with multiple colors as well as font size:

See the Pen Using CSS custom properties for theme previews by Keith Clark (@keithclark) on CodePen.

And David Darnes with theming built into a Jekyll site:

Experimenting with CSS Custom Properties with my @jekyllrb theme, allowing people to customise it https://t.co/SP9lhxdcoD (WIP) pic.twitter.com/7QAzKtD5n7

— David Darnes (@DavidDarnes) April 27, 2017

Microsoft Demo

Greg Whitworth created this demo:

Which uses color modifiers within color functions themselves:

.distant-building__window {
  fill: rgb(
    calc(111 + (111 * var(--building-r-mod))),
    calc(79 + (79 * var(--building-g-mod))),
    calc(85 + (85 * var(--building-b-mod)))
  );
}

Which is not supported in all browsers.

Greg also pointed out that CSS4 color functions (which we’ve covered before), will make all this theming stuff even more powerful.

The Polymer Project themes through Custom Properties

At least it did in the v1 docs. The idea is that you’d have a web compontent, like:

<iron-icon icon="[[toggleIcon]]">
</iron-icon>

That had smart defaults, but was specifically built to allow styling via theming:

<style>
  iron-icon {
    fill: var(--icon-toggle-color, rgba(0,0,0,0));
    stroke: var(--icon-toggle-outline-color, currentcolor);
  }
  :host([pressed]) iron-icon {
    fill: var(--icon-toggle-pressed-color, currentcolor);
  }
</style>

Which meant that you could set those variables and have the component take on new colors.

Support and fallbacks

Support has gotten pretty good recently:

Green indicates full support at the version listed (and above). Yellow indicates partial support. Red indicates no support. See Caniuse for full browser support details.

Desktop

Chrome Opera Firefox IE Edge Safari
49 36 31 No 15 9.1

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
9.3 37 No 56 57 52

Opera Mini and IE are notably missing. We already covered the idea of a fallback through setting a valid non-variable property before the one using a Custom Property.

Like many modern CSS features, you can use @supports to test for support before using:

@supports (--color: red) {
  :root {
    --color: red;
  }
  body {
    color: var(--color);
  }
}

It always depends on the situation, but just putting fallbacks on a previous declaration is probably the most useful way to deal with non-support in CSS. There are also edge cases.

Michael Scharnagl documents a JavaScript method for testing:

if (window.CSS && window.CSS.supports && window.CSS.supports('--a', 0)) {
  // CSS custom properties supported.
} else {
  // CSS custom properties not supported
}

Colors and Accessibility

When setting colors for text, and the color behind that text, the contrast between those colors is an accessibility issue. Too little contrast, too hard to read.

One somewhat common solution to this is to choose whether the text should be light or dark (white or black) based on the color behind it.

David Halford has a demo calculating this with JavaScript:

See the Pen JS function for accessible color contrast by David Halford (@davidhalford) on CodePen.

And Brendan Saunders with Sass:

See the Pen Sass text-contrast mixin by Brendan Saunders (@bluesaunders) on CodePen.


CSS Custom Properties and Theming is a post from CSS-Tricks

Using Fetch

Post pobrano z: Using Fetch

Whenever we send or retrieve information with JavaScript, we initiate a thing known as an Ajax call. Ajax is a technique to send and retrieve information behind the scenes without needing to refresh the page. It allows browsers to send and retrieve information, then do things with what it gets back, like add or change HTML on the page.

Let’s take a look at the history of that and then bring ourselves up-to-date.

Another note here, we’re going to be using ES6 syntax for all the demos in this article.

A few years ago, the easiest way to initiate an Ajax call was through the use of jQuery’s ajax method:

$.ajax('some-url', {
  success: (data) => { /* do something with the data */ },
  error: (err) => { /* do something when an error happens */}
});

We could do Ajax without jQuery, but we had to write an XMLHttpRequest, which is pretty complicated.

Thankfully, browsers nowadays have improved so much that they support the Fetch API, which is a modern way to Ajax without helper libraries like jQuery or Axios. In this article, I’ll show you how to use Fetch to handle both success and errors.

Support for Fetch

Let’s get support out of the way first.

Green indicates full support at the version listed (and above). Yellow indicates partial support. Red indicates no support. See Caniuse for full browser support details.

Desktop

Chrome Opera Firefox IE Edge Safari
42 29 39 No 14 10.1

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
10.3 37 No 56 57 52

Support for Fetch is pretty good! All major browsers (with the exception of Opera Mini and old IE) support it natively, which means you can safely use it in your projects. If you need support anywhere it isn’t natively supported, you can always depend on this handy polyfill.

Getting data with Fetch

Getting data with Fetch is easy. You just need to provide Fetch with the resource you’re trying to fetch (so meta!).

Let’s say we’re trying to get a list of Chris’ repositories on Github. According to Github’s API, we need to make a get request for api.github.com/users/chriscoyier/repos.

This would be the fetch request:

fetch('https://api.github.com/users/chriscoyier/repos');

So simple! What’s next?

Fetch returns a Promise, which is a way to handle asynchronous operations without the need for a callback.

To do something after the resource is fetched, you write it in a .then call:

fetch('https://api.github.com/users/chriscoyier/repos')
  .then(response => {/* do something */})

If this is your first encounter with Fetch, you’ll likely be surprised by the response Fetch returns. If you console.log the response, you’ll get the following information:

{
  body: ReadableStream
  bodyUsed: false
  headers: Headers
  ok : true
  redirected : false
  status : 200
  statusText : "OK"
  type : "cors"
  url : "http://some-website.com/some-url"
  __proto__ : Response
}

Here, you can see that Fetch returns a response that tells you the status of the request. We can see that the request is successful (ok is true and status is 200), but a list of Chris’ repos isn’t present anywhere!

Turns out, what we requested from Github is hidden in body as a readable stream. We need to call an appropriate method to convert this readable stream into data we can consume.

Since we’re working with GitHub, we know the response is JSON. We can call response.json to convert the data.

There are other methods to deal with different types of response. If you’re requesting an XML file, then you should call response.text. If you’re requesting an image, you call response.blob.

All these conversion methods (response.json et all) returns another Promise, so we can get the data we wanted with yet another .then call.

fetch('https://api.github.com/users/chriscoyier/repos')
  .then(response => response.json())
  .then(data => {
    // Here's a list of repos!
    console.log(data)
  });

Phew! That’s all you need to do to get data with Fetch! Short and simple, isn’t it? 🙂

Next, let’s take a look at sending some data with Fetch.

Sending data with Fetch

Sending data with Fetch is pretty simple as well. You just need to configure your fetch request with three options.

fetch('some-url', options);

The first option you need to set is your request method to post, put or del. Fetch automatically sets the method to get if you leave it out, which is why getting a resource takes lesser steps.

The second option is to set your headers. Since we’re primarily sending JSON data in this day and age, we need to set Content-Type to be application/json.

The third option is to set a body that contains JSON content. Since JSON content is required, you often need to call JSON.stringify when you set the body.

In practice, a post request with these three options looks like:

let content = {some: 'content'};

// The actual fetch request
fetch('some-url', {
  method: 'post',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(content)
})
// .then()...

For the sharp-eyed, you’ll notice there’s some boilerplate code for every post, put or del request. Ideally, we can reuse our headers and call JSON.stringify on the content before sending since we already know we’re sending JSON data.

But even with the boilerplate code, Fetch is still pretty nice for sending any request.

Handling errors with Fetch, however, isn’t as straightforward as handling success messages. You’ll see why in a moment.

Handling errors with Fetch

Although we always hope for Ajax requests to be successful, they can fail. There are many reasons why requests may fail, including but not limited to the following:

  1. You tried to fetch a non-existent resource.
  2. You’re unauthorized to fetch the resource.
  3. You entered some arguments wrongly
  4. The server throws an error.
  5. The server timed out.
  6. The server crashed.
  7. The API changed.
  8. …

Things aren’t going to be pretty if your request fails. Just imagine a scenario you tried to buy something online. An error occured, but it remains unhandled by the people who coded the website. As a result, after clicking buy, nothing moves. The page just hangs there… You have no idea if anything happened. Did your card go through? 😱.

Now, let’s try to fetch a non-existent error and learn how to handle errors with Fetch. For this example, let’s say we misspelled chriscoyier as chrissycoyier

// Fetching chrissycoyier's repos instead of chriscoyier's repos
fetch('https://api.github.com/users/chrissycoyier/repos')

We already know we should get an error since there’s no chrissycoyier on Github. To handle errors in promises, we use a catch call.

Given what we know now, you’ll probably come up with this code:

fetch('https://api.github.com/users/chrissycoyier/repos')
  .then(response => response.json())
  .then(data => console.log('data is', data))
  .catch(error => console.log('error is', error));

Fire your fetch request. This is what you’ll get:

Fetch failed, but the code that gets executed is the second `.then` instead of `.catch`

Why did our second .then call execute? Aren’t promises supposed to handle errors with .catch? Horrible! 😱😱😱

If you console.log the response now, you’ll see slightly different values:

{
  body: ReadableStream
  bodyUsed: true
  headers: Headers
  ok: false // Response is not ok
  redirected: false
  status: 404 // HTTP status is 404.
  statusText: "Not Found" // Request not found
  type: "cors"
  url: "https://api.github.com/users/chrissycoyier/repos"
}

Most of the response remain the same, except ok, status and statusText. As expected, we didn’t find chrissycoyier on Github.

This response tells us Fetch doesn’t care whether your AJAX request succeeded. It only cares about sending a request and receiving a response from the server, which means we need to throw an error if the request failed.

Hence, the initial then call needs to be rewritten such that it only calls response.json if the request succeeded. The easiest way to do so to check if the response is ok.

fetch('some-url')
  .then(response => {
    if (response.ok) {
      return response.json()
    } else {
      // Find some way to get to execute .catch()
    }
  });

Once we know the request is unsuccessful, we can either throw an Error or reject a Promise to activate the catch call.

// throwing an Error
else {
  throw new Error('something went wrong!')
}

// rejecting a Promise
else {
  return Promise.reject('something went wrong!')
}

Choose either one, because they both activate the .catch call.

Here, I choose to use Promise.reject because it’s easier to implement. Errors are cool too, but they’re harder to implement, and the only benefit of an Error is a stack trace, which would be non-existent in a Fetch request anyway.

So, the code looks like this so far:

fetch('https://api.github.com/users/chrissycoyier/repos')
  .then(response => {
    if (response.ok) {
      return response.json()
    } else {
      return Promise.reject('something went wrong!')
    }
  })
  .then(data => console.log('data is', data))
  .catch(error => console.log('error is', error));
Failed request, but error gets passed into catch correctly

This is great. We’re getting somewhere since we now have a way to handle errors.

But rejecting the promise (or throwing an Error) with a generic message isn’t good enough. We won’t be able to know what went wrong. I’m pretty sure you don’t want to be on the receiving end for an error like this…

Yeah… I get it that something went wrong… but what exactly? 🙁

What went wrong? Did the server time out? Was my connection cut? There’s no way for me to know! What we need is a way to tell what’s wrong with the request so we can handle it appropriately.

Let’s take a look at the response again and see what we can do:

{
  body: ReadableStream
  bodyUsed: true
  headers: Headers
  ok: false // Response is not ok
  redirected: false
  status: 404 // HTTP status is 404.
  statusText: "Not Found" // Request not found
  type: "cors"
  url: "https://api.github.com/users/chrissycoyier/repos"
}

Okay great. In this case, we know the resource is non-existent. We can return a 404 status or Not Found status text and we’ll know what to do with it.

To get status and statusText into the .catch call, we can reject a JavaScript object:

fetch('some-url')
  .then(response => {
    if (response.ok) {
      return response.json()
    } else {
      return Promise.reject({
        status: response.status,
        statusText: response.statusText
      })
    }
  })
  .catch(error => {
    if (error.status === 404) {
      // do something about 404
    }
  })

Now we’re getting somewhere again! Yay! 😄.

Let’s make this better! 😏.

The above error handling method is good enough for certain HTTP statuses which doesn’t require further explanation, like:

  • 401: Unauthorized
  • 404: Not found
  • 408: Connection timeout
  • …

But it’s not good enough for this particular badass:

  • 400: Bad request.

What constitutes bad request? It can be a whole slew of things! For example, Stripe returns 400 if the request is missing a required parameter.

Stripe’s explains it returns a 400 error if the request is missing a required field

It’s not enough to just tell our .catch statement there’s a bad request. We need more information to tell what’s missing. Did your user forget their first name? Email? Or maybe their credit card information? We won’t know!

Ideally, in such cases, your server would return an object, telling you what happened together with the failed request. If you use Node and Express, such a response can look like this.

res.status(400).send({
  err: 'no first name'
})

Here, we can’t reject a Promise in the initial .then call because the error object from the server can only be read after response.json.

The solution is to return a promise that contains two then calls. This way, we can first read what’s in response.json, then decide what to do with it.

Here’s what the code looks like:

fetch('some-error')
  .then(handleResponse)

function handleResponse(response) {
  return response.json()
    .then(json => {
      if (response.ok) {
        return json
      } else {
        return Promise.reject(json)
      }
    })
}

Let’s break the code down. First, we call response.json to read the json data the server sent. Since, response.json returns a Promise, we can immediately call .then to read what’s in it.

We want to call this second .then within the first .then because we still need to access response.ok to determine if the response was successful.

If you want to send the status and statusText along with the json into .catch, you can combine them into one object with Object.assign().

let error = Object.assign({}, json, {
  status: response.status,
  statusText: response.statusText
})
return Promise.reject(error)

With this new handleResponse function, you get to write your code this way, and your data gets passed into .then and .catch automatically

fetch('some-url')
  .then(handleResponse)
  .then(data => console.log(data))
  .catch(error => console.log(error))

Unfortunately, we’re not done with handling the response just yet 🙁

Handling other response types

So far, we’ve only touched on handling JSON responses with Fetch. This already solves 90% of use cases since APIs return JSON nowadays.

What about the other 10%?

Let’s say you received an XML response with the above code. Immediately, you’ll get an error in your catch statement that says:

Parsing an invalid JSON produces a Syntax error

This is because XML isn’t JSON. We simply can’t return response.json. Instead, we need to return response.text. To do so, we need to check for the content type by accessing the response headers:

.then(response => {
  let contentType = response.headers.get('content-type')

  if (contentType.includes('application/json')) {
    return response.json()
    // ...
  }

  else if (contentType.includes('text/html')) {
    return response.text()
    // ...
  }

  else {
    // Handle other responses accordingly...
  }
});

Wondering why you’ll ever get an XML response?

Well, I encountered it when I tried using ExpressJWT to handle authentication on my server. At that time, I didn’t know you can send JSON as a response, so I left it as its default, XML. This is just one of the many unexpected possibilities you’ll encounter. Want another? Try fetching some-url 🙂

Anyway, here’s the entire code we’ve covered so far:

fetch('some-url')
  .then(handleResponse)
  .then(data => console.log(data))
  .then(error => console.log(error))

function handleResponse (response) {
  let contentType = response.headers.get('content-type')
  if (contentType.includes('application/json')) {
    return handleJSONResponse(response)
  } else if (contentType.includes('text/html')) {
    return handleTextResponse(response)
  } else {
    // Other response types as necessary. I haven't found a need for them yet though.
    throw new Error(`Sorry, content-type ${contentType} not supported`)
  }
}

function handleJSONResponse (response) {
  return response.json()
    .then(json => {
      if (response.ok) {
        return json
      } else {
        return Promise.reject(Object.assign({}, json, {
          status: response.status
          statusText: response.statusText
        }))
      }
    })
}
function handleTextResponse (response) {
  return response.text()
    .then(text => {
      if (response.ok) {
        return json
      } else {
        return Promise.reject({
          status: response.status,
          statusText: response.statusText,
          err: text
        })
      }
    })
}

It’s a lot of code to write/copy and paste into if you use Fetch. Since I use Fetch heavily in my projects, I create a library around Fetch that does exactly what I described in this article (plus a little more).

Introducing zlFetch

zlFetch is a library that abstracts away the handleResponse function so you can skip ahead to and handle both your data and errors without worrying about the response.

A typical zlFetch look like this:

zlFetch('some-url', options)
  .then(data => console.log(data))
  .catch(error => console.log(error));

To use zlFetch, you first have to install it.

npm install zl-fetch --save

Then, you’ll import it into your code. (Take note of default if you aren’t importing with ES6 imports). If you need a polyfill, make sure you import it before adding zlFetch.

// Polyfills (if needed)
require('isomorphic-fetch') // or whatwg-fetch or node-fetch if you prefer

// ES6 Imports
import zlFetch from 'zl-fetch';

// CommonJS Imports
const zlFetch = require('zl-fetch');

zlFetch does a bit more than removing the need to handle a Fetch response. It also helps you send JSON data without needing to write headers or converting your body to JSON.

The below the functions do the same thing. zlFetch adds a Content-Type and converts your content into JSON under the hood.

let content = {some: 'content'}

// Post request with fetch
fetch('some-url', {
  method: 'post',
  headers: {'Content-Type': 'application/json'}
  body: JSON.stringify(content)
});

// Post request with zlFetch
zlFetch('some-url', {
  method: 'post',
  body: content
});

zlFetch also makes authentication with JSON Web Tokens easy.

The standard practice for authentication is to add an Authorization key in the headers. The contents of this Authorization key is set to Bearer your-token-here. zlFetch helps to create this field if you add a token option.

So, the following two pieces of code are equivalent.

let token = 'someToken'
zlFetch('some-url', {
  headers: {
    Authorization: `Bearer ${token}`
  }
});

// Authentication with JSON Web Tokens with zlFetch
zlFetch('some-url', {token});

That’s all zlFetch does. It’s just a convenient wrapper function that helps you write less code whenever you use Fetch. Do check out zlFetch if you find it interesting. Otherwise, feel free to roll your own!

Here’s a Pen for playing around with zlFetch:

See the Pen zlFetch demo by Zell Liew (@zellwk) on CodePen.

Wrapping up

Fetch is a piece of amazing technology that makes sending and receiving data a cinch. We no longer need to write XHR requests manually or depend on larger libraries like jQuery.

Although Fetch is awesome, error handling with Fetch isn’t straightforward. Before you can handle errors properly, you need quite a bit of boilerplate code to pass information go to your .catch call.

With zlFetch (and the info presented in this article), there’s no reason why we can’t handle errors properly anymore. Go out there and put some fun into your error messages too 🙂


By the way, if you liked this post, you may also like other front-end-related articles I write on my blog. Feel free to pop by and ask any questions you have. I’ll get back to you as soon as I can.


Using Fetch is a post from CSS-Tricks

Focus Styles on Non-Interactive Elements?

Post pobrano z: Focus Styles on Non-Interactive Elements?

Last month, Heather Migliorisi looked at the accessibility of Smooth Scrolling. In order to do smooth scrolling, you:

  1. Check if the clicked link is #jump link
  2. Stop the browser default behavior of jumping immediately to that element on the page
  3. Animate the scrolling to the element the #jump link pointed to

Stopping the browser default behavior is the part that is problematic for accessibility. No longer does the #jump link move focus to element the #jump link pointed to. So Heather added a #4: move focus to the element the #jump link pointed to.

But moving focus through JavaScript isn’t possible on every element. Sometimes you need to force that element to be focusable, which she did through setting tabindex="-1".

We since updated our snippet to do this more-accessible handling of focus. Since then, we’ve heard from quite a few folks about a new side effect to the updated snippet:

Notice the glowing blue outline of the headers that were scrolled to.

After the smooth scrolling, the headers that were scrolled to now have the default blue glowing outline that links have by default. Even if we don’t always love the blue glowing outline (the style varies by user agent, it might be a dotted outline, for example) we know better to remove it.

There is even a website dedicated to that sentiment:

http://www.outlinenone.com/

You can change the focus style if you like, but it’s good accessibility to have a distinct focus style for elements that are in focus. I can even imagine an argument for leaving the focus styles alone.

But but but

Headers aren’t focusable elements.

They aren’t „interactive” elements. We aren’t used to seeing focus styles on non-interactive elements. But now, all the sudden, because we used a smooth scrolling technique from the internet, we’re getting them. That tabindex="-1" technique to allow focus is causing it.

I reached out to Heather to ask her about this.

The :focus styling for headings and other non-interactive elements can be removed/left off. It’s really up to the folks behind the creative site if they want it or not there. In some cases, I’ve removed it, in others I’ve styled it. It just depends.

To my surprise, it’s OK to remove focus styles in the case that the element you’re force-focusing isn’t interactive. That last point is important, and Heather clarified:

As long as the headings are not links… 😉

So if you really hated the focus styles, you could do:

h1:focus,
h2:focus, 
h3:focus,
h4:focus,
h5:focus,
h6:focus {
  outline: 0;
}

You’re safe there. Even in the cases of <a><h3></h3></a> or <h3><a></a></h3>, the link still has focus styles.

It’s not just headers

Jump links can point to any element, and there are lots of non-focusable-by-default elements. Another classic technique in this situation is the „yellow fade” technique. Let’s say instead of linking to headers, we were linking to <section>s. When any section comes into focus, we could style it like this:

section:focus {
  outline: 0;
  animation: yellowFade 3s forwards;
}
@keyframes yellowFade {
  from { background: lightYellow; }
  to   { background: white; }
}

Which gives us:

Which is an adaptation of something that was often used for :target.


Focus Styles on Non-Interactive Elements? is a post from CSS-Tricks