Tag: made

5 Mistakes I Made When Starting My First React Project

You know what it’s like to pick up a new language or framework. Sometimes there’s great documentation to help you find your way through it. But even the best documentation doesn’t cover absolutely everything. And when you work with something that’s new, you’re bound to find a problem that doesn’t have a written solution.

That’s how it was for me the first time I created a React project — and React is one of those frameworks with remarkable documentation, especially now with the beta docs. But I still struggled my way through. It’s been quite a while since that project, but the lessons I gained from it are still fresh in my mind. And even though there are a lot of React “how-to” tutorials in out there, I thought I’d share what I wish I knew when I first used it.

So, that’s what this article is — a list of the early mistakes I made. I hope they help make learning React a lot smoother for you.

Using create-react-app to start a project

TL;DR Use Vite or Parcel.

Create React App (CRA) is a tool that helps you set up a new React project. It creates a development environment with the best configuration options for most React projects. This means you don’t have to spend time configuring anything yourself.

As a beginner, this seemed like a great way to start my work! No configuration! Just start coding!

CRA uses two popular packages to achieve this, webpack and Babel. webpack is a web bundler that optimizes all of the assets in your project, such as JavaScript, CSS, and images. Babel is a tool that allows you to use newer JavaScript features, even if some browsers don’t support them.

Both are good, but there are newer tools that can do the job better, specifically Vite and Speedy Web Compiler (SWC).

These new and improved alternatives are faster and easier to configure than webpack and Babel. This makes it easier to adjust the configuration which is difficult to do in create-react-app without ejecting.

To use them both when setting up a new React project you have to make sure you have Node version 12 or higher installed, then run the following command.

npm create vite

You’ll be asked to pick a name for your project. Once you do that, select React from the list of frameworks. After that, you can select either Javascript + SWC or Typescript + SWC

Then you’ll have to change directory cd into your project and run the following command;

npm i && npm run dev

This should run a development server for your site with the URL localhost:5173

And it’s as simple as that.

Using defaultProps for default values

TL;DR Use default function parameters instead.

Data can be passed to React components through something called props. These are added to a component just like attributes in an HTML element and can be used in a component’s definition by taking the relevant values from the prop object passed in as an argument.

// App.jsx export default function App() {   return <Card title="Hello" description="world" /> }  // Card.jsx function Card(props) {   return (     <div>       <h1>{props.title}</h1>       <p>{props.description}</p>     </div>   ); }  export default Card;

If a default value is ever required for a prop, the defaultProp property can be used:

// Card.jsx function Card(props) {   // ... }  Card.defaultProps = {   title: 'Default title',   description: 'Desc', };  export default Card;

With modern JavaScript, it is possible to destructure the props object and assign a default value to it all in the function argument.

// Card.jsx function Card({title = "Default title", description= "Desc"}) {   return (     <div>       <h1>5 Mistakes I Made When Starting My First React Project</h1>       <p>{description}</p>     </div>   ) }  export default Card;

This is more favorable as the code that can be read by modern browsers without the need for extra transformation.

Unfortunately, defaultProps do require some transformation to be read by the browser since JSX (JavaScript XML) isn’t supported out of the box. This could potentially affect the performance of an application that is using a lot of defaultProps.

Don’t use propTypes

TL;DR Use TypeScript.

In React, the propTypes property can be used to check if a component is being passed the correct data type for its props. They allow you to specify the type of data that should be used for each prop such as a string, number, object, etc. They also allow you to specify if a prop is required or not.

This way, if a component is passed the wrong data type or if a required prop is not being provided, then React will throw an error.

// Card.jsx import { PropTypes } from "prop-types";  function Card(props) {   // ... }  Card.propTypes = {   title: PropTypes.string.isRequired,   description: PropTypes.string, };  export default Card;

TypeScript provides a level of type safety in data that’s being passed to components. So, sure, propTypes were a good idea back when I was starting. However, now that TypeScript has become the go-to solution for type safety, I would highly recommend using it over anything else.

// Card.tsx interface CardProps {   title: string,   description?: string, }  export default function Card(props: CardProps) {   // ... }

TypeScript is a programming language that builds on top of JavaScript by adding static type-checking. TypeScript provides a more powerful type system, that can catch more potential bugs and improves the development experience.

Using class components

TL;DR: Write components as functions

Class components in React are created using JavaScript classes. They have a more object-oriented structure and as well as a few additional features, like the ability to use the this keyword and lifecycle methods.

// Card.jsx class Card extends React.Component {   render() {     return (       <div>         <h1>{this.props.title}</h1>         <p>{this.props.description}</p>       </div>     )   } }  export default Card;

I prefer writing components with classes over functions, but JavaScript classes are more difficult for beginners to understand and this can get very confusing. Instead, I’d recommend writing components as functions:

// Card.jsx function Card(props) {   return (     <div>       <h1>{props.title}</h1>       <p>{props.description}</p>     </div>   ) }  export default Card;

Function components are simply JavaScript functions that return JSX. They are much easier to read, and do not have additional features like the this keyword and lifecycle methods which make them more performant than class components.

Function components also have the advantage of using hooks. React Hooks allow you to use state and other React features without writing a class component, making your code more readable, maintainable and reusable.

Importing React unnecessarily

TL;DR: There’s no need to do it, unless you need hooks.

Since React 17 was released in 2020, it’s now unnecessary to import React at the top of your file whenever you create a component.

import React from 'react'; // Not needed! export default function Card() {}

But we had to do that before React 17 because the JSX transformer (the thing that converts JSX into regular JavaScript) used a method called React.createElement that would only work when importing React. Since then, a new transformer has been release which can transform JSX without the createElement method.

You will still need to import React to use hooks, fragments, and any other functions or components you might need from the library:

