Tuesday, October 21, 2014

The danger of Sass @extend and selector limits

Recently whilst working on a Sass project in Liferay Portal we hit the CSS selector limit in Internet Explorer 9 - whereby you cant exceed more than 4096 selectors in one CSS file . This highlighted to us the compounding nature of extending (@extend) classes in Sass.

From a development perspective it’s handy to have a generic class and extend from as opposed to adding multiple classes to the element- which is already a challenge when dealign with markup defined at a server level (i.e. non MVC)

Here’s an example of what I mean:

.btn {
  box-sizing:border-box;
  padding:6px 12px;
  font-size:14px;
  line-height:20px;
  background-color:DodgerBlue ;
  border:1px solid CornflowerBlue;
}

.primary-btn { @extend .btn; font-size:18px/24px; }

.secondary-btn { @extend .btn; background-color:#999999; border-color:#666666 }

.action-btn { @extend .btn; background-color:#ffff;  }

.btn, .primary-btn, .secondary-btn, .action-btn {

  box-sizing:border-box;
  padding:6px 12px;
  font-size:14px;
  line-height:20px;
   background-color:DodgerBlue ;
  border:1px solid CornflowerBlue;
}
    
    

How to work around it?

In our situation we opted to split the CSS files up, as the cost of extra HTTP request was minimal and it meant we could keep using extend to make maintenance a little easier

Friday, September 26, 2014

Stylesheet limitations in Internet Explorer 9 and below

  • A sheet may contain up to 4095 rules - check yours 
  • A sheet may @import up to 31 sheets
  • @import nesting supports up to 4 levels deep
Thursday, September 4, 2014

Sass placeholders vs class inheritance

Should you create a base class or use a placeholder?

The difference is placeholder style’s won’t get compiled unless something extends from in in your project so if the purpose is just to consolidate base styles i.e. consolidate some variables the placeholder is a better option, but if you’re just making an alternative style tweak class inheritance is your best option. Below is a good example of how both can be used

Below is a good example of how both can be used

    // use placeholder to consolidate our variables for the stylized font
%stylized-font {
   font:$stylized-font;
   color:$stylized-font-color;
}

// page headers
.page-header {
   @extend %stylized-font;
}

// custom header for about page
.about-header {
   @extend .page-header;
    color:blue;
}

Sass mixins vs placeholders

When you first dive into Sass it’s tempting to start creating mixins, for everything but mixins aren’t always the best fit for some situations and can lead to more overhead. Mixins for instance will import all those rules into every class fin which they are included. However placeholders  ( or class inheritance) will result in a consolidation of all classes extending from that placeholder or class -  see example below

Example of extending the clearfix class (called clear-after here)

    // clear floats of child elements (micro clearfix)
.clear-after {
    & {
        *zoom: 1;
    }
    &:before,
    &:after {
        content: "";
        display: table;
    }
    &:after {
        clear: both;
    }
 }
 // Example elements with floating children
 .header {
    @extend .clear-after;
 }

 .content {
   @extend .clear-after;
 }
 
 .footer {
   @extend .clear-after;
 }
    

Resulting CSS

.clear-after, .header, .content, .footer {
  *zoom: 1;
}
.clear-after:before, .header:before, .content:before, .footer:before, .clear-after:after, .header:after, .content:after, .footer:after {
  content: "";
  display: table;
}
.clear-after:after, .header:after, .content:after, .footer:after {
  clear: both;
}
    
Friday, August 29, 2014

Sass mixin for cross-browser RGBA

Handy little mixing to inject rgba() with IE filter

The mixin:

@mixin transparent-background($color, $alpha) {
  $rgba: rgba($color, $alpha);
  $ie-hex-str: ie-hex-str($rgba);
  background-color: transparent;
  background-color: $rgba;
  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie-hex-str},endColorstr=#{$ie-hex-str});
  zoom: 1;
}

Usage:

   .blue-container {
    $color-bg: rgb(0,0,255);
    background-color: $color-bg;
    .transparent-red-element {
        @include alpha-color(rgba(255, 0, 0, .65), border-color, $color-bg);
    }
} 
   

Checkout rgbapng mixin if you also want a PNG fallabck

Wednesday, August 27, 2014

Liferay and SASS

Finally, something to help wrangle Theme Stylesheets!

SASS has been a saviour for me when developing themes. Before SASS I would have a base stylesheet that would end up being 2000+ lines by the time I included styles for our custom portlets, then I would have a custom stylesheet to tweak styles and add branding that would be another 600+ lines. With SASS, I can now use variables to take care of most of the basic customisation and my custom stylesheet is almost purely branding.

Of course there was a bit of trial and error to work out how to implement SASS in Liferay themes. First you need to tell Liferay that your going to use it’s  SASS compiler which happens to be Compass via adding the @import “compass”; statement at the top of your custom.css file, then you need to make sure all you CSS files that use SASS have the appropriate naming convention _file.scss for Liferay’s Compass implementation to identify which files in needs to parse during build.

Example custom.css

@import "compass"; // tell Liferay where using Compass
@import "variables";  // Where I define font, link colour etc
@import "helpers"; // Mixins etc
@import url(jquery-ui-1.10.4.custom.css); // non-sass plugin css
@import "default"; // Base theme
@import "brand"; // Where all my be-spoke styles and branding is done
    

Where to from here?

Start optimizing your stylesheets - Here some thought starters:

  • use variables to declare common things such as fonts and colours
  • mixins to overcome declaring prefixes for border radius etc
  • inheritance/extensions to reduce repetition e.g. for adding clearfix
  • operators to calculate grid layout dimensions and convert hex colours to rgb/rgba 

Examples to follow in my next post stay tuned!

Thursday, July 10, 2014

Bootstrapped Liferay Language selector (Take 2)

I’ve found issues with the usual embed code so I rolled my own using Velocity, feel free to use and abuse:

<script src=”https://gist.github.com/htmlr/fdede9d227f8c2e5d080.js”></script>

Thursday, June 19, 2014

Email creation a little easier thanks to Campaign Monitors INLINER tool

IMHO asking most front-end developer to code an EDMs is offensive. It’s a step back in time as opposed to the shiny new HTM5/CSS3 playground due to the fact most email clients your going to probably target (E.g. Outlook 2000-2010) only support very basic HTML and it ends up being a case of nesting HTML tables, spacer images and a whole lot of inline CSS -  a very laborsome and error prone task .  Luckily Campaign Monitor’s Inliner tool makes it a little less tedious as it will inject all your CSS inline which let’s you keep your CSS in one spot (i.e. the head of your document) whilst you develop and fine tuning.

Note: If you’re using Campaign Monitor it actually gives you the option to do this when you upload your HTML which is nice.

http://inliner.cm/

Happy EDM building……NOT!

Monday, June 2, 2014

Easy file comparison on Mac using FileMerge

If you’ve got  Xcode installed on your Mac it has a handy inbuilt tool called FileMerge which lets you check for differences between 2 files. 

Here’s how to create an alias to FileMerge so you don’t need to boot Xcode everytime:

  • Go to Macintosh HD > Applications
  • Right-click Xcode.app
  • Click Show Package Contents
  • Go to Contents > Applications
  • Right-click Filemerge.app
  • Click Make Alias
  • You will need to type your password
  • Move the alias to your dock or desktop
Wednesday, May 21, 2014

Fixing jQuery UI Autocomplete issue within fixed container

As experienced by others, I came across an issue whereby my jQuery UI Autocomplete dropdown was acting like a fixed element and not scrolling with the rest of the form.

Here’s 2 options for fixing it depending on your situation:

During initialization

$( ".selector" ).autocomplete({ appendTo: "#someElem" });


..or after initialization

$('.ui-autocomplete').each(function(){
$(this).autocomplete('option','appendTo', $(this).parent());
});