When developing my first FitBit Versa watch face, I ran into an issue when my wife and I were testing on our devices.  When the battery gets low, the OS displays a low battery icon.  The issue here is that the face that I developed already has an icon that changes with the battery level:

Now the OS battery icon is in almost the same exact place, so it looks really weird to have them overlapping each other.  From what I have found on the developer's forum, there is no way to suppress the OS's icon.

Solution


According to the Versa user manual, the OS displays the icon when the device is within 24 hours of running out of power, and starts flashing when it gets to a critical level.  The only solution that I have come up with at this time is to just hide my custom icon when it gets near that level. Hopefully in the future, the power API will be able to tell us when this actually happens, as it can be different for different devices. Here is a simplified version of the JavaScript that handles this for us:

import { battery } from "power";

imgBattery = document.getElementById("battery_img");

let batteryChargeLevel = Math.floor(battery.chargeLevel);

if(batteryChargeLevel <= 20) {
    imgBattery.style.display = "none";
} else {
    imgBattery.style.display = "inline";
}

For the full code, you can visit the repository for this face on GitHub. This file also contains an example of how to hide the custom icon when the watch is attached to the charger, as again, the OS has it's own icon that it wants to display.

I am hopeful that in a future version of the FitBit OS, we will have the ability to suppress the OS's icon, and be able to just use our custom icon for our watch face.

I have been planning a custom theme for my personal site here at ChrisPerko.NET. Currently, the site is running a child theme of Hestia, developed by ThemeIsle.com. It's a great theme, and I've had it for over a year, but I want something custom! I had a choice to make; which starter theme to use? It is very useful to create a theme completely from scratch in order to understand what all is being done behind the scenes. Alecaddd has a great YouTube series called Create a Premium WordPress Theme, and it is a great place to start if you've never built a theme from scratch.


_Underscores

_Underscores is a great starter theme. It was created by the same folks that created and maintain WordPress itself. I am currently using this as part of the TailwindCSS Theming Series on YouTube. _Underscores gets rid of all the annoying parts of developing a theme, such as setting up the header.php and footer.php files, javascript and stylesheet enqueues, and even setting up a simple mobile navigation menu! If you are fairly new to WordPress theme development, it is a great place to start. Honestly, a simple theme could be built by just working the CSS of the _Underscores theme.

The WordPress CLI (Command Line Interface) comes baked with a command to generate a brand new _Underscores theme for you in an existing WordPress installation. This feature allows a rapid setup of your environment; in minutes you can have a fresh install of WordPress running locally, with a brand new theme ready for styling!


Sage

I have been working in Laravel development for that past year, and really love the framework. One thing I really like about it, is how fast you can get an application running using Blade templates. If you don't know, Blade allows you to write very clean front-end code with access to all the PHP goodness. Instead of having to break into PHP to do something such as a for loop, you can simply do this in Blade: @foreach(users as user):.

Using Blade templates in WordPress seemed like it would be a great way to write cleaner, more readable code. This is where Sage by Roots comes in. Sage is a starter theme that comes with a bunch of goodies out of the box just like _Underscores. It has all of the fun things that Blade has to offer, such as extending layout files, and you can start it by using Bootstrap 4, Foundation, Bulma, or even nothing if you really want to control everything.

My main concern with Sage is how drastically different it is to a regular theme. The file structure closely resembles an application source structure than a theme. This may work for you if you are building a complicated application on top of WordPress, but for a standard theme this will seem very daunting. The Blade files are nice and neat, but you must have a separate file acting like a controller to get the data you need to that Blade template. Controllers make a lot of sense when building an app, but to just display a post on a page seems like overkill to me.

My last gripe with Sage really just comes down to this: What if I build a theme for a client and later on they decide to hire another developer to make some changes? That developer will most likely have never used Sage, and the huge difference in file structure alone versus a standard theme will probably completely confuse that developer. Using Sage would also be a huge learning curve for an inexperienced developer, so if you are new to the world of web development, I highly suggest using either of the other two starter themes on this post.


AWPS

The last starter theme for this post is AWPS, or the Alecaddd WordPress Starter Theme. AWPS is based on _Underscores, so if you like what _Underscores has to offer, I highly recommend at least taking a look at this theme.

This theme has an advantage in my book over _Underscores in that the back-end is all object-oriented. This leads to much cleaner code, and is very easy to extend to add in any feature you can think of. It utilizes the PSR-4 autoloader, so no more require() lines scattered about in your PHP code.

Want a fast setup? No worries, there is a CLI for that! A new feature of the CLI allows you to even give the theme a custom namespace for all of the class files. Want a more in-depth look at it in a video format? Alessandro has even created a YouTube series on AWPS to get you familiar with it quickly.


Conclusion

