Author Archive

Progressive And Responsive Navigation


  

Developing for the Web can be a difficult yet rewarding job. Given the number of browsers across the number of platforms, it can sometimes be a bit overwhelming. But if we start coding with a little forethought and apply the principles of progressive enhancement from the beginning and apply some responsive practices at the end, we can easily accommodate for less-capable browsers and reward those with modern browsers in both desktop and mobile environments.

screenshot

A Common Structure

Below is the HTML structure of a navigation menu created by WordPress. This unordered list is pretty common for content management systems and hand-coded websites alike. This will be the basis for our work.

Please note: Any ellipses (…) in the snippets below stand in for code that we have already covered. We have used them to shorten the code and highlight the parts that are relevant to that section.

<nav class="main-navigation">
   <ul>
      <li><a href="#home">Home</a></li>
      <li>
         <a href="#about">About Us</a>
         <ul class="children">
            <li><a href="#leadership">Leadership</a></li>
            <li><a href="#involvement">Involvement</a></li>
            <li><a href="#vision">Our Vision</a></li>
         </ul>
      </li>
      <li><a href="#clients">Our Clients</a></li>
      <li>
         <a href="#support">Support</a>
         <ul class="children">
            <li><a href="#blog">Blog</a></li>
            <li><a href="#downloads">Downloads</a></li>
            <li><a href="#faq">FAQ</a></li>
         </ul>
      </li>
      <li><a href="#contact">Contact Us</a></li>
   </ul>
</nav>

Unstyled Navigation
Our navigation, unstyled.

Our Tools

  • CSS Reset
  • HTML5 elements
  • LESS CSS
  • jQuery

CSS Reset

Resetting our CSS styles is where we’ll start. Browsers have different default styles for the elements we’ll be using, so understanding this and getting all of the elements to look the same is important. In this example, since we’re using an unordered list, there will be default left padding, top and bottom margins, and a list-style. You can either deal with these individually or, if you’re project will include more than just this navigation, use a reset to clear all of the styles and start fresh. I prefer Eric Meyer’s Reset CSS, but there are a few others to choose from, listed below. Whichever you choose, make sure it accounts for the new HTML5 elements.

HTML5 and CSS3 Elements

We’ll be wrapping the menu in HTML5’s nav element, which is one HTML5 feature that we should be using right now. If you need more good reasons to use HTML5 in your daily work, such as accessibility, then read “Top 10 Reasons to Use HTML5 Right Now� over at Codrops.

CSS3 will give our menu the progressive feel we’re looking for. We can use nifty effects such as linear gradients, text and box shadows and rounded corners, while providing a reasonable appearance for browsers that are dragging their feet. You could also consider using something like CSS3 Pie in the process. This will give those lagging browsers most of the functionality they lack to display your CSS3 properties.

LESS CSS

To make our CSS more efficient, we’ll use LESS along with a class file to ease the difficulty of dealing with all of those browser prefixes. Other options, such as Sass and Compass, do effectively the same thing and might better fit your particular development environment. If you’re interested in learning more about LESS and how it compares to Sass, check out another article of mine, “An Introduction to LESS, and Comparison to Sass.�

jQuery

To make our navigation a little friendlier in small browsers, such as those on mobile devices, we’ll use JavaScript. Essentially, we will gather all of the elements in our navigation and reorganize them into a select form element. Then, when the user selects an option from the list, they will navigate to that page. Interaction with a select element is one of the easiest and best ways to handle navigation in a small window. The practice is pretty common as well, so the learning curve for users will be gentler.

Getting Started

After applying a reset, we get something like the following. You can see that the margins, padding and list styles have been cleared.

Reset navigation
Reset navigation

Child-Level Menus

For now, the child-level menus will only get in the way. The best thing to do is remove them from the equation and add them back in when it’s time to style them. To achieve this, we will apply position: relative to all of the list elements, and move the children off screen until they are needed.

.main-navigation {
   li {
      position: relative;
   }
   .children {
      left: -999em;
      position: absolute;
   }
}

Applying left: -999em; position: absolute; will move the children to the left of the screen by a significant margin. This method is preferable to just using display: none because it is more accessible to screen readers.