import { useState } from 'react';  export default function Card() {   const [count, setCount] = useState(0);   // ... }

Those were my early mistakes!

Maybe “mistake” is too harsh a word since some of the better practices came about later. Still, I see plenty of instances where the “old” way of doing something is still being actively used in projects and other tutorials.

To be honest, I probably made way more than five mistakes when getting started. Anytime you reach for a new tool it is going to be more like a learning journey to use it effectively, rather than flipping a switch. But these are the things I still carry with me years later!

If you’ve been using React for a while, what are some of the things you wish you knew before you started? It would be great to get a collection going to help others avoid the same struggles.


5 Mistakes I Made When Starting My First React Project originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

CSS-Tricks

, , , , ,

How I Made an Icon System Out of CSS Custom Properties

SVG is the best format for icons on a website, there is no doubt about that. It allows you to have sharp icons no matter the screen pixel density, you can change the styles of the SVG on hover and you can even animate the icons with CSS or JavaScript.

There are many ways to include an SVG on a page and each technique has its own advantages and disadvantages. For the last couple of years, I have been using a Sass function to import directly my icons in my CSS and avoid having to mess up my HTML markup.

I have a Sass list with all the source codes of my icons. Each icon is then encoded into a data URI with a Sass function and stored in a custom property on the root of the page.

TL;DR

What I have for you here is a Sass function that creates a SVG icon library directly in your CSS.

The SVG source code is compiled with the Sass function that encodes them in data URI and then stores the icons in CSS custom properties. You can then use any icon anywhere in your CSS like as if it was an external image.

This is an example pulled straight from the code of my personal site:

.c-filters__summary h2:after {   content: var(--svg-down-arrow);   position: relative;   top: 2px;   margin-left: auto;   animation: closeSummary .25s ease-out; }

Demo

Sass structure

/* All the icons source codes */ $  svg-icons: (   burger: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0...' );  /* Sass function to encode the icons */ @function svg($  name) {   @return url('data:image/svg+xml, #{$  encodedSVG} '); }  /* Store each icon into a custom property */ :root {   @each $  name, $  code in $  svg-icons {     --svg-#{$  name}: #{svg($  name)};   } }  /* Append a burger icon in my button */ .menu::after {   content: var(--svg-burger); }		

This technique has both pros and cons, so please take them into account before implementing this solution on your project:

Pros

  • There are no HTTP requests for the SVG files.
  • All of the icons are stored in one place.
  • If you need to update an icon, you don’t have to go over each HTML templates file.
  • The icons are cached along with your CSS.
  • You can manually edit the source code of the icons.
  • It does not pollute your HTML by adding extra markup.
  • You can still change the color or some aspect of the icon with CSS.

Cons

  • You cannot animate or update a specific part of the SVG with CSS.
  • The more icons you have, the heavier your CSS compiled file will be.

I mostly use this technique for icons rather than logos or illustrations. An encoded SVG is always going to be heavier than its original file, so I still load my complex SVG with an external file either with an <img> tag or in my CSS with url(path/to/file.svg).

Encoding SVG into data URI

Encoding your SVG as data URIs is not new. In fact Chris Coyier wrote a post about it over 10 years ago to explain how to use this technique and why you should (or should not) use it.

There are two ways to use an SVG in your CSS with data URI:

  • As an external image (using background-image,border-image,list-style-image,…)
  • As the content of a pseudo element (e.g. ::before or ::after)

Here is a basic example showing how you how to use those two methods:

The main issue with this particular implementation is that you have to convert the SVG manually every time you need a new icon and it is not really pleasant to have this long string of unreadable code in your CSS.

This is where Sass comes to the rescue!

Using a Sass function

By using Sass, we can make our life simpler by copying the source code of our SVG directly in our codebase, letting Sass encode them properly to avoid any browser error.

This solution is mostly inspired by an existing function developed by Threespot Media and available in their repository.

Here are the four steps of this technique:

  • Create a variable with all your SVG icons listed.
  • List all the characters that needs to be skipped for a data URI.
  • Implement a function to encode the SVGs to a data URI format.
  • Use your function in your code.

1. Icons list

/** * Add all the icons of your project in this Sass list */ $  svg-icons: (   burger: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24.8 18.92" width="24.8" height="18.92"><path d="M23.8,9.46H1m22.8,8.46H1M23.8,1H1" fill="none" stroke="#000" stroke-linecap="round" stroke-width="2"/></svg>' );

2. List of escaped characters

/** * Characters to escape from SVGs * This list allows you to have inline CSS in your SVG code as well */ $  fs-escape-chars: (   ' ': '%20',   '\'': '%22',   '"': '%27',   '#': '%23',   '/': '%2F',   ':': '%3A',   '(': '%28',   ')': '%29',   '%': '%25',   '<': '%3C',   '>': '%3E',   '\': '%5C',   '^': '%5E',   '{': '%7B',   '|': '%7C',   '}': '%7D', );

3. Encode function

/** * You can call this function by using `svg(nameOfTheSVG)` */ @function svg($  name) {   // Check if icon exists   @if not map-has-key($  svg-icons, $  name) {     @error 'icon “#{$  name}” does not exists in $  svg-icons map';     @return false;   }    // Get icon data   $  icon-map: map-get($  svg-icons, $  name);    $  escaped-string: '';   $  unquote-icon: unquote($  icon-map);   // Loop through each character in string   @for $  i from 1 through str-length($  unquote-icon) {     $  char: str-slice($  unquote-icon, $  i, $  i);      // Check if character is in symbol map     $  char-lookup: map-get($  fs-escape-chars, $  char);      // If it is, use escaped version     @if $  char-lookup != null {         $  char: $  char-lookup;     }      // Append character to escaped string     $  escaped-string: $  escaped-string + $  char;   }    // Return inline SVG data   @return url('data:image/svg+xml, #{$  escaped-string} '); }		

4. Add an SVG in your page

button {   &::after {     /* Import inline SVG */     content: svg(burger);   } }

If you have followed those steps, Sass should compile your code properly and output the following:

button::after {   content: url("data:image/svg+xml, %3Csvg%20xmlns=%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox=%270%200%2024.8%2018.92%27%20width=%2724.8%27%20height=%2718.92%27%3E%3Cpath%20d=%27M23.8,9.46H1m22.8,8.46H1M23.8,1H1%27%20fill=%27none%27%20stroke=%27%23000%27%20stroke-linecap=%27round%27%20stroke-width=%272%27%2F%3E%3C%2Fsvg%3E "); }		

Custom properties

The now-implemented Sass svg() function works great. But its biggest flaw is that an icon that is needed in multiple places in your code will be duplicated and could increase your compiled CSS file weight by a lot!

To avoid this, we can store all our icons into CSS variables and use a reference to the variable instead of outputting the encoded URI every time.

We will keep the same code we had before, but this time we will first output all the icons from the Sass list into the root of our webpage:

/**   * Convert all icons into custom properties   * They will be available to any HTML tag since they are attached to the :root   */  :root {   @each $  name, $  code in $  svg-icons {     --svg-#{$  name}: #{svg($  name)};   } }

Now, instead of calling the svg() function every time we need an icon, we have to use the variable that was created with the --svg prefix.

button::after {   /* Import inline SVG */   content: var(--svg-burger); }

Optimizing your SVGs

This technique does not provide any optimization on the source code of the SVG you are using. Make sure that you don’t leave unnecessary code; otherwise they will be encoded as well and will increase your CSS file size.

You can check this great list of tools and information on how to optimize properly your SVG. My favorite tool is Jake Archibald’s SVGOMG — simply drag your file in there and copy the outputted code.

Bonus: Updating the icon on hover

With this technique, we cannot select with CSS specific parts of the SVG. For example, there is no way to change the fill color of the icon when the user hovers the button. But there are a few tricks we can use with CSS to still be able to modify the look of our icon.

For example, if you have a black icon and you want to have it white on hover, you can use the invert() CSS filter. We can also play with the hue-rotate() filter.

That’s it!

I hope you find this little helper function handy in your own projects. Let me know what you think of the approach — I’d be interested to know how you’d make this better or tackle it differently!


How I Made an Icon System Out of CSS Custom Properties originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

CSS-Tricks

, , , ,
[Top]

How I Made a Pure CSS Puzzle Game

I recently discovered the joy of creating CSS-only games. It’s always fascinating how HTML and CSS are capable of handling the logic of an entire online game, so I had to try it! Such games usually rely on the ol’ Checkbox Hack where we combine the checked/unchecked state of a HTML input with the :checked pseudo-class in CSS. We can do a lot of magic with that one combination!

In fact, I challenged myself to build an entire game without Checkbox. I wasn’t sure if it would be possible, but it definitely is, and I’m going to show you how.

In addition to the puzzle game we will study in this article, I have made a collection of pure CSS games, most of them without the Checkbox Hack. (They are also available on CodePen.)

Want to play before we start?

I personally prefer playing the game in full screen mode, but you can play it below or open it up over here.

Cool right? I know, it’s not the Best Puzzle Game You Ever Saw™ but it’s also not bad at all for something that only uses CSS and a few lines of HTML. You can easily adjust the size of the grid, change the number of cells to control the difficulty level, and use whatever image you want!

We’re going to remake that demo together, then put a little extra sparkle in it at the end for some kicks.

The drag and drop functionality

While the structure of the puzzle is fairly straightforward with CSS Grid, the ability to drag and drop puzzle pieces is a bit trickier. I had to relying on a combination of transitions, hover effects, and sibling selectors to get it done.

If you hover over the empty box in that demo, the image moves inside of it and stays there even if you move the cursor out of the box. The trick is to add a big transition duration and delay — so big that the image takes lots of time to return to its initial position.

img {   transform: translate(200%);   transition: 999s 999s; /* very slow move on mouseout */ } .box:hover img {   transform: translate(0);   transition: 0s; /* instant move on hover */ }

Specifying only the transition-delay is enough, but using big values on both the delay and the duration decreases the chance that a player ever sees the image move back. If you wait for 999s + 999s — which is approximately 30 minutes — then you will see the image move. But you won’t, right? I mean, no one’s going to take that long between turns unless they walk away from the game. So, I consider this a good trick for switching between two states.

Did you notice that hovering the image also triggers the changes? That’s because the image is part of the box element, which is not good for us. We can fix this by adding pointer-events: none to the image but we won’t be able to drag it later.

That means we have to introduce another element inside the .box:

That extra div (we’re using a class of .a) will take the same area as the image (thanks to CSS Grid and grid-area: 1 / 1) and will be the element that triggers the hover effect. And that is where the sibling selector comes into play:

.a {   grid-area: 1 / 1; } img {   grid-area: 1 / 1;   transform: translate(200%);   transition: 999s 999s; } .a:hover + img {   transform: translate(0);   transition: 0s; }

Hovering on the .a element moves the image, and since it is taking up all space inside the box, it’s like we are hovering over the box instead! Hovering the image is no longer a problem!

Let’s drag and drop our image inside the box and see the result:

Did you see that? You first grab the image and move it to the box, nothing fancy. But once you release the image you trigger the hover effect that moves the image, and then we simulate a drag and drop feature. If you release the mouse outside the box, nothing happens.

Hmm, your simulation isn’t perfect because we can also hover the box and get the same effect.

True and we will rectify this. We need to disable the hover effect and allow it only if we release the image inside the box. We will play with the dimension of our .a element to make that happen.

Now, hovering the box does nothing. But if you start dragging the image, the .a element appears, and once released inside the box, we can trigger the hover effect and move the image.

Let’s dissect the code:

.a {   width: 0%;   transition: 0s .2s; /* add a small delay to make sure we catch the hover effect */ } .box:active .a { /* on :active increase the width */   width: 100%;   transition: 0s; /* instant change */ } img {   transform: translate(200%);   transition: 999s 999s; } .a:hover + img {   transform: translate(0);   transition: 0s; }

Clicking on the image fires the :active pseudo-class that makes the .a element full-width (it is initially equal to 0). The active state will remain active until we release the image. If we release the image inside the box, the .a element goes back to width: 0, but we will trigger the hover effect before it happens and the image will fall inside the box! If you release it outside the box, nothing happens.

There is a little quirk: clicking the empty box also moves the image and breaks our feature. Currently, :active is linked to the .box element, so clicking on it or any of its children will activate it; and by doing this, we end up showing the .a element and triggering the hover effect.

We can fix that by playing with pointer-events. It allows us to disable any interaction with the .box while maintaining the interactions with the child elements.

.box {   pointer-events: none; } .box * {   pointer-events: initial; }

Now our drag and drop feature is perfect. Unless you can find how to hack it, the only way to move the image is to drag it and drop it inside the box.

Building the puzzle grid

Putting the puzzle together is going to feel easy peasy compared to what we just did for the drag and drop feature. We are going to rely on CSS grid and background tricks to create the puzzle.

Here’s our grid, written in Pug for convenience:

- let n = 4; /* number of columns/rows */ - let image = "https://picsum.photos/id/1015/800/800";  g(style=`--i:url($ {image})`)   - for(let i = 0; i < n*n; i++)     z       a       b(draggable="true") 

The code may look strange but it compiles into plain HTML:

<g style="--i: url(https://picsum.photos/id/1015/800/800)">  <z>    <a></a>    <b draggable="true"></b>  </z>  <z>    <a></a>    <b draggable="true"></b>  </z>  <z>    <a></a>    <b draggable="true"></b>  </z>   <!-- etc. --> </g>

I bet you’re wondering what’s up with those tags. None of these elements have any special meaning — I just find that the code is much easier to write using <z> than a bunch of <div class="z"> or whatever.

This is how I’ve mapped them out:

  • <g> is our grid container that contains N*N <z> elements.
  • <z> represents our grid items. It plays the role of the .box element we saw in the previous section.
  • <a> triggers the hover effect.
  • <b> represents a portion of our image. We apply the draggable attribute on it because it cannot be dragged by default.

Alright, let’s register our grid container on <g>. This is in Sass instead of CSS:

$ n : 4; /* number of columns/rows */  g {   --s: 300px; /* size of the puzzle */    display: grid;   max-width: var(--s);   border: 1px solid;   margin: auto;   grid-template-columns: repeat($ n, 1fr); }

We’re actually going to make our grid children — the <z> elements — grids as well and have both <a> and <b> within the same grid area:

z {   aspect-ratio: 1;   display: grid;   outline: 1px dashed; } a {   grid-area: 1/1; } b {   grid-area: 1/1; }

As you can see, nothing fancy — we created a grid with a specific size. The rest of the CSS we need is for the drag and drop feature, which requires us to randomly place the pieces around the board. I’m going to turn to Sass for this, again for the convenience of being able to loop through and style all the puzzle pieces with a function:

b {   background: var(--i) 0/var(--s) var(--s); }  @for $ i from 1 to ($ n * $ n + 1) {   $ r: (random(180));   $ x: (($ i - 1)%$ n);   $ y: floor(($ i - 0.001) / $ n);   z:nth-of-type(#{$ i}) b{     background-position: ($ x / ($ n - 1)) * 100% ($ y / ($ n - 1)) * 100%;     transform:        translate((($ n - 1) / 2 - $ x) * 100%, (($ n - 1)/2 - $ y) * 100%)        rotate($ r * 1deg)        translate((random(100)*1% + ($ n - 1) * 100%))        rotate((random(20) - 10 - $ r) * 1deg)    } }

You may have noticed that I’m using the Sass random() function. That’s how we get the randomized positions for the puzzle pieces. Remember that we will disable that position when hovering over the <a> element after dragging and dropping its corresponding <b> element inside the grid cell.

z a:hover ~ b {   transform: translate(0);   transition: 0s; }

In that same loop, I am also defining the background configuration for each piece of the puzzle. All of them will logically share the same image as the background, and its size should be equal to the size of the whole grid (defined with the --s variable). Using the same background-image and some math, we update the background-position to show only a piece of the image.

That’s it! Our CSS-only puzzle game is technically done!

But we can always do better, right? I showed you how to make a grid of puzzle piece shapes in another article. Let’s take that same idea and apply it here, shall we?

Puzzle piece shapes

Here’s our new puzzle game. Same functionality but with more realistic shapes!

This is an illustration of the shapes on the grid:

If you look closely you’ll notice that we have nine different puzzle-piece shapes: the four corners, the four edges, and one for everything else.

The grid of puzzle pieces I made in the other article I referred to is a little more straightforward:

We can use the same technique that combines CSS masks and gradients to create the different shapes. In case you are unfamiliar with mask and gradients, I highly recommend checking that simplified case to better understand the technique before moving to the next part.

First, we need to use specific selectors to target each group of elements that shares the same shape. We have nine groups, so we will use eight selectors, plus a default selector that selects all of them.

z  /* 0 */  z:first-child  /* 1 */  z:nth-child(-n + 4):not(:first-child) /* 2 */  z:nth-child(5) /* 3 */  z:nth-child(5n + 1):not(:first-child):not(:nth-last-child(5)) /* 4 */  z:nth-last-child(5)  /* 5 */  z:nth-child(5n):not(:nth-child(5)):not(:last-child) /* 6 */  z:last-child /* 7 */  z:nth-last-child(-n + 4):not(:last-child) /* 8 */

Here is a figure that shows how that maps to our grid:

Now let’s tackle the shapes. Let’s focus on learning just one or two of the shapes because they all use the same technique — and that way, you have some homework to keep learning!

For the puzzle pieces in the center of the grid, 0:

mask:    radial-gradient(var(--r) at calc(50% - var(--r) / 2) 0, #0000 98%, #000) var(--r)       0 / 100% var(--r) no-repeat,   radial-gradient(var(--r) at calc(100% - var(--r)) calc(50% - var(--r) / 2), #0000 98%, #000)      var(--r) 50% / 100% calc(100% - 2 * var(--r)) no-repeat,   radial-gradient(var(--r) at var(--r) calc(50% - var(--r) / 2), #000 98%, #0000),   radial-gradient(var(--r) at calc(50% + var(--r) / 2) calc(100% - var(--r)), #000 98%, #0000);

The code may look complex, but let’s focus on one gradient at a time to see what’s happening:

Two gradients create two circles (marked green and purple in the demo), and two other gradients create the the slots that other pieces connect to (the one marked blue fills up most of the shape while the one marked red fills the top portion). A CSS variable, --r, sets the radius of the circular shapes.

The shape of the puzzle pieces in the center (marked 0 in the illustration) is the hardest to make as it uses four gradients and has four curvatures. All the others pieces juggle fewer gradients.

For example, the puzzle pieces along the top edge of the puzzle (marked 2 in the illustration) uses three gradients instead of four:

mask:    radial-gradient(var(--r) at calc(100% - var(--r)) calc(50% + var(--r) / 2), #0000 98%, #000) var(--r) calc(-1 * var(--r)) no-repeat,   radial-gradient(var(--r) at var(--r) calc(50% - var(--r) / 2), #000 98%, #0000),   radial-gradient(var(--r) at calc(50% + var(--r) / 2) calc(100% - var(--r)), #000 98%, #0000);

We removed the first (top) gradient and adjusted the values of the second gradient so that it covers the space left behind. You won’t notice a big difference in the code if you compare the two examples. It should be noted that we can find different background configurations to create the same shape. If you start playing with gradients you will for sure come up with something different than what I did. You may even write something that’s more concise — if so, share it in the comments!

In addition to creating the shapes, you will also find that I am increasing the width and/or the height of the elements like below:

height: calc(100% + var(--r)); width: calc(100% + var(--r));

The pieces of the puzzle need to overflow their grid cell to connect.

Final demo

Here is the full demo again. If you compare it with the first version you will see the same code structure to create the grid and the drag-and-drop feature, plus the code to create the shapes.

Possible enhancements

The article ends here but we could keep enhancing our puzzle with even more features! How about a a timer? Or maybe some sort of congratulations when the player finishes the puzzle?

I may consider all these features in a future version, so keep an eye on my GitHub repo.

Wrapping up

And CSS ism’t a programming language, they say. Ha!

I’m not trying to spark some #HotDrama by that. I say it because we did some really tricky logic stuff and covered a lot of CSS properties and techniques along the way. We played with CSS Grid, transitions, masking, gradients, selectors, and background properties. Not to mention the few Sass tricks we used to make our code easy to adjust.

The goal was not to build the game, but to explore CSS and discover new properties and tricks that you can use in other projects. Creating an online game in CSS is a challenge that pushes you to explore CSS features in great detail and learn how to use them. Plus, it’s just a lot of fun that we get something to play with when all is said and done.

Whether CSS is a programming language or not, doesn’t change the fact that we always learn by building and creating innovative stuff.


How I Made a Pure CSS Puzzle Game originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

CSS-Tricks

, , ,
[Top]

Embedded Analytics Made Simple With Cumul.io Integrations

Browse through SaaS communities on Twitter, LinkedIn, Reddit, Discord, you name it and you’ll see a common theme appear in many of them. That theme can go by many names: BI, analytics, insights and so on. It’s natural, we do business, collect data, we succeed or fail. We want to look into all of that, make some sense of the data we have and take action. This need has produced many projects and tools that make the lives of anyone who wants to look into the data just a bit easier. But, when humans have, humans want more. And in the world of BI and analytics, “more” often comes in the form of embedding, branding, customized styling and access and so on. Which ends up meaning more work for developers and more time to account for. So, naturally there has been a need for BI tools that will let you have it all.

Let’s make a list of challenges you may face as the builder and maintainer of these dashboards:

  1. You want to make the dashboards available to end users or viewers from within your own application or platform
  2. You want to be able to manage different dashboard collections (i.e. “integrations”)
  3. You want to be able to grant specific user rights to a collection of dashboards and datasets
  4. You want to make sure users have access to data only relevant to them

Cumul.io provides a tool we call Integrations which helps solve these challenges. In this article I’ll walk you through what integrations are, and how to set one up. The cool thing is that for most of the points above, there is minimal code required and for the most part can be set within the Cumul.io UI.

Some Background — Integrations

An Integration in Cumul.io is a structure that defines a collection of dashboards intended to be used together (e.g. in the same application). It is also what we use to embed dashboards into an application. In other words, to embed dashboards into an application, we give the application access to the integration that they belong to. You can associate dashboards to an integration and administrate what type of access rights the end users of the integration will have on these dashboards and the datasets they use. A dashboard may be a part of multiple integrations, but it may have different access rights on different integrations. When it comes to embedding, there are a number of SDKs available to make life simple regardless of what your stack looks like. 😊

Once you have a Cumul.io account and if you are an “owner” of an organization in Cumul.io, you will be able to manage and maintain all of your integrations via the Integrations tab. Let’s have a look at an example Cumul.io account. Below you can see the Dashboards that one Cumul.io user might have created:

Although these are all the dashboards this user may have created, it’s likely that not all dashboards are intended for the same end-users, or application for that matter. So, the owner of this Cumul.io account would create and maintain an Integration (or more!) 💪 Let’s have a look at what that might look like for them:

So, it looks like the owner of this Cumul.io account maintains two separate applications.

Now let’s see what the process of creating an integration and embedding its dashboards into an application would look like. The good news is, as mentioned before, a lot of the steps you will have to take can be done within the Cumul.io UI.

Disclaimer: For the purposes of this article, I’ll solely focus on the Integration part. So, I’ll be skipping everything to do with dashboard creation and design and we will be starting with a pre-made set of imaginary dashboards.

What we will be doing:

Creating an Integration

For simplicity, let’s only create one integration for now. Let’s imagine we have an analytics platform that we maintain for our company. There are three dashboards that we want to provide to our end-users: the Marketing Dashboard, the Sales Dashboard and the Leads Dashboard.

Let’s say that out of all the dashboards this account has created or has access to, for this particular project they want to use only the following:

New Integration

To create the integration, we go to the Integrations tab and select New Integration. The dialogue that pops up will already give you some idea of what your next steps will be:

Selecting Dashboards

Next up, you will be able to select which of your dashboards will be included in this integration. You will also be able to give the Integration a name, which here I’ve decided will appropriately be “Very Important Integration”:

Once you confirm your selection, you will have the option of defining a slug for each dashboard (highly recommended). These can later be used while embedding the dashboards into your application. You will later see that slugs make it easy to reference dashboards in your front-end code, and make it easier to replace dashboards if needed too (as you won’t need to worry about dashboard IDs in the front-end code).

Access Rights

You will then get to set the integration’s access rights for the datasets its dashboards use. Here we set this to “Can view.” For more info on access rights and what they entail, check out our associating datasets to integrations:

Filters and Parameters (and Multi-Tenant Access)

Side Note: To help with multi-tenant access — which would make sense in this imaginary set up — Cumul.io makes it possible to set parameters and filters on datasets that a dashboard uses. This means that each user that logs into your analytics platform would only see the data they personally have access to in the dashboards. You can imagine that in this scenario access would be based on which department the end user works for in the company. For more on how to set up multi-tenancy with Cumul.io, check out our article, “Multi-Tenancy on Cumul.io Dashboards with Auth0”. This can be done within the dashboard design process (which we are skipping), which makes it easier to visualize what the filters are doing. But here, we will be setting these filters in the Integration creation process.

Here, we set the filters the datasets might need to have. In this scenario, as we filter based on the users’ departments, we define a department parameter and filter based on that:

And voilà! Once you’re done with setting those, you have successfully created an integration. The next dialogue will give you instructions for what will be your next steps for embedding your integration:

Now you’ll be able to see this brand new Integration in your Integration tab. This is also where you will have quick access to the Integration ID, which will later be used for embedding the dashboards.

Good news! After your Integration is created, you can always edit it. You can remove or add dashboards, change the slugs of dashboards or access rights too. So you don’t have to worry about creating new integrations as your application changes and evolves. And as editing an integration is all within the UI, you won’t need to worry about having a developer set it all up again. Non-technical users can adapt these integrations on the go.

Embedding Dashboards

Let’s see where we want to get to. We want to provide the dashboards within a custom app. Simple, user logs into an app, the app has dashboards, they see the dashboards with the data they’re allowed to see. It could look like the following for example:

Someone had a very specific vision on how they wanted to provide the dashboards to the end user. They wanted a sidebar where they could flip through each of the dashboards. It could have been something completely different too. What we will focus on is how we can embed these dashboards into our application regardless of what the host application looks like.

Cumul.io comes with a set of publicly available SDKs. Here I’ll show you what you would do if you were to use the Node SDK. Check out our developer docs to see what other SDKs are available and instructions on how to use them.

Step 1: Generate SSO Tokens For Your End Users

Before you can generate SSO tokens for your end users, you will have to make sure that you create an API key and token in Cumul.io. You can do this from your Cumul.io Profile. It should be the organization owner with access to the integration that creates and uses this API key and token to make the SSO authorization request. Once you’ve done this, let’s first create a Cumul.io client which would be done in the server side of the application:

const Cumulio = require("cumulio");  const client = new Cumulio({   api_key: '<YOUR API KEY>',   api_token: '<YOUR API TOKEN>', });

Now we can create the SSO token for the end user. For more information on this API call and the required fields check out our developer documentation on generating SSO tokens.

let promise = client.create('authorization', {   integration_id: '<THE INTEGRATION ID>',   type: 'sso',   expiry: '24 hours',   inactivity_interval: '10 minutes',   username: '< A unique identifier for your end user >',   name: '< end-user name >',   email: '< end-user email >',   suborganization: '< end-user suborganization >',   role: 'viewer',   metadata: {} });

Here, notice how we have added the optional metadata field. This is where you can provide the parameters and values with which you want to filter the dashboards’ datasets on. In the example we’ve been going through we’ve been filtering based on department so we would be adding this to the metadata. Ideally you would get this information from the authentication provider you use. See a detailed explanation on how we’ve done this with Auth0.

This request will return a JSON object that contains an authorization id and token which is later used as the key/token combination to embed dashboards in the client-side.

Something else you can optionally add here which is pretty cool is a CSS property. This would allow you to define custom look and feel for each user (or user group). For the same application, this is what the Marketing Dashboard could look like for Angelina vs Brad:

Step 2: Embed

We jumped ahead a bit there. We created SSO tokens for end users but we haven’t yet actually embedded the dashboards into the application. Let’s have a look at that. First up, you should install and import the Web component.

import '@cumul.io/cumulio-dashboard';

After importing the component you can use it as if it were an HTML tag. This is where you will embed your dashboards:

<cumulio-dashboard   dashboardId="< a dashboard id >"   dashboardSlug="< a dashboard slug >"   authKey="< SSO key from step 1 >"   authToken="< SSO token from step 1 >"> </cumulio-dashboard>

Here you will have a few options. You can either provide the dashboard Id for any dashboard you want to be embedding, or you can provide the dashboard slug which we defined in the Integration setup (which is why I highly recommend this, it’s much more readable doing it this way). For more detailed information on how to embed dashboards you can also check out our developer documentation.

A nice way to do this step is of course just defining the skeleton of the dashboard component in your HTML file and filling in the rest of it from the client side of your application. I’ve done the following, although it’s of course not the only way:

I’ve added the dashboard component with the ID dashboard:

<cumulio-dashboard id="dashboard"></cumulio-dashboard>

Then, I’ve retrieved this component in the client code as follows:

const dashboardElement = document.getElementById("dashboard");

Then I request the SSO token from the server side of my application which returns the required key and token to add to the dashboard component. Let’s assume we have a wrapper function getDashboardAuthorizationToken() that does this for us and returns the response from the server-side SSO token request. Next, we simply fill in the dashboard component accordingly:

const authorizationToken = await getDashboardAuthorizationToken(); if (authorizationToken.id && authorizationToken.token) {   dashboardElement.authToken = authorizationToken.token;   dashboardElement.authKey = authorizationToken.id;   dashboardElement.dashboardSlug = "marketing|sales|leads"; }

Notice how in the previous steps I chose to define slugs for my dashboards that are a part of this integration. This means I can avoid looking up dashboard IDs and adding dashboardId as one of my parameters of the dashboardElement. Instead I can just provide one of the slugs marketing, sales or leads and I’m done! Of course you would have to set up some sort of selection process to your application to decide where and when you embed which dashboard.

That’s it folks! We’ve successfully created an Integration in Cumul.io and in a few lines of code, we’ve been able to embed its dashboards into our application 🎉 Now imagine a scenario where you have to maintain multiple applications at once, either for within the same company or separate ones. Whatever your scenario, I’m sure you can imagine how if you have a number of dashboards where each of them have to go to different places and each of them have to have different access rights depending on where they are and on and on we go.. How it can quickly get out of hand. Integrations allow you to manage this in a simple and neat way, all in one place, and as you can see, mostly from within the Cumul.io UI.

There’s a lot more you can do here which we haven’t gone through in detail. Such as adding user specific custom themes and CSS. We also didn’t go through how you would set parameters and filters in dashboards, or how you would use them from within your host application so that you have a multi-tenant setup. Below you can find some links to useful tutorials and documentation for these steps if you are interested.


The post Embedded Analytics Made Simple With Cumul.io Integrations appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

How I Made a Generator for SVG Loaders With Sass and SMIL Options

While learning Vue.js, I started building free web tools that involved the exploration of SVG, with the goal of learning something about both! Let’s take a look at one of those tools: a generator that makes SVG loaders and lets you choose between SMIL or Sass animation, different styles, colors, shapes, and effects. It even lets you paste in a custom path or text, and then download the final SVG, copy the code, or open a demo over at CodePen.

How it started

Three coincidences led me to build a generator for SVG loaders.

Coincidence 1: Sarah Drasner’s book

The first time I read about Sass loops was in Sarah Drasner’s SVG Animations. She shows how to stagger animations with a Sass function (like the does in Chapter 6, “Animating Data Visualizations”).

I was inspired by that chapter and the possibilities of Sass loops.

Coincidence 2: A GIF

At that same point in life, I was asked to replicate a “loader” element, similar to Apple’s old classic.

A round segmented spinner where each segment fades in and out in succession to create a circling effect.
This is a mockup of the loader I was asked to make.

I referenced Sarah’s example to make it happen. This is the Sass loop code I landed on:

@for $ i from 1 to 12 {   .loader:nth-of-type(#{$ i}) {     animation: 1s $ i * 0.08s opacityLoader infinite;   } } @keyframes opacityLoader {  to { opacity: 0; } }

This defines a variable for a number (i) from 1 to 12 that increases the delay of the animation with every :nth-child element. It was the perfect use case to animate as many elements as I wanted with only two lines of Sass, saving me CSS declarations for each of the delays I needed. This is the same animation, but written in vanilla CSS to show the difference:

.loader:nth-of-type(1) {   animation: 1s 0.08s opacityLoader infinite; } .loader:nth-of-type(2) {   animation: 1s 0.16s opacityLoader infinite; }  /* ... */  .loader:nth-of-type(12) {   animation: 1s 0.96s opacityLoader infinite; } @keyframes opacityLoader {   to { opacity: 0; } }

Coincidence 3: An idea

With these things going on in my head, I had an idea for a gallery of loaders, where each loader is made from the same Sass loop. I always struggle to find these kinds of things online, so I thought it might be useful for others, not to mention myself.

I had already built this kind of thing before as a personal project, so I ended up building a loader generator. Let me know if you find bugs in it!

One loader, two outputs

I was blocked by my own developer skills while creating a generator that produces the right Sass output. I decided to try another animation approach with SMIL animations, and that’s what I wound up deciding to use.

But then I received some help (thanks, ekrof!) and got Sass to work after all.

So, I ended up adding both options to the generator. I found it was a challenge to make both languages return the same result. In fact, they sometimes produce different results.

SMIL vs. CSS/Sass

I learned quite a bit about SMIL and CSS/Sass animations along the way. These are a few of the key takeaways that helped me on my way to making the generator:

  • SMIL doesn’t rely on any external resources. It animates SVG via presentation attributes directly in the SVG markup. That’s something that neither CSS nor Sass can do.
  • SMIL animations are preserved when an SVG is embedded as an image or as a background image. It is possible to add a CSS <style> block directly inside the SVG, but not so much with Sass, of course. That’s why there is an option to download the actual SVG file when selecting the SMIL option in the generator.
  • SMIL animations look a bit more fluid. I couldn’t find the reason for this (if anyone has any deeper information here, please share!). I though it was related to GPU acceleration, but it seems they both use the same animation engine.
Two spinners, one left and one right. They are both red and consist of circles that fade in and out in succession as an animated GIF.
SMIL (left) and Sass (right)

You might notice a difference in the chaining of the animations between both languages:

  • I used additive="sum" in SMIL to add animations one after the other. This makes sure each new animation effect avoids overriding the previous animation.
  • That said, in CSS/Sass, the W3C points out that [when] multiple animations are attempting to modify the same property, then the animation closest to the end of the list of names wins.

That’s why the order in which animations are applied might change the Sass output.

Working with transforms

Working with transformations in the loader’s styling was a big issue. I had applied transform: rotate inline to each shape because it’s a simple way to place them next to each other in a circle and with a face pointing toward the center.

<svg>   <!-- etc. -->   <use class="loader" xlink:href="#loader" transform="rotate(0 50 50)" />   <use class="loader" xlink:href="#loader" transform="rotate(30 50 50)" />   <use class="loader" xlink:href="#loader" transform="rotate(60 50 50)" />   <!-- etc. --> </svg>

I could declare a type in SMIL with <animateTransform> (e.g. scale or translate) to add that specific transform to the original transformation of each shape:

<animateTransform   attributeName="transform"   type="translate"   additive="sum"   dur="1s"   :begin="`$ {i * 0.08}s`"   repeatCount="indefinite"   from="0 0"   to="10" />

But instead, transform in CSS was overriding any previous transform applied to the inline SVG. In other words, the original position reset to 0 and showed a very different result from what SMIL produced. That meant the animations wound up looking identical no matter what.

The same two red spinners as before but with different results. The SMIL version on the left seems to work as expected but the Sass one on the right doesn't animate in a circle like it should.

The (not very pretty) solution to make the Sass similar to SMIL was to place each shape inside a group (<g>) element, and apply the inline rotation to the groups, and the animation to the shapes. This way, the inline transform isn’t affected by the animation.

<svg>   <!-- etc. -->   <g class="loader" transform="rotate(0 50 50)">     <use xlink:href="#loader" />   </g>   <g class="loader" transform="rotate(30 50 50)">     <use xlink:href="#loader" />   </g>   <!-- etc. --> </svg>

Now both languages have a very similar result.

The technology I used

I used Vue.js and Nuxt.js. Both have great documentation, but there are more specific reasons why I choose them.

I like Vue for lots of reasons:

  • Vue encapsulates HTML, CSS, and JavaScript as a “single file component” where all the code lives in a single file that’s easier to work with.
  • The way Vue binds and dynamically updates HTML or SVG attributes is very intuitive.
  • HTML and SVG don’t require any extra transformations (like making the code JSX-compatible).

As far as Nuxt goes:

  • It has a quick boilerplate that helps you focus on development instead of configuration.
  • There’s automatic routing and it supports auto-importing components.
  • It’s a good project structure with pages, components, and layouts.
  • It’s easier to optimize for SEO, thanks to meta tags.

Let’s look at a few example loaders

What I like about the end result is that the generator isn’t a one-trick pony. There’s no one way to use it. Because it outputs both SMIL and CSS/Sass, there are several ways to integrate a loader into your own project.

Download the SMIL SVG and use it as a background image in CSS

Like I mentioned earlier, SMIL features are preserved when an SVG is used as a background image file. So, simply download the SVG from the generator, upload it to your server, and reference it in CSS as a background image.

Similarly, we could use the SVG as a background image of a pseudo-element:

Drop the SVG right into the HTML markup

The SVG doesn’t have to be a background image. It’s just code, after all. That means we can simply drop the code from the generator into our own markup and let SMIL do its thing.

Use a Sass loop on the inline SVG

This is what I was originally inspired to do, but ran into some roadblocks. Instead of writing CSS declarations for each animation, we can use the Sass loop produced by the generator. The loop targets a .loader class that’s already applied to the outputted SVG. So, once Sass is compiled to CSS, we get a nice spinning animation.

I’m still working on this

My favorite part of the generator is the custom shape option where you can add text, emojis, or any SVG element to the mix:

The same circle spinner but using custom SVG shapes: one a word, one a poop emoji, and bright pink and orange asterisk.
Custom text, emoji, and SVG

What I would like to do is add a third option for styles to have just one element where you get to work with your own SVG element. That way, there’s less to work with, while allowing for simpler outputs.

The challenge with this project is working with custom values for so many things, like duration, direction, distance, and degrees. Another challenge for me personally is becoming more familiar with Vue because I want to go back and clean up that messy code. That said, the project is open source, and pull requests are welcome! Feel free to send suggestions, feedback, or even Vue course recommendations, especially ones related to SVG or making generators.

This all started with a Sass loop that I read in a book. It isn’t the cleanest code in the world, but I’m left blown away by the power of SMIL animations. I highly recommend Sarah Soueidan’s guide for a deeper dive into what SMIL is capable of doing.

If you’re curious about the safety of SMIL, that is for good reason. There was a time when Chrome was going to entirely deprecated SMIL (see the opening note in MDN). But that deprecation has been suspended and hasn’t (seemingly) been talked about in a while.

Can I use SMIL?

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Firefox IE Edge Safari
5 4 No 79 6

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
92 90 3 6.0-6.1

The post How I Made a Generator for SVG Loaders With Sass and SMIL Options appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

Mistakes I’ve Made as an Engineering Manager

I’ve been a manager for many years at companies of different scale. Through these experiences, I’ve done my share of learning, and made some mistakes along that way that were important lessons for me. I want to share those with you.

But before diving in, I want to mention a strong caveat that my advice may be unique to my situation because I’m white and a woman in tech. My experiences may be relevant to that point of view, but your mileage may vary.

Another huge caveat: I’m sharing mistakes I’ve made so far in the interest of helping others, but I’m sure I’m not done making mistakes, either. I don’t have it all figured it out, I’m still on this journey.

Credit: WoCinTechChat

Mistake 1: Thinking people give feedback the way they want to receive it

Feedback is one of the most important tools you have as a manager, but it can also be incredibly disruptive with poor execution. One of the hardest things I’ve had to learn is that humans aren’t pure functions: you can put a form input in front of them one day and get one result, then again another day and get an entirely different result.

The same is true of how people give and receive feedback: someone may give you feedback in a particular way, but they prefer to receive much differently when it comes to themselves.

How do you get around this? Asking helps. I’ve started doing an exercise with my team where I ask the group as a whole how they would like to get feedback. Not only does it open up ideas, but it also helps that each individual has to think for themselves how they prefer to receive feedback. Normalizing this type of vulnerability and self-reflection can help us all feel like partners, instead of some top-down edict.

Another thing that’s helped? Asking folks directly in a one-on-one meeting if they have feedback for me as a manager, and following up with an anonymous survey. Again, it makes things feel less one-sided and provides everyone the opportunity to say things that they might not want to say directly to my face, which I know can be tough.

And lastly, if something comes up, addressing it immediately can be helpful. There’s nothing worse than your manager having an issue with something you did and only finding out about it three months later, especially if it’s tied to a performance review that you could have impacted had they been transparent earlier.

The truth is that even my advice here is imperfect. Feedback is tough. Being honest and improving together as a team is awkward. It’s incredibly worth it, though. That’s where the real growth is. That said, no two people are alike, no two groups are alike, and you may have to use your best judgement given the situation at hand.

Mistake 2: Trying to do everything yourself as a manager is the best way to help

Years ago, I managed a woman who was bright, talented, capable, and an all around pleasure. She was sort of new to the industry and could come across as timid, so I did my best to be a poop umbrella for her, fighting battles behind the scenes to set her up for success. She was on a steady track to land a senior role. Even after I decided to leave the company, I let the next manager know this person is track for a senior position in the next few months.

Then I moved to another city. Years later, I met up with the woman and was shocked to learn she never got the position.

Here’s what I learned: her promotion wasn’t the same high priority for the capable hands I left her in as it was for me. The team was challenged with a million other things that took center stage to the extent that her promotion fell off the radar. But even more than that, what became very clear to me was that all of that “protection” I thought I had set up for her didn’t really serve her well for the long haul. For example, I didn’t teach her how to advocate for herself or how to navigate the system. I vowed never to make that mistake again.

This is tough! If you’re strong and care about your team as people, it can feel very unnatural to teach someone to advocate instead of moving things out of their way themselves. And the point is not to throw that person into the fire. The point is to care. Are you teaching the things they need to learn? Are they really growing under you? Feeling like you’re protecting someone at all costs also lead to your own ego trip, too, which threatens progress.

Try to think through what skills someone needs to succeed without you. Teach those things incrementally. Sure, this is easy advice to say, but it’s really hard to do in the thick of things. Spend some time with it, and think through ways you can inject that learning into everyday work and interactions.

Credit: Charles Deluvio on Unsplash

Mistake 3: Communicating something one time is enough

No one likes to feel like they’re repeating themselves. It’s annoying to say someone more than once, and it’s annoying to hear something over and again. But if you have a big enough group and there’s enough going on, things are going to slip through the cracks, so repetition becomes an important tool to make things stick. The trick is to say the same things, but in different ways.

There was a time last year when I asked my team to do something and none of them did it. What happened there? Given that it’s a team of highly efficient, strong collaborators, do you think they just all table-flipped and didn’t take action? Not a chance. I was the one who wasn’t clear. In fact, you can probably guess that if a whole group of people don’t understand or take action, the chance is that you, the manager are the common denominator for why something is blocked. Not only did I not repeat myself enough to be clear, I didn’t align anyone with the why of the purpose of the task. It’s pretty easy to forget or not prioritize doing something if you have no clue why you’re doing it. Repeat yourself and align the group with the importance of the task and you’ll likely have a better result.

Think of all the ways we have to communicate these days: chats, emails, video meetings, texts, document comments, and so much more. And because some people communicate better in one medium than another, using all of the platforms have in various mediums becomes a strategy for repetition without nagging.

I’ve found that what work best is allowing everyone to own the information themselves. For example, if your team practices career laddering, each person they read the ladders aloud in a one-on-one and then talk you through their responses to each item. That way, you’re not lecturing — they are owning where they are and what the next steps are as you guide them along.

Mistake 4: You have to have everything together all the time

Some folks think that management looks like a steel fortress of preparedness and authority. I’m not so sure about that.

If something goes wrong, are you more likely to tell the manager acts as though they have everything together all the time, or the manager owns their mistakes? The truth is that your team needs to know you’re human. You can’t fix problems if you don’t know about them, and no one will tell you about them unless you make space for that.

One time, the night before a big release, someone on the team pushed a change that created thousands upon thousands of calls to a service that, in turn, thought it was the target of a DDoS attack, which then shut down our access. Here’s a moment when a lot of folks could have panicked and blamed one another. Instead, we giggled wildly, jumped into chat and on calls, fixed it, and kept going.

I couldn’t have been more proud of the team that day. Their response was wonderful. And it makes all the difference in how we work together, recover, and iterate.

You’re the manager. You have to be show your vulnerability first. You can try this by admitting you’re having a bad day, that you don’t understand something, or made a mistake.


Being a manager is tough. Your mistakes impact people. I’ve made all of the mistakes above and more. I feel that it’s critical to share and learn from one another, so when we encounter pitfalls, we don’t feel alone and know a path forward.


The post Mistakes I’ve Made as an Engineering Manager appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

A Complete State Machine Made With HTML Checkboxes and CSS

State machines are typically expressed on the web in JavaScript and often through the popular XState library. But the concept of a state machine is adaptable to just about any language, including, amazingly, HTML and CSS. In this article, we’re going to do exactly that. I recently built a website that included a “no client JavaScript” constraint and I needed one particular unique interactive feature.

The key to all this is using <form> and <input type="radio"> elements to hold a state. That state is toggled or reset with another radio <input> or reset <button> that can be anywhere on the page because it is connected to the same <form> tag. I call this combination a radio reset controller, and it is explained in more detail at the end of the article. You can add more complex state with additional form/input pairs.

It’s a little bit like the Checkbox Hack in that, ultimately, the :checked selector in CSS will be doing the UI work, but this is logically more advanced. I end up using a templating language (Nunjucks) in this article to keep it manageable and configurable.

Traffic light state machine

Any state machine explanation must include the obligatory traffic light example. Below is a working traffic light that uses a state machine in HTML and CSS. Clicking “Next” advances the state. The code in this Pen is post processed from the state machine template to fit in a Pen. We’ll get into the code in a more readable fashion later on.

Hiding/Showing table information

Traffic lights aren’t the most practical every-day UI. How about a <table> instead?

There are two states (A and B) that are changed from two different places in the design that affect changes all over the UI. This is possible because the empty <form> elements and <input> elements that hold state are at the very top of the markup and thus their state can be deduced with general sibling selectors and the rest of the UI can be reached with descendent selectors. There is a loose coupling of UI and markup here, meaning we can change the state of almost anything on the page from anywhere on the page.

General four-state component

Diagram of a generic four-state finite state machine

The goal is a general purpose component to control the desired state of the page. “Page state” here refers to the desired state of the page and “machine state” refers to the internal state of the controller itself. The diagram above shows this generic state machine with four states(A, B, C and D). The full controller state machine for this is shown below. It is built using three of the radio reset controller bits. Adding three of these together forms a state machine that has eight internal machine states (three independent radio buttons that are either on or off).

Diagram of the controller’s internal states

The “machine states” are written as a combination of the three radio buttons (i.e. M001 or M101). To transition from the initial M111 to M011, the radio button for that bit is unset by clicking on another radio <input> in the same group. To transition back, the reset <button> for the <form> attached to that bit is clicked which restores the default checked state. Although this machine has eight total states, only certain transitions are possible. For instance, there is no way to go directly from M111 to M100 because it requires two bits to be flipped. But if we fold these eight states into four states so that each page state shares two machine states (i.e. A shares states M111 and M000) then there is a single transition from any page state to any other page state.

Reusable four-state component

For reusability, the component is built with Nunjucks template macros. This allows it to be dropped into any page to add a state machine with the desired valid states and transitions. There are four required sub-components:

  • Controller
  • CSS logic
  • Transition controls
  • State classes

Controller

The controller is built with three empty form tags and three radio buttons. Each of the radio buttons checked attribute is checked by default. Each button is connected to one of the forms and they are independent of each other with their own radio group name. These inputs are hidden with display: none because they are are not directly changed or seen. The states of these three inputs comprise the machine state and this controller is placed at the top of the page.

{% macro FSM4S_controller()%}   <form id="rrc-form-Bx00"></form>   <form id="rrc-form-B0x0"></form>   <form id="rrc-form-B00x"></form>   <input data-rrc="Bx00" form="rrc-form-Bx00" style="display:none" type="radio" name="rrc-Bx00" checked="checked" />   <input data-rrc="B0x0" form="rrc-form-B0x0" style="display:none" type="radio" name="rrc-B0x0" checked="checked" />   <input data-rrc="B00x" form="rrc-form-B00x" style="display:none" type="radio" name="rrc-B00x" checked="checked" /> {% endmacro %}

CSS logic

The logic that connects the controller above to the state of the page is written in CSS. The Checkbox Hack uses a similar technique to control sibling or descendant elements with a checkbox. The difference here is that the button controlling the state is not tightly coupled to the element it is selecting. The logic below selects based on the “checked” state of each of the three controller radio buttons and any descendant element with class .M000. This state machine hides any element with the .M000 class by setting display: none !important. The !important isn’t a vital part of the logic here and could be removed; it just prioritizes the hiding from being overridden by other CSS.

{%macro FSM4S_css()%} <style>   /* Hide M000 (A1) */   input[data-rrc="Bx00"]:not(:checked)~input[data-rrc="B0x0"]:not(:checked)~input[data-rrc="B00x"]:not(:checked)~* .M000  {     display: none !important;   }    /* one section for each of 8 Machine States */  </style> {%endmacro%}

Transition control

Changing the state of the page requires a click or keystroke from the user. To change a single bit of the machine state, the user clicks on a radio button that is connected to the same form and radio group of one of the bits in the controller. To reset it, the user clicks on a reset button for the form connected to that same radio button. The radio button or the reset button is only shown depending on which state they are in. A transition macro for any valid transition is added to the HTML. There can be multiple transitions placed anywhere on the page. All transitions for states currently inactive will be hidden.

{%macro AtoB(text="B",class="", classBtn="",classLbl="",classInp="")%}   <label class=" {{class}} {{classLbl}} {{showM111_A()}} "><input class=" {{classInp}} " form="rrc-form-Bx00" type="radio" name="rrc-Bx00" />{{text}}</label>   <button class=" {{class}} {{classBtn}} {{showM000_A1()}} " type="reset" form="rrc-form-Bx00">{{text}}</button> {%endmacro%} 

State class

The three components above are sufficient. Any element that depends on state should have the classes applied to hide it during other states. This gets messy. The following macros are used to simplify that process. If a given element should be shown only in state A, the {{showA()}} macro adds the states to hide.

{%macro showA() %}   M001 M010 M100 M101 M110 M011 {%endmacro%} 

Putting it all together

The markup for the traffic light example is shown below. The template macros are imported in the first line of the file. The CSS logic is added to the head and the controller is at the top of the body. The state classes are on each of the lights of the .traffic-light element. The lit signal has a {{showA()}} macro while the “off” version of signal has the machine states for the .M000 and .M111 classes to hide it in the A state. The state transition button is at the bottom of the page.

{% import "rrc.njk" as rrc %} <!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8" />   <title>Traffic Light State Machine Example</title>   <link rel="stylesheet" href="styles/index.processed.css">   {{rrc.FSM4S_css()}} </head> <body>   {{rrc.FSM4S_controller()}}   <div>     <div class="traffic-light">       <div class="{{rrc.showA()}} light red-light on"></div>       <div class="M111 M000 light red-light off"></div>       <div class="{{rrc.showB()}} light yellow-light on"></div>       <div class="M100 M011 light yellow-light off"></div>       <div class="{{rrc.showC()}} light green-light on"></div>       <div class="M010 M101 light green-light off"></div>     </div>     <div>       <div class="next-state">         {{rrc.AtoC(text="NEXT", classInp="control-input",           classLbl="control-label",classBtn="control-button")}}         {{rrc.CtoB(text="NEXT", classInp="control-input",           classLbl="control-label",classBtn="control-button")}}         {{rrc.BtoA(text="NEXT", classInp="control-input",           classLbl="control-label",classBtn="control-button")}}       </div>     </div>   </div> </body> </html>

Extending to more states

The state machine component here includes up to four states which is sufficient for many use cases, especially since it’s possible to use multiple independent state machines on one page.

That said, this technique can be used to build a state machine with more than four states. The table below shows how many page states can be built by adding additional bits. Notice that an even number of bits does not collapse efficiently, which is why three and four bits are both limited to four page states.

Bits (rrcs) Machine states Page states
1 2 2
2 4 2
3 8 4
4 16 4
5 32 6

Radio reset controller details

The trick to being able to show, hide, or control an HTML element anywhere on the page without JavaScript is what I call a radio reset controller. With three tags and one line of CSS, the controlling button and controlled element can be placed anywhere after this controller. The controlled side uses a hidden radio button that is checked by default. That radio button is connected to an empty <form> element by an ID. That form has a type="reset" button and another radio input that together make up the controller.

<!-- RRC Controller --> <form id="rrc-form"></form> <label>   Show   <input form="rrc-form" type="radio" name="rrc-group" /> </label> <button type="reset" form="rrc-form">Hide</button>  <!-- Controlled by RRC --> <input form="rrc-form" class="hidden" type="radio" name="rrc-group" checked /> <div class="controlled-rrc">Controlled from anywhere</div>

This shows a minimal implementation. The hidden radio button and the div it controls need to be siblings, but that input is hidden and never needs to be directly interacted with by the user. It is set by a default checked value, cleared by the other radio button, and reset by the form reset button.

input[name='rrc-group']:checked + .controlled-rrc {   display: none; } .hidden {   display: none; }

Only two line of CSS are required to make this work. The :checked pseudo selector connects the hidden input to the sibling it is controlling. It adds the radio input and reset button that can be styled as a single toggle, which is shown in the following Pen:

Accessibility… should you do this?

This pattern works, but I am not suggesting it should be used everywhere for everything. In most cases, JavaScript is the right way to add interactivity to the web. I realize that posting this might get some heat from accessibility and semantic markup experts. I am not an accessibility expert, and implementing this pattern may create problems. Or it may not. A properly labelled button that does something to the page controlled by otherwise-hidden inputs might work out fine. Like anything else in accessibility land: testing is required.

Also, I have not seen anyone else write about how to do this and I think the knowledge is useful — even if it is only appropriate in rare or edge-case situations.


The post A Complete State Machine Made With HTML Checkboxes and CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

Web Scraping Made Simple With Zenscrape

Web scraping has always been taken care of by actual developers, since a lot of coding, proxy management and CAPTCHA-solving is involved. However, the scraped data is very often needed by people that are non-coders: Marketers, Analysts, Business Developers etc.

Zenscrape is an easy-to-use web scraping tool that allows people to scrape websites without having to code.

Let’s run through a quick example together:

Select the data you need

The setup wizard guides you through the process of setting up your data extractor. It allows you to select the information you want to scrape visually. Click on the desired piece of content and specify what type of element you have. Depending on the package you have bought (they also offer a free plan), you can select up to 30 data elements per page.

The scraper is also capable of handling element lists.

Schedule your extractor

Perhaps, you want to scrape the selected data at a specific time interval. Depending on your plan, you can choose any time span between one minute to one hour. Also, decide what is supposed to happen with the scraped data after it has been gathered.

Use your data

In this example, we have chosen the .csv-export method and have selected a 10 minute scraping interval. Our first set of data should be ready by now. Let’s take a look:

Success! Our data is ready for us to be downloaded. We can now access all individual data sets or download all previously gathered data at once, in one file.

Need more flexibility?

Zenscrape also offers a web scraping API that returns the HTML markup of any website. This is especially useful for complicated scraping projects, that require the scraped content to be integrated into a software application for further processing.

Just like the web scraping suite, the API does not forward failed requests and takes care of proxy management, Capotcha-solving and all other maintenance tasks that are usually involved with DIY web scrapers.

Since the API returns the full HTML markup of the related website, you have full flexibility in terms of data selection and further processing.

Try Zenscrape

The post Web Scraping Made Simple With Zenscrape appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

How we made Carousell’s mobile web experience 3x faster

Both a sobering and interesting read from Stacey Tay on how the team at Carousell gathered the metrics to define a performance budget and, in turn, developed a better experience for their customers:

Our new PWA listing page loads 3x faster than our old listing page. After releasing this new page, we’ve had a 63% increase in organic traffic from Indonesia, compared to our our all time-high week. Over a 3 week period, we also saw a 3x increase in ads click-through-rates and a 46% increase in anonymous users who initiated a chat on the listing page.

The team inlined critical CSS, reduced the number of resources the app was loading, and implemented a lazy loading strategy, among many other things. I think it’s interesting to note that they also changed the design of the app in certain ways to make things more performant, too. I reckon it’s easy to fall into the trap of thinking that performance is solely a task for developers and posts like this prove that it’s more collaborative than that.

Direct Link to ArticlePermalink

The post How we made Carousell’s mobile web experience 3x faster appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]