In conclusion, for my new theme, I have decided to go with AWPS. Although it doesn't use Blade templates, which I originally wanted, it is very easy to use. Packed with all the features I loved about _Underscores, AWPS really brings the starter theme up to modern day coding standards.

For beginner developers, I recommend either starting with _Underscores, or if you have an understanding of OOP, go with AWPS. You will be up and running in no time!

I use transitions and transformations a lot in CSS. They are really useful tools that can help make a site look and feel really good. However, there is something I can never remember, so I am putting it in writing here for myself, and for anyone else that runs into this problem.


Tricky Tricky

There is a very small difference in the syntax between transitioning multiple properties versus transforming multiple properties on an element. In transitions, you separate the different transitions by a comma, but transformations omit this comma.

.my-class {

    transition: background-color 200ms, color 300ms, opacity 450ms;

    transform: rotateX(30deg) scale(1.1); /* no comma! */

}

I think this is poor design in CSS. It makes sense to separate each transition by a comma, and I would think that it would make the most sense to do the same in the transformations. I hope that if you are having an issue figuring out how to do multiple transitions or transformations that this has helped you out!

Last week, I wrote about my initial views of TailwindCSS.  I had a lot of interest from readers on Twitter to continue the post to cover the components aspect of Tailwind.  The Tailwind docs do contain a page on how to extract components already, so I want to take this time to cover my workflow and thought process on extracting components in an app.  In this article, I will be using the starter Laravel app, along with Laravel mix.  If you are unfamiliar with Laravel, that is okay, we will be mostly covering the HTML/CSS, and using Laravel as a jumping off point.  The source code for this project can be found on github.


Project Setup

To get things started, I used the Laravel installer to scaffold out a blank application:

laravel new tailwind-components

cd tailwind-components

npm install

php artisan make:auth

Next step is to install Tailwind:

npm install tailwindcss --save-dev

Now that we are done scaffolding our app, we have a layout file at resources/views/layouts/app.blade.php, and the main file we will work with today at resources/views/welcome.blade.php.  Let's go into welcome.blade.php and remove everything from the file, and start with a blank canvas.  We will now enter the following code to utilize the main app.blade.php layout file.

@extends('layouts.app')

@section('content')

@endsection

All of our code will exist between the @section('content') and @endsection blade directives.  Let's now visit app.blade.php and set it up.  We will remove the pre-built navigation bar so that we can build our own using Tailwind.  The body section of your file should look like this:

<body>
    <div id="app">
        @yield('content')
    </div>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}"></script>
</body>

The last bit is to setup Tailwind.  Open up webpack.mix.js and change it to look like the following:

let mix = require('laravel-mix');
let tailwindcss = require('tailwindcss');

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css')
   .options({
       processCssUrls: false,
       postCss: [
           tailwindcss('./tailwind.js')
       ]
   });

Per the Tailwind installation docs, we need to setup the tailwind.js file that we have set on line 9 of our mix file.

./node_modules/.bin/tailwind init tailwind.js

For this example, we are going to leave the generated tailwind.js config file alone, and focus only on our components.  Last step for our project setup is to clear out resources/assets/sass/app.scss and set it to use the Tailwind preflight and utilities:

@tailwind preflight;

// Add component files here.

@tailwind utilities;

Setting up the Navigation Bar

Let's build a basic navigation bar using the Tailwind utilities.  We just need a bar with a title, we can always add links later if we choose.

    <div id="app">

        <nav class="py-4 px-2 mb-4 bg-grey-lightest shadow-md">
            <span class="font-medium">Tailwind Components</span>
        </nav>
        
        @yield('content')
    </div>

Now we must think about if this could make use of turning all of those classes into a component or not.  Since we are using a layout file that all of our pages will inherit, I do not think it is worth it to make a component for the navbar.  This is easy enough to update here in the HTML if we ever want to change the styles.


Application Buttons

We know that our app will need to use buttons.  Let's style one up using the Tailwind utilities, and then create a component for them.  For this example, we will be putting all of our code in the welcome.blade.php file, inside of the @section('content').  I'll first wrap all of these buttons that we will create into a container and center it, just to make it look a little nicer.

<div class="container px-4 mx-auto text-center">
   <button class="px-4 py-2 rounded shadow bg-blue hover:bg-blue-dark text-white">
      Button
   </button>
</div>

This is great!  We were able to use the utility classes to design a button that we want to use within our app.  Since we know we will need many buttons, this is a perfect candidate to turn it into a component.  Let's create a new file for our buttons: resources/assets/sass/buttons.scss, and load it into our app.scss file.

@tailwind preflight;

// Add component files here.
@import 'buttons';

@tailwind utilities;

Now within our newly created buttons.scss file, we will create a class .btn.  Note, that the hover attributes cannot be used as a class name, and must use the CSS :hover selector.

.btn {
    @apply .px-4 .py-2 .rounded .shadow .bg-blue .text-white;

    &:hover {
        @apply .bg-blue-dark;
    }
}