Unstyled without children
Unstyled without children

Common Navigation Styles

Every navigation menu will probably have links in it. But these links are not like the links we see in the main body of the page, which are blue, underlined and distinguishable from the surrounding text. Rather, links in the navigation will stand alone, and their function will be obvious. That being said, the links in a nav element will probably have a few features of their own that distinguish them from typical anchor tags.

nav {
   a {
      color: inherit;
      display: block;
      text-decoration: none;
   }
}

Thus, a link will inherit the color of the text assigned to the parent element, in this case nav. It will be set to display as a block-level element, because we want the clickable area to be large and we do not want underlining (because that would just look funny).

Navigation with more functional links
Navigation with more functional links

Please note: color: inherit is not supported in IE 6 or 7. If you need to support those browsers, then you will need to explicitly set the color that you want.

Lining Up

Getting the menu in line calls for the use of floats. Initially, we’ll float all of the elements in the nav element to the left. Later, we’ll undo this property for the child-level menus, along with a lot of the other styles that we’ll set along the way.

.main-navigation {
   ul, li, a {
      float: left;
   }
   …
}

Inline navigation
Inline navigation

Because every element in the nav element is now floated, the element itself will collapse as though it were empty. There are a few ways to deal with this. One is to also float the nav element itself, which will expand it to wrap around its contents. If need be, you can set it to width: 100% to fill any remaining space to the right. Or you could use Nicolas Gallagher’s “micro� clearfix solution, which essentially adds clear: both just before the closing of the nav element.

/* For modern browsers */
.cf:before,
.cf:after {
    content:"";
    display:table;
}
.cf:after {
    clear:both;
}
/* For IE 6/7 (trigger hasLayout) */
.cf {
    zoom:1;
}

Because we’re using LESS for our CSS, applying the clearfix to our main-navigation class without modifying the markup is very easy.

.main-navigation {
   .cf;
   …
}

We’ll see more of this, as well as a description of how this works, in the section titled “Rounded Corners and Gradients� below.

Styling

All righty. By now, you’re probably as tired of looking at an unstyled menu as I am. To start, we’ll build what looks like a block wall, and then chisel a nice menu out of it. We won’t serve the block wall to antiquated browsers, but it’s a good start anyway.

Background Color and Borders

.main-navigation {
   font-size: 0.8em;

   ul, li, a {
      …
   }
   ul {
      background: #eee;
      border: 1px solid #ddd;
   }
   li {
      …
      border-right: 1px solid #ddd;
   }
   li:last-child {
      border-right: none;
   }
   a {
      height: 35px;
      line-height: 35px;
      margin: 3px;
      padding: 0 15px;
   }
   .children {
      …
   }
}

In the code above, the text was just too big, so we shrunk it with font-size: 0.8em. This property is set on the main-navigation class, so it applies throughout the navigation. The top-level unordered list has a border: 1px solid #ddd property to break it out from the page. Each list item element is given a border-right: 1px solid #ddd; to separate it from each other. The li:last-child selector targets the last list item element in the unordered list, removing the right border because no item follows it.

The links within the navigation are given a background color and some left and right padding to add distinction and increase their clickable area. We’re fixing the height and line-height, instead of using top and bottom padding, so that we can predict more accurately where the child-level menus will be positioned relative to their shared parent list item.

Navigation resembling a block wall
Navigation resembling a block wall

Rounded Corners and Gradients

.main-navigation {
   …
   text-shadow: 0 1px 1px #fff;

   ul {
      border: 1px solid #ddd;
      .border-radius();
      .linear-gradient();
   }
   …
}

.border-radius (@radius: 5px) {
   border-radius: @radius;
}
.linear-gradient (@start: #fff, @end: #ddd, @percent: 100%) {
   background: @start; /* Old */
   background: -moz-linear-gradient(top,  @start 0%, @end @percent); /* FF3.6+ */
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,@start), color-stop(@percent,@end)); /* Chrome, Safari 4+ */
   background: -webkit-linear-gradient(top,  @start 0%,@end @percent); /* Chrome 10+, Safari 5.1+ */
   background: -o-linear-gradient(top,  @start 0%,@end @percent); /* Opera 11.10+ */
   background: -ms-linear-gradient(top,  @start 0%,@end @percent); /* IE 10+ */
   background: linear-gradient(top,  @start 0%,@end @percent); /* W3C */
}

Above, we have created two new classes, border-radius and linear-gradient.

The border-radius class is actually what LESS developers refer to as a parametric mixin. Essentially, it’s like a class, but you can pass variables to it in case the default value isn’t exactly what you want. In this case, if 5 pixels isn’t what you want, you could reference the mixin as .border-radius(10px), and then it would use 10px instead of the original 5px. With the border-radius property, you could also pass it something like .border-radius(5px 0 0 5px), and it would apply the 5-pixel rounding to only the top-left and bottom-left corners. For more information and possibilities on border-radius, see “Border-Radius: Create Rounded Corners With CSS� at CSS3.info.

Another parametric mixin is linear-gradient. But with LESS, you can add classes to other selectors and it will apply the same styles—thus negating the need to modify the markup just to add another class (and, by extension, its styles) to an element. Both of the classes I’ve created cover the possibilities of browser syntax. Currently, Webkit has two different syntaxes, because for some reason the browser makers decided to ignore the specification when first implementing it and made up their own syntax. With Chrome 10 and Safari 5.1, they went back to the specification, joining the other browsers, and made things a little easier for us. However, if you still care about the previous versions, you’ll need to add their crazy syntax as well. We’ve also added a white text-shadow to the text in the navigation to give it a slightly beveled look.

Navigation with a gradient and rounded corners
With the two classes applied, you can see the slight gradient and the rounded corners.

Some browsers do not support CSS3 gradients. Yes, I’m looking at you, Internet Explorer 6, 7, 8 and 9. If you want to use something other than the filter syntax for gradients, you’ll have to wait for version 10. In the meantime, either you could use the filter syntax for IE (see the “For Internet Explorer� section of “Cross-Browser CSS Gradient�) and put them in an IE-specific style sheet, or you could use an image gradient. You could also just leave them without the gradient, but that’s not the point here.

Parent-Level Hover States

.main-navigation {
   …
   li:hover {
      a {
         .linear-gradient(#dfdfdf, #c0bebe, 100%);
      }
      .children {
         …
         a {
            background: none;
         }
      }
   }
   …
}

The code above will trigger the hover state for anchor elements when the user hovers over their parent list item, rather than hovering over the anchors themselves. This way is preferable so that the anchor element maintains its hover state when the user is mousing over the child-level menu as well. Doing it this way does, however, create the need to reset the background color of anchor elements within the child-level menus. That’s the part you see within the children selector.

Hovering over the parent-level links
Hovering over the parent-level links

Displaying the Children

Bringing the children back onto the screen is easy enough. But before we get carried away, we need to clear out a few styles that are applied to all unordered lists, list items and anchors.

.main-navigation {
   …
   .children {
      background: #fff;
      left: -999em;
      position: absolute;

      li, a {
         float: none;
      }
      li {
         border-right: none;
      }
   }
}

The code above changes the background of the child-level menu to white, instead of the light gradient that we used in the parent-level menu. The next couple of lines remove the left float from the list items and anchors. We’ve also gotten rid of the right border that separates the list items in the parent-level menu.

The Hovering Box

.main-navigation {
   …
   .children {
      background: #fff;
      .box-shadow();
      left: -999em;
      margin-left: -65px;
      position: absolute;
      top: 30px;
      width: 130px;
      …
   }
}

…
.box-shadow (@x: 0, @y: 5px, @blur: 5px, @spread: -5px, @color: #000) {
   -moz-box-shadow: @x @y @blur @spread @color;
   -webkit-box-shadow: @x @y @blur @spread @color;
   box-shadow: @x @y @blur @spread @color;
}
…

We’ve added another parametric mixin to the equation. This one produces the box shadow, with all of its parameters as variables, and with the browser prefixes. We’ve borrowed the styles from .children to make the box appear to hover over the parent menu. To center the child underneath the parent element, we’ve set the left position to 50%, and set the left margin to the negative value of half the width of the child. In this case, the child level menu is set to 130 pixels wide, so we’ve set the left margin to -65 pixels.

Navigation w/child reset to hover style
Navigation with the child reset to hover style

Child-Level Hovers

.main-navigation {
   …
   .children {
      …
      a {
         .border-radius(3px);
         height: 30px;
         line-height: 30px;
         margin: 3px;
      }
      a:hover {
         background: #dff2ff;
      }
   }
}

We’re using the parametric mixin that we created for the border-radius for the links in the children as well. Adding a 3-pixel margin and 3-pixel border radius to all of the anchor elements within the child menu will accent the 5-pixel border radius of the menu well. We’ve also adjusted the height and line height a little, because they just seemed too high. Finally, we gave the list items a nice soft-blue background color on hover.

Navigation w/child menus and their hover state
Navigation with child menus and their hover state

Responding to Mobile Browsers and Size Constraints

A lot of screen sizes and browsers are out there. The iPhone has had two resolutions. Up to the 3GS model, it was 480 × 320; since the iPhone 4, it has been 960 × 640. Android browsers run from 480 × 320 to 854 × 480. Android also has a lot of browsers to choose from. There are the usual Firefox and Opera, as well as a ton of browsers by small start-ups. You can get Opera for the iPhone, but since you can’t make it the default browser, you’re pretty much stuck with Safari. Given this variety, we’ll have to make some adjustments if we want our navigation to be useful on all devices and in all browsers.

Fitting the Content

Accomplishing this part is easy, but doing it will probably require adjusting our styles. But that’s why we’re here, isn’t it?

Currently, when we open the navigation demo in iOS, it looks like this:

Original navigation in iOS
Original navigation in iOS

This might not look too bad on a giant screen, and it might even be usable on the iPad, but you would struggle to use it on a phone. Zooming in might make it easier, but that’s not ideal. Optimizing for the device is preferable, and forcing the browser to use the available space is simple.

<meta name="viewport" content="width=device-width">

This alone makes a huge difference in the way the browser renders the page. And while the menu is not the prettiest it’s ever been, it is a lot more functional.

Navigation on iOS with the viewport adjusted
Navigation on iOS with the viewport adjusted

Media Queries

We can use media queries to adjust the styles based on the media in the browser. In this case, we’ll use the width of the page to change the look and feel of the navigation to make it more suitable to the available space. In this case, we’ll make the menu items more button-like.

@media only screen and (max-width: 640px) {
   .main-navigation {
      ul {
         border: none;
         background: none;
         .border-radius(0);
      }
      li {
         border-right: none;
      }
      a {
         border: 1px solid #ddd;
         .border-radius();
         font-size: 1.2em;
         height: auto;
         .linear-gradient();
         line-height: 1em;
         padding: 15px;
      }
   }
}

In the code above, we’ve used a media query to target situations in which the user is only looking at a screen and in which the width of the window is a maximum of 640 pixels. In this scenario, we’ve removed the border, background and border radius from the unordered list, and applied those styles to the anchors themselves. We’ve also increased the font size of the anchors, cleared the height and line height, and adjusted the padding of the links to increase the clickable area.

Navigation adjusted for mobile display
Navigation adjusted for mobile

As you can see, the links look much friendlier in a mobile browser. They are, however, only half functional, because touch devices don’t have a hover state. This means that if you have child-level menus, as we do here, you’ll have to figure out a way to display them as well. You could replace the hover state with a touch event of some kind, or expand the children out onto the page. That would greatly increase the size of the navigation, though. The following method might be best.

Replacing the Menu in Mobile Browsers With JavaScript

$(function() {
   /* Get the window's width, and check whether it is narrower than 480 pixels */
   var windowWidth = $(window).width();
   if (windowWidth <= 480) {

      /* Clone our navigation */
      var mainNavigation = $('nav.main-navigation').clone();

      /* Replace unordered list with a "select" element to be populated with options, and create a variable to select our new empty option menu */
      $('nav.main-navigation').html('<select class="menu"></select>');
      var selectMenu = $('select.menu');

      /* Navigate our nav clone for information needed to populate options */
      $(mainNavigation).children('ul').children('li').each(function() {

         /* Get top-level link and text */
         var href = $(this).children('a').attr('href');
         var text = $(this).children('a').text();

         /* Append this option to our "select" */
         $(selectMenu).append('<option value="'+href+'">'+text+'</option>');

         /* Check for "children" and navigate for more options if they exist */
         if ($(this).children('ul').length > 0) {
            $(this).children('ul').children('li').each(function() {

               /* Get child-level link and text */
               var href2 = $(this).children('a').attr('href');
               var text2 = $(this).children('a').text();

               /* Append this option to our "select" */
               $(selectMenu).append('<option value="'+href2+'">--- '+text2+'</option>');
            });
         }
      });
   }

   /* When our select menu is changed, change the window location to match the value of the selected option. */
   $(selectMenu).change(function() {
      location = this.options[this.selectedIndex].value;
   });
});

To summarize, first we’re checking whether the window is less than or equal to 480 pixels. To ensure an accurate reading on mobile devices, you can use a meta tag to scale the viewport accordingly:

<meta name="viewport" content="width=device-width">

We populate the first variable, windowWidth, with the value of the window’s width as defined by the given device. We can use this value to then check whether the width is narrower than a particular value. We’ve chosen 480 pixels here because, while we might want to use media queries to adjust the menu below 640 pixels, at a certain point the viewport would be just too small to justify the menu taking up all that space.

We then use jQuery to create a clone of our menu that we can later crawl to create our options. After we’ve done that, it’s safe to replace the unordered list with the select element that we’ll be using and then select it with jQuery.

In the largest part of the code, we’re crawling through the clone of our navigation. The selector used, $(mainNavigation).children('ul').children('li'), ensures that we go through only the uppermost list elements first. This is key to creating the nested appearance of the select menu. With it, we select the “direct� child-level unordered list elements and then their “direct� child-level list elements, and then parse through them.

Inside each of these “direct� descendants, we get the value of the href attribute and the text of the link, and we store them in variables to be inserted in their respective options. This is implemented by appending <option value="'+href+'">'+text+'&kt;/option> to our new select list.

While we’re in the top-level list item elements, we can check whether any child-level menus need to be parsed. The statement if ($(this).children('ul').length > 0) checks whether the count of the selector is greater than 0. If it is, that means child-level items need to be added. We can use that same selector, with a slight addition, to go through these elements and add them to our select list, $(this).children('ul').children('li').each().

The same parsing method applies to these elements, although they use different variables to store the values of the anchor tags, so as not to create conflicts. We have also prefixed text to the menu labels at this level, --- , to differentiate them from the other items.

Parsing through the menu in this method (nested) will create the parent-child relationship you would expect.

After the menu is created, a little more JavaScript will enable the select list to serve as navigation.

$(selectMenu).change(function() {
   location = this.options[this.selectedIndex].value;
});

When the select menu is changed, a new option is selected, and the window location is changed to reflect the value of the option. That value comes from the href of the original anchor element.

The result is like so:

screenshot
The select menu in a desktop browser

Select menu on Android and iPhone
The select menu in Android and iPhone browsers

Given the increased clickable area of the native controls, the select menu is obviously much more user-friendly on mobile.

Share Your Experience

We’d love to see and hear about some of your experiences with menus across browsers and platforms; please share below. And if you have any questions, we’ll do our best to find answers for you.

(al)


© Jeremy Hixon for Smashing Magazine, 2012.


An Introduction To LESS, And Comparison To Sass


  

I’ve been using LESS religiously ever since I stumbled upon it months ago. CSS was never really a problem for me, in and of itself, but I was intrigued by the idea of using variables to create something along the lines of a color palette for my websites and themes. Having a color palette with a fixed number of options to choose from helps prevent me from going color crazy and deviating from a chosen style.

As it turns out, LESS — and Sass for that matter — are so much more than that. LESS and Sass share a lot of similarities in syntax, including the following:

  • Mixins – Classes for classes.
  • Parametric mixins – Classes to which you can pass parameters, like functions.
  • Nested Rules – Classes within classes, which cut down on repetitive code.
  • Operations – Math within CSS.
  • Color functions – Edit your colors.
  • Namespaces – Groups of styles that can be called by references.
  • Scope – Make local changes to styles.
  • JavaScript evaluation – JavaScript expressions evaluated in CSS.

The main difference between LESS and Sass is the way in which they are processed. LESS is a JavaScript library and is, therefore, processed client-side.

Sass, on the other hand, runs on Ruby and is processed server-side. A lot of developers might not choose LESS because of the additional time needed for the JavaScript engine to process the code and output the modified CSS to the browser. There are a few ways around this. The way I get around it is to use LESS only during the development process. Once I’m finished, I copy and paste the LESS output into a minifier and then into a separate CSS file to be included in place of the LESS files. Another option is to use LESS.app to compile and minify your LESS files. Both options will minimize the footprint of your styles, as well as avoid any problems that might result from the client’s browser not running JavaScript. While this is not likely, it’s always a possibility.

LESS Is More

Installation

Including LESS in something that you’re building is about as easy as it gets:

  1. Go get yourself a copy of less.js;
  2. Create a file to put your styles in, such as style.less;
  3. Add the following code to your HTML’s <head>:
<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>

Note the rel attribute of the link. You are required to append the /less to the end of the value in order for LESS to work. You are also required to include the script immediately after the link to the style sheet. If you’re using HTML5 syntax, and I can’t imagine why you wouldn’t be, you can leave out the type="text/css" and the type="text/javascript".

There’s also a server-side version of LESS. The easiest way to install LESS on the server is with Node Package Manager (NPM).

Variables

If you’re a developer, variables are one of your best friends. In the event that you’ll be using information repeatedly (in this case, a color), setting it to a variable makes sense. This way, you guarantee yourself consistency and probably less scrolling about looking for a hex value to copy and paste. You can even do some fun little adding and subtracting of hex values that you want to render. Take this example:

@blue: #00c;
@light_blue: @blue + #333;
@dark_blue: @blue - #333;

If we apply these styles to three divs, we can see the gradated effect created by adding and subtracting the hex values to and from the original blue:

A screenshot illustrating the transition from 3 shades of blue

The transition from @light_blue to @blue to @dark_blue.

The only difference in variables between LESS and Sass is that, while LESS uses @, Sass uses $. There are some scope differences as well, which I’ll get to shortly.

Mixins

On occasion, we might create a style that’s intended to be used repeatedly throughout the style sheet. Nothing is stopping you from applying multiple classes to the elements in the HTML, but you could also do this without ever leaving your style sheet, using LESS. To illustrate this, I have pasted some sample code that one might use to style two elements on the page.

.border {
border-top: 1px dotted #333;
}

article.post {
background: #eee;
.border;
}

ul.menu {
background: #ccc;
.border;
}

This will give you something similar to what you would get if you had gone back to the HTML file and added the .bordered class to the two elements there — except you’ve done it without leaving the style sheet. And it works just as well:

A screenshot illustrating two elements that share a border style

Both the article and the unordered list share the border style.

With Sass, you declare @mixin prior to the style to identify it as a mixin. Later, you declare @include to call it.

@mixin border {
border-top: 1px dotted #333;
}

article.post {
background: #eee;
@include border;
}

ul.menu {
background: #ccc;
@include border;
}

Parametric Mixins

Like having functions in your CSS (*swoon*), these can be immensely useful for those seemingly redundant tasks of modern-day CSS. The best and most useful example of their use relates to the many vendor prefixes that we struggle with during this transition from CSS2 to CSS3. Nettuts+ has a wonderful webcast and article by Jeffrey Way, with details on including a file consisting entirely of useful parametric mixins that cover most of your favorite CSS3 properties in the respective vendor prefixes. For example, a simple mixin to handle rounded corners in their various forms:

.border-radius( @radius: 3px ) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}

In this case, the .border-radius class has a default radius of 3 pixels, but you can pass whatever value you like to get a rounded corner of that radius. Something like .border-radius(10px) will round the corners by 10 pixels.

The syntax in Sass is very similar to that of LESS. Just use the $ for variables, and call the mixins with the @mixin and @include method mentioned earlier.

Selector Inheritance

Here’s something not provided in LESS. With this ability, you can append a selector to a previously established selector without the need to add it in a comma-separated format.

.menu {
	border: 1px solid #ddd;
}

.footer {
	@extend .menu;
}

/* will render like so: */
.menu, .footer {
	border: 1px solid #ddd;
}

Nested Rules

Nesting classes and ids in CSS can be one of the only methods to keep your styles from interfering with and from being interfered with any other styles that may be added along the way. But this can get very messy. Using a selector like #site-body .post .post-header h2 is unappealing and takes up a lot of unnecessary space. With LESS, you can nest ids, classes and elements as you go. Using the example above, you could do something like this:

#site-body { …

    .post { …

        .post-header { …

            h2 { … }

            a { …

            	&:visited { … }
            	&:hover { … }
            }
        }
    }
}

The above code is essentially the same as the ugly selector in the previous paragraph, but it’s much easier to read and understand, and it takes up much less space. You can also refer in element styles to their pseudo-elements by using the &, which in this case functions similar to this in JavaScript.

Operations

This is about what you would expect: using fixed numbers or variables to perform mathematical operations in your styles.

@base_margin: 10px;
@double_margin: @base_margin * 2;

@full_page: 960px;
@half_page: @full_page / 2;
@quarter_page: (@full_page / 2) / 2;

For the record, I am aware that I could have also divided by four to get the @quarter_page variable, but I wanted to illustrate that the parentheses rule from the “order of operations� also applies. Parentheses are also required if you’re going to perform operations within compound properties; for example, border: (@width / 2) solid #000.

Sass is a lot more versatile with numbers than LESS. It has built into it conversion tables to combine comparable units. Sass can work with unrecognized units of measurement and print them out. This feature was apparently introduced in an attempt to future-proof the library against changes made by the W3C.

/* Sass */
2in + 3cm + 2pc = 3.514in

/* LESS */
2in + 3cm + 2pc = Error

Color Functions

Earlier, I mentioned how LESS helps me stick to a color scheme in my coding process. One of the parts that contributes to this the most is the color function. Suppose you use a standard blue throughout your styles, and you want to use this color for a gradated “Submit� button in a form. You could go into Photoshop or another editor to get the hex value for a slightly lighter or darker shade than the blue for the gradient. Or you could just use a color function in LESS.

@blue: #369;

.submit {
    padding: 5px 10px;
    border: 1px solid @blue;
    background: -moz-linear-gradient(top, lighten(@blue, 10%), @blue 100%); /*Moz*/
    background: -webkit-gradient(linear, center top, center bottom, from(lighten(@blue, 10%)), color-stop(100%, @blue)); /*Webkit*/
    background: -o-linear-gradient(top, lighten(@blue, 10%) 0%, @blue 100%); /*Opera*/
    background: -ms-linear-gradient(top, lighten(@blue, 10%) 0%, @blue 100%); /*IE 10+*/
    background: linear-gradient(top, lighten(@blue, 10%) 0%, @blue 100%); /*W3C*/
    color: #fff;
    text-shadow: 0 -1px 1px rgba(0,0,0,0.4);
}

The lighten function literally lightens the color by a percentage value. In this case, it will lighten the base blue by 10%. This method enables us to change the color of gradated elements and any other elements with that color simply by changing the base color itself. This could prove immensely helpful in theming. Plus, if you used a parametric function, like the ones listed above, you could alleviate some of that browser-prefix tedium with something as simple as .linear-gradient(lighten(@blue), @blue, 100%);.

Either way, you get an effect that’s rather nice:

Screenshot of a styled submit button

Our nicely gradated, variable-based “Submit� button.

There are a lot of other color functions for darkening and saturating colors and even spinning the color wheel to other colors. I recommend trying them out to see what you can come up with.

Sass seems to have a lot more color options — not that I would need them all. Lighten and darken are the only ones that I see myself using often. For more detail, Nex3 has an in-depth article on the topic.

Conditionals and Control

This is rather nifty, and another thing not provided by LESS. With Sass, you have the ability to use if { } else { } conditional statements, as well as for { } loops. It supports and, or and not, as well as the <, >, <=, >= and == operators.

/* Sample Sass "if" statement */
@if lightness($color) > 30% {
  background-color: #000;
} @else {
  background-color: #fff;
}

/* Sample Sass "for" loop */
@for $i from 1px to 10px {
  .border-#{i} {
    border: $i solid blue;
  }
}

Namespaces

Namespaces can be used to add another level of organization to our CSS, by allowing us to create groups of commonly used styles and then pick from them along the way. For instance, if we created a group of styles called defaults, we could pull from this group when we come across an element that needs it.

#defaults {
	.nav_list () {
		list-style: none;
		margin: 0; padding: 0;
	}
	.button () { … }
	.quote () { … }
}

Later, in our code, if we come across a ul element within a nav element, we would know that we’ll need our default style. So, we can simply call it, and it will be applied.

nav ul {
	#defaults > .nav_list;
}

Scope

Scoping is standard throughout programming and thus standard in LESS. If you define a variable at the root level of your style sheet, it will be available and consistent throughout the document. If, however, you redefine the variable from within a selector such as an id or class, then it will be available — with the new value — only within that selector.

@color: #00c; /* blue */

#header {
	@color: #c00; /* red */

	border: 1px solid @color; /* will have a red border */
}

#footer {
	border: 1px solid @color; /* will have a blue border */
}

Because we’ve restated the variable within the #header selector, the value for that variable will be different and will apply only within that selector. Anything before or after it will retain the value of the original statement.

Scope is handled a little differently in Sass. In the above code, when the @color variable is changed to red, it will be interpreted as such from that point on within the code.

Comments

This part is pretty basic. Two types of comments are valid in LESS. The standard CSS comment, /* comment */, is valid and will get passed through the processing and outputted. Single-line comments, // comment, work as well but will not get passed and outputted and, as a result, are “silent.�

Importing

Importing is pretty standard, too. The standard @import: 'classes.less'; works just fine. If, however, you’re importing another LESS file, then the file extension is optional, so @import 'classes'; would work as well. If you want to import something without LESS processing it, you can use the .css extension (for example, @import: 'reset.css';).

String Interpolation

String values can also be used in variables and called within styles via @{name}.

@base_url = 'http://coding.smashingmagazine.com';
background-image: url("@{base_url}/images/background.png");

Escaping

There will be times when you need to include a value that is not valid CSS syntax or that LESS doesn’t recognize. More often than not, it will be some crazy Microsoft hack. To avoid throwing errors and breaking LESS, you will need to escape them.

.class {
	filter: ~"progid:DXImageTransform.Microsoft.Alpha(opacity=20)";
}

/* Will actually be outputted like this: */
.class {
	filter: progid:DXImageTransform.Microsoft.Alpha(opacity=20);
}

JavaScript Evaluation

This is one of my favorite parts of LESS: using Javascript in style sheets — simply brilliant. You can use expressions and also reference aspects of the environment using backticks.

@string: `'howdy'.toUpperCase()`; /* @string becomes 'HOWDY' */

/* You can also use the previously mentioned interpolation: */
@string: 'howdy';
@var: ~`'@{string}'.topUpperCase()`; /* becomes 'HOWDY' */

/* Here we access part of the document */
@height = `document.body.clientHeight`;

Output Formatting

Whereas LESS has no output settings, Sass provides four output versions: nested, compact, compressed and expanded.

Final Thoughts

These two libraries share a lot of basics. Both of them are fantastic tools for designers who code, and they can also help developers work more efficiently and quickly. If you’re a fan of Ruby or HAML, then Sass might be right up your ally. For me, being a PHP and JavaScript geek, I tend to lean towards LESS for its ease of inclusion and access to JavaScript’s expressions and document attributes. I doubt that I’ve even come close to truly grasping the possibilities of programming in my style sheets, but I am intent on trying. If you’ve been using either, or both, of these in your work, I’d love to hear more about it and see some of your results. Tips, tricks and corrections are, of course, always welcome as well.

(al)


© Jeremy Hixon for Smashing Magazine, 2011.


  •   
  • Copyright © 1996-2010 BlogmyQuery - BMQ. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress