Entries tagged “less.”

Super secret new Colorpeek features

 I’ve been waiting to blog about this till I had a chance to redesign Colorpeek to better communicate these features, but it’s been two weeks and I want to show off. My app, my rules, right? Here we go…

Drag and drop images

You can now drag and drop image files into Colorpeek and watch it magically grab the most prominent colors in supported browsers. This is helpful if you want to start a new palette from existing source imagery, and it’s possible thanks to Lokesh Dhakar’s awesome Color Thief script.

Export palette to various text formats

Let’s say you’ve got a rather attractive palette all ready to go, but you don’t want to copy and paste every value individually.

Now you can hit the share button and choose “Export.” You can copy the values in a few different formats: Plain text, JSON, LESS, SCSS or Stylus. Let me know if I’m missing a format you’d like!

Yada yada yada

I bumped Knockout to version 2.3.0 and updated the brand color keywords.

Wait, why are you still reading this? Go try it already!

Happier IE fallbacks with CSS, LESS and conditional comments

Nobody likes writing CSS fallbacks. They’re a speed bump in your creative flow. Here’s how I use a couple different techniques to simplify the process

This assumes that you’re using conditional comments on the html tag to define classes for certain versions of IE. This technique was originally proposed by Paul Irish and refined in the HTML5 Boilerplate to something like this:

<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]>    <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 8]>    <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->

You can omit the “no-js” class if you aren’t using Modernizr, and feel free to remove or tweak the conditional comments to suit the versions of IE that actually require fixes (I recommend referring to this Quirksmode post for examples).

With this markup is in place, you can conveniently target styles to specific versions of IE. For example, let’s say I’m running into a box model bug in IE7 that’s resulting in a div not having the correct amount of top margin. Thanks to the classes I’ve applied using conditional comments, I can apply extra margin only for that browser version and below.

.example { margin-top: 24px; }
.lt-ie8 .example { margin-top: 48px; }

Voila! .example will have extra margin to account for the bug in IE7 and below without impacting any other browsers.

Vanilla CSS works well for a simple, top-level item like that, but it can get a bit hairy when you try to apply similar fixes with particularly deep inheritance. An example:

.l-container.example.s-active .button {
    background-color: #00ccff;
    display: block;
    line-height: 42px;
}
.lt-ie8 .l-container.example.s-active .button {
    height: 42px;
}

Yeesh… that’s pretty verbose! Here’s where the beauty of LESS comes in handy, particularly its support for scoped variables, nested rules and the ampersand combinator:

.l-container.example.s-active .button {
    @height: 42px;
    background-color: #00ccff;
    display: block;
    line-height: @height;
    .lt-ie8 & {
        height: @height;
    }
}

Occurrences of @height will be replaced with 42px in the compiled CSS. The ampersand in the nested selector will be replaced by the parent selector. This will compile to exactly the same as the previous example, but with a lot less redundant typing.

That’s all well and good for one-off bug fixes, but what about recurring fixes that need to be applied on a case-by-case basis? That’s where the power of parametric mixins comes in handy.

Here’s an example of a mixin we can use to support transparency in old IE syntax and standard syntax. Note that because IE’s filter property does not use standard CSS syntax, it can throw off the LESS parser, so we use a leading tilde (essentially the LESS equivalent of eval) and string interpolation to render the rule:

.opacity(@amount) {
    opacity: @amount;
    .lt-ie9 & {
        @ieop: @amount * 100;
        filter: ~"alpha(opacity=@{ieop})";
    }
}

.example { .opacity(0.5); }

Which will compile to:

.example { opacity: 0.5; }
.lt-ie9 .example { filter: alpha(opacity=50); }

Here’s another example for supporting inline-block in IE7 and below:

.inline-block() {
    display: inline-block;
    .lt-ie8 & {
        display: inline;
        zoom: 1;
    }
}

.example { .inline-block(); }

Compiled:

.example { display: inline-block; }
.lt-ie8 .example {
    display: inline;
    zoom: 1;
}

Like The Force, nested rules can be used for good or for evil. When working with this sort of shorthand it can get a little too easy to overuse mixins or forget to combine selectors to insure your compiled CSS is still fairly lean. Refer to this entry for more on that very topic.

When LESS is just enough

Allison Wagner wrote a thoughtful post summarizing her experience with LESS on Happy Cog‘s lovely blog, Cognition. Her criticisms echoed my own when I first started using the self-described “dynamic stylesheet language,” so I thought I’d respond to them here so that other designer/developers might avoid similar points of trepidation.

She starts with the difficulty of debugging the compiled CSS:

LESS, by virtue of the compiler, rewrites and reformats CSS, which means the line numbers referenced by Web Inspector or Firebug are guaranteed to be wrong. I found myself having to search for styles a lot more, whereas in the past I would have simply referenced the line number in the debugger. While this may seem like a small annoyance to many, it slowed me down quite a bit.

Yep, totally annoying and, as Allison suggests, never 100% avoidable. While I would argue that fundamental LESS features (such as variable and operator support) more than make up for time lost to this quirk, there are still a couple of ways to minimize its impact:

  1. Use @import in your primary style sheet to include your mixins and variables in one or more separate files. Since these will usually contain the majority of your un-compiled styles, the resultant CSS should map a little bit closer to your LESS line numbers.

  2. If you’re using less.js for development (as opposed to less.app or a server-side compiler), calling less.watch() appending #!watch to your URL and refreshing the page will make LESS asynchronously recompile whenever your style sheet is modified. This can greatly expedite troubleshooting, especially if you have enough screen real estate to develop and preview side-by-side.

Allison’s other concern is the risk of “code bloat”:

Let’s face it, CSS is not exactly a champion of the DRY (Don’t Repeat Yourself) programming principal. Repetitious values in a pure CSS style sheet are the mark of a solid design system. Even the most well-written, pure CSS is typically teeming with identical declarations repeated over and over. I like that LESS advocates a very DRY approach to writing styles with shortcuts like mixins. And while the DRY approach is promoted inside the LESS files themselves, the generated CSS is anything but DRY. In fact, it’s far less DRY than pure CSS.

She provides a brief example of potential code bloat while suggesting that LESS users “are encouraged to embed [declarations] into each selector individually in the form of a mixin”. To be clear, this behavior isn’t encouraged by LESS any more than repetitious selections are encouraged by jQuery. If you use LESS to enhance your existing principles of well-formed and scalable CSS, there’s no reason why your code bloat should become unmanageable.

Example time! Let’s say we have an hCard with a photo, full name and role we’d like to style. Our vanilla CSS might look like this:

.vcard {
    border: 1px solid #ccc;
    margin: 10px;
    padding: 10px;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}
.vcard, .vcard .photo {
    -webkit-box-shadow: 0 1px 3px #eee;
    -moz-box-shadow: 0 1px 3px #eee;
    box-shadow: 0 1px 3px #eee;
}
.vcard .photo {
    float: right;
    margin: 0 0 10px 10px;
}
.vcard .fn {
    font-weight: bold;
    text-transform: uppercase;
}
.vcard .role {
    color: #999;
    font-size: 87.5%; /* 14px / 16px */
}

Not unmanageable. But let’s see how we can make it easier to read, write and expand upon using LESS. We’ll start by looking for things that can be re-used or streamlined. The gutter value seems to be consistent, so we’ll move that to a variable so we can change it easily. Also, those vendor prefixes are a bit lengthy, so we’ll move them into mixins we can re-use anywhere.

@gutter: 10px;
.border-radius (@radius) {
    -webkit-border-radius: @radius;
    -moz-border-radius: @radius;
    border-radius: @radius;
}
.box-shadow (@shadow) {
    -webkit-box-shadow: @shadow;
    -moz-box-shadow: @shadow;
    box-shadow: @shadow;
}

With our variables and mixins established, we can rewrite our LESS like so:

.vcard {
    border: 1px solid #ccc;
    margin: @gutter;
    padding: @gutter;
    .border-radius(3px);
    &, .photo {
        .box-shadow(0 1px 3px #eee);
    }
    .photo {
        float: right;
        margin: 0 0 @gutter @gutter;
    }
    .fn {
        font-weight: bold;
        text-transform: uppercase;
    }
    .role {
        color: #999;
        font-size: 14 / 16 * 100%;
    }
}

Note the use of the ampersand combinator, which will be replaced with the parent selector (.vcard) in the output. Combined with the nested .photo, .fn and .role selectors, we’ve avoided re-typing the parent selector altogether. We’re no longer repeating vendor prefixes or margin/padding sizes, and LESS can do the font-size math for us. Best of all, the output is identical to that of our vanilla CSS. Sayonara, code bloat!

I’m not saying that Allison’s criticism isn’t a possibility in LESS… only that it’s a direct result of how you choose to use the language. In his blog post CSS: Taking control of the cascade, Jason Z. illustrates a LESS technique that he finds valuable in spite of its verbosity. LESS won’t make these decisions for you, it only provides the tools to do the job faster and easier than you could have otherwise.

To quote Stan Lee in Spider-Man’s first appearance, “with great power there must also come — great responsibility!”