We can now change all of those classes on our button element to use just btn.  The @apply directive that ships with Tailwind allows this magic to happen above.  We are now looking at a very clean file that clearly states what our buttons look like.  However, we now need to have a couple other button types: one that is a light grey, and one that is red.  All of the buttons should look the same other than the colors, so we will want to extract the reusable utilities.  Later on, if we are asked to change the buttons to not have rounded corners, we will only have one class to change.  Here is how it will look:

.btn {
    @apply .px-4 .py-2 .rounded .shadow;
}

.btn-primary {
    @apply .bg-blue .text-white;

    &:hover {
        @apply .bg-blue-dark;
    }
}

.btn-normal {
    @apply .bg-grey-lightest;

    &:hover {
        @apply .bg-grey-lighter;
    }
}

.btn-danger {
    @apply .bg-red-light .text-white;

    &:hover {
        @apply .bg-red;
    }
}

That's it!  We have just a few lines of code that completely define how we want our buttons to look.  Each button will use the btn class, as well as a class to denote what color to use. Here is an example of using these classes:

        <button class="btn btn-primary">
            Button
        </button>

        <button class="btn btn-normal">
            Normal
        </button>

        <button class="btn btn-danger">
            Danger
        </button>


Building Some Forms

Forms are also an important part of any application.  Let's steal an example form from the Tailwind examples.  We are going to use the first login form example.  Our app needs to have a login form, but also a registration form.  It would be nice if they looked the same.  We may need other forms in the future, so having components for each of these inputs would be nice.

<div class="w-full max-w-xs">
  <form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
    <div class="mb-4">
      <label class="block text-grey-darker text-sm font-bold mb-2" for="username">
        Username
      </label>
      <input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker" id="username" type="text" placeholder="Username">
    </div>
    <div class="mb-4">
      <label class="block text-grey-darker text-sm font-bold mb-2" for="password">
        Password
      </label>
      <input class="shadow appearance-none border border-red rounded w-full py-2 px-3 text-grey-darker mb-3" id="password" type="password" placeholder="******************">
      <p class="text-red text-xs italic">Please choose a password.</p>
    </div>
    <div class="flex items-center justify-between">
      <button class="bg-blue hover:bg-blue-dark text-white font-bold py-2 px-4 rounded" type="button">
        Sign In
      </button>
      <a class="inline-block align-baseline font-bold text-sm text-blue hover:text-blue-darker" href="#">
        Forgot Password?
      </a>
    </div>
  </form>
  <p class="text-center text-grey text-xs">
    ©2017 Acme Corp. All rights reserved.
  </p>
</div>

Whoa! That's a lot of classes! Let's take a look at what we can already change: the button. We want the button to match our primary button, so by just changing the class to be .btn .btn-primary, we will have it match our theme. We also have a link here for 'Forgot Password'. We should have our links all look the same on the site. Let's make a file for HTML elements: resources/assets/sass/elements.scss.

a {
    @apply .inline-block .align-baseline .font-bold .text-sm .text-blue;

    &:hover {
        @apply .text-blue-darker;
    }
}

We can now remove all of the classes from the Forgot Password hyperlink. Be sure to include this new file in app.scss.

@tailwind preflight;

// Add component files here.
@import 'buttons';
@import 'elements';

@tailwind utilities;

We may or may not want all forms to look the same. Let's say we want the login and register forms to exist in this small white card, and others will not have these features. We can refactor the classes on the form tag into a component. We will create a new file: resources/assets/sass/forms.scss, and you guessed it, we will need to import it into app.scss.

form.login-register-form {
    @apply .bg-white .shadow-md .rounded .px-8 pt-6 .pb-8 .mb-4;
}

Labels and inputs should be uniform, so let's create components for those, pulling the utility classes out of the HTML. We also want the same padding between each input, so let's refactor that out as a component as well. Even though it is just a single utility class, this will make it easy to adjust the sizing to all form fields later.

form.login-register-form {
    @apply .bg-white .shadow-md .rounded .px-8 pt-6 .pb-8 .mb-4;

    .input-group {
        @apply .pb-4;
    }

    label {
        @apply .block .text-grey-darker .text-sm .font-bold .mb-2;
    }

    input.form-input {
        @apply .shadow .appearance-none .border .rounded .w-full .py-2 .px-3 .text-grey-darker;
    }
}

One more thing that I noticed when looking at this form is that an input field can be invalid. Let's make these classes so that invalid fields on other forms will have the same look.

form.login-register-form {
    @apply .bg-white .shadow-md .rounded .px-8 pt-6 .pb-8 .mb-4;

    .input-group {
        @apply .pb-4;
    }

    label {
        @apply .block .text-grey-darker .text-sm .font-bold .mb-2;
    }

    input.form-input {
        @apply .shadow .appearance-none .border .rounded .w-full .py-2 .px-3 .text-grey-darker;
    }

    input.invalid {
        @apply .border-red .mb-3;
    }

    p.warning-text {
        @apply .text-red .text-xs .italic;
    }
}

We have cleaned up the form quite a bit. We still have utility classes, but that is fine. They only exist in spots that are specific to this particular form. We don't want to over-think the components!

    <div class="container w-full max-w-xs mx-auto my-8">
        <form class="login-register-form">
            <div class="input-group">
                <label for="username">
                    Username
                </label>
                <input class="form-input" id="username" type="text" placeholder="Username">
            </div>
            <div class="input-group">
                <label for="password">
                    Password
                </label>
                <input class="form-input invalid" id="password" type="password" placeholder="******************">
                <p class="warning-text">Please choose a password.</p>
            </div>
            <div class="flex items-center justify-between">
                <button class="btn btn-primary" type="button">
                    Sign In
                </button>
                <a href="#">
                    Forgot Password?
                </a>
            </div>
        </form>
        <p class="text-center text-grey text-xs">
            ©2017 Acme Corp. All rights reserved.
        </p>
    </div>

We can now easily create a registration form, and have it look similar to the sign in form.

    <div class="w-full max-w-xs mx-auto mt-8">
        <form class="login-register-form">
            <div class="input-group">
                <label for="username">Username</label>
                <input class="form-input" type="text" id="username" placeholder="Username">
            </div>
            <div class="input-group">
                <label for="email">Email</label>
                <input class="form-input" type="email" id="email" placeholder="email@email.com">
            </div>
            <div class="input-group">
                <label for="password">Password</label>
                <input class="form-input" type="password" id="password" placeholder="********">
            </div>
            <div class="input-group mb-6">
                <label for="confirm-password">Confirm Password</label>
                <input class="form-input" type="password" id="confirm-password" placeholder="********">
            </div>
            <div class="input-group text-center">
                <div class="btn btn-primary">Register</div>
            </div>
            <div class="text-center">
                <a href="">
                    Already have an account?
                </a>
            </div>
        </form>
    </div>


Conclusion

In closing, I hope that this article has made it clear how easy it is to create components out of the Tailwind utility classes, and how easy it is to read and modify these components. I personally like to build out these components using the utility classes in the HTML. Only when I start to see patterns of re-usability do I think it is a good idea to refactor the classes out into a single component. Using the @apply directive allows us to have small, concise CSS that is easy to modify.

A few months ago, I remember Adam Wathan tweeting about a CSS framework he was building, titled Tailwind (it came from building his KiteTail app).  I turned thirty this year, and that seems to have made me a grumpy old developer.  I used to see something new and want to be the first one using it, on the bleeding edge of technology.  Five years ago I would have been so excited to see this.  Why was I grumpy?  Utility-first CSS was why!

Utility-first CSS seemed to me like nothing better than writing inline styles.  We, as an industry, moved away from writing inline styles and started using style-sheets for many reasons.  Separations of concerns was one, and also the ability to refactor your code.  I saw some examples of Tailwind online, and was disgusted to see code like this:

<img class="w-24 rounded rounded-full border-4 border-white absolute pin-l pin-b -mb-8 ml-4" src="..." />

Can you imagine if you wanted to have a bunch of images look the same, re-using the same massive group of classes?  Think of what would happen if management or your client came to you and said "Hey, let's make all the images not have that white border".  Now you will have to search through your files and find all of those classes scattered among your HTML (or JavaScript if you are using templates in a framework such as React, Vue, etc).

The Good Parts

Tailwind does allow you to make extremely quick mock-ups and proof of concepts.  I finally gave in to my grumpiness and read through the docs, and started playing with the code on CodePen.  The first thing I did was a recreation of a Twitter profile card, which actually landed on the front-page of Codepen.  You can view the pen and the source code here.

I also started playing with making my own set of alert boxes.  First, I started by recreating a couple of the examples from the Tailwind docs, then made some modifications to design my own.  Again, you can view the code on Codepen.

I'm Not So Grumpy Anymore

The ability to make these components is super simple with Tailwind.  But what about a real application?  I'm not talking about a TODO app or something you just bang out one afternoon; I'm talking a large application.  How do we manage all of these classes, and how do we manage large design changes on a project?  Here is the answer that changed my opinion of Tailwind: it is component-friendly!  This means that you can actually take those globs of classes that you want to use for every image, or button, or notification box, and create a component out of them.  This single feature is what really made me see the light.  You still get the ability to make awesome design components extremely quickly, and you can put those ideas to use into components that you can use throughout your project!

I am too far into KickoffWP.com to be willing to refactor everything to use Tailwind, but I do plan to utilize the framework in my next project.

Next: TailwindCSS Components Workflow Process

Copyright © 2018 Chris Perko

linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram