Using @if to output browser-specific versions

494 views
Skip to first unread message

HansBKK

unread,
Jul 16, 2010, 3:20:30 AM7/16/10
to Compass

I saw this from Nathan somewhere:

> The much more useful control structure is @if. It allows not only great flexibility in mixins,
> but the ability to do things like “compile for WebKit” or “compile for IE”. If you set a
> !browser variable, you can then use @if to compile in sections of your CSS based on that.

This got me excited, since I'm currently striving for progressive
enhancement / responsive design as well as performance / scalability
ideals, and have wanted to get away from this traditional technique:

* Keep your browser specific (IE.CSS) and/or invalidating
(HACKS.CSS) code in a separate file and use it to override the main
(SCREEN.CSS) that everyone gets.

towards this goal:

* A given browser/device (UA) gets an appropriate single (full)
alternative stylesheet. To the extent it's appropriate/worthwhile for
performance reasons, strive for an ideal where the UA gets served
*only* relevant code (e.g. gecko doesn't get -webkit rules)

I've been doing some experimenting with this, and it seems entirely
feasible within Compass, and not even that much extra dev work using
diff'ing tools. I plan to post my intended matrix of Sass $variables
vs stylesheets - very much a work in progress - but thought I'd post
this first to see if interested others here could point me to any
relevant examples / posts or (I wish) documentation on these issues.
Obviously outside the Sass/Compass world would be fine, as the hardest
part so far is wrapping my brain around an algebra of logic that is
simple enough to manage, but deals effectively with valid vs invalid,
CSS2 vs CSS3, old/new vs browser/engine etc.

Actually the hardest part will of course be real-world implementation
and testing, but the above is where I'm at at the moment, so any help
would be greatly appreciated, as would suggestions as to where else to
post this.

Thanks

HansBKK

unread,
Jul 16, 2010, 11:43:55 PM7/16/10
to Compass
. . . interpreting the deafening silence as acute anticipation. . .
8-)

> I plan to post my intended matrix of Sass $variables vs stylesheets - very much a work in progress

So here it is:

http://spreadsheets.google.com/pub?key=t83v_WZhnp_F1w-vyaOvdFQ&single=true&gid=0&output=html

For posterity's sake, in case the above disappears, there's a text
record of my .scss file headers at the bottom of this message.

-----------------------------------------------

Here are a couple of Sass snippets to demonstrate the use of @if to
classify which rules go to which stylesheets. Note I've defaulted to
start with making each "flavor" pretty well self-documenting, showing
the (locally irrelevant) alternative code commented out, except where
the redundancy would be ridiculous. Since I use minifiers that strip
out all comments before rolling out a new design version from dev to
public, these won't impact served file weights.

Standalone declaration

<code>

@if $moz and ($invalid == true) {
/* For Gecko only - not valid. */
button::-moz-focus-inner { border: 0; }
}
@else {
/* For Gecko only - not valid. */
/* button::-moz-focus-inner { border: 0; } */
}

</code>


Within a ruleset:

<code>

//-------------------------------------- - - - - - -
// originally:
// margin: 0.8em 0 0;
// *margin: 1.75em 0 0;
//-------------------------------------- - - - - - -
@if $ie6-7 and $invalid {
/* For IE 6 & 7 only. */
margin: 1.75em 0 0;
/* For all but IE 6 & 7. */
/* margin: 0.8em 0 0; */
/* For all. */
}
@if not $ie6-7 {
/* For IE 6 & 7 only. */
/* margin: 1.75em 0 0; */
/* For all but IE 6 & 7. */
margin: 0.8em 0 0;
/* For all. */
}
@if not $invalid {
/* For IE 6 & 7 only. */
margin: 1.75em 0 0;
/* For all but IE 6 & 7. */
margin: 0.8em 0 0;
/* For all. */
}
// strange how this doesn't work - posted an issue
/* For all. */
padding: 0 0.5em;

</code>


Sample mixin - something like this probably already exists within
Compass' native libraries, sorry I didn't check them out first

<code>
@mixin css3-border-box {
@if $ie6-7 and $invalid {
/* For IE 6 and up only - not valid. */
-ms-box-sizing: border-box;
/* For `other` browsers - not valid CSS 2.1 - yes valid CSS3. */
/* box-sizing: border-box; */
}
@if $ie8-up and $invalid {
/* For IE 6 and up only - not valid. */
-ms-box-sizing: border-box;
}
@if $moz and $invalid {
/* For Gecko only - not valid. */
-moz-box-sizing: border-box;
}
@if $webkit and $invalid {
/* For Webkit only - not valid. */
-webkit-box-sizing: border-box;
}
@if $css3 and $invalid {
/* For `other` browsers - not valid CSS 2.1 - yes valid CSS3. */
box-sizing: border-box;
}
@if not $invalid {
/* For `other` browsers - not valid CSS 2.1 - yes valid CSS3. */
/* box-sizing: border-box; */
}
}

</code>
-----------------------------------------------

Implementation details:

Development efficiency:

This methodology wouldn't be at all practical without using a decent
diff'ing tool. For those otherwise pitiable users stuck on windoze,
this is one niche where the platform offers a superior tool - I highly
recommend Winmerge. And personally I'd never work without version
control, even when flying solo.


Browser detection:

I've decided to implement the "browser sniffing" with enhance.js,
which actually uses feature detection to classify UA's into "good/
modern" browsers vs "old/crippled". These stylesheets listed here only
go to Grade A UAs, while a LITE.CSS delivers a simplified single-
column fluid design suitable for older handhelds, IE5 et al. Obviously
UA's without CSS capabilities get POSH.

The performance advantage of further engine-specific browser detection
(UA string sniffing is SO first-decade) would be pretty minor.
Therefore, out of this "Grade A / Full view" group, the only files I'm
currently planning to actually serve are IE6-7.CSS and SCREEN.CSS -
but the capability is there for those using a more traditional
browsers detection routine.

VALID.CSS is only for running through W3's validation service (good
for catching typos and missed hacks).


Future enhancements:

Within my "Full" design I plan to detect the viewport width and swap
out different versions of the layout accordingly; but that's
definitely Stage 2 for now.

iOS-targeting is left as an exercise for the reader (hint: don't use
media=handheld).

===============================================

Following redundant information for archive backup purposes only:

<code>

// IE6-7.CSS: $invalid: true; | $css3: false; | $ie6-7: true;
// $ie8-up: false; | $moz: false; | $webkit: false; |
$opera: false;
//
// SCREEN.CSS: $invalid: true; | $css3: true; | $ie6-7: false;
// $ie8-up: true; | $moz: true; | $webkit: true; |
$opera: true;
//
// VALID.CSS: $invalid: false; | $css3: false; | $ie6-7: true;
// $ie8-up: true; | $moz: true; | $webkit: true; |
$opera: true;
//
// IE8-UP.CSS $invalid: true; | $css3: true; | $ie6-7: false;
// $ie8-up: true; | $moz: false; | $webkit: false; |
$opera: false;
//
// GECKO.CSS. $invalid: true; | $css3: true; | $ie6-7: false;
// $ie8-up: false; | $moz: true; | $webkit: false; |
$opera: false;
//
// WEBKIT.CSS: $invalid: true; | $css3: true; | $ie6-7: false;
// $ie8-up: false; | $moz: false; | $webkit: true; |
$opera: false;
//
// OPERA.CSS: $invalid: true; | $css3: true; | $ie6-7: false;
// $ie8-up: false; | $moz: false; | $webkit: false; |
$opera: true;

</code>

HansBKK

unread,
Jul 17, 2010, 1:50:05 AM7/17/10
to Compass
Sorry, forgot to include the conditionals for the "OTHER.CSS",
intended for unidentified UAs:

// OTHER.CSS: $invalid: true; | $css3: true; | $ie6-7: false; |
// $ie8-up: false; | $moz: true; | $webkit: true; |
$opera: true;

I've left the Trident-specific rules out since conditional comments
ensure accurate identification of IE, as opposed to the less reliable
engine-detection routines for moz/webkit/opera. Unless anyone knows of
Trident-based UA's that don't obey CCs?

If I were using these browser-specific stylesheets, I would
periodically verify that OTHER.CSS was getting served to a tiny
percentage of visitors, and if that proportion grows, specifically
investigate making the sniffer script more accurate/inclusive.
Remember also that these "Full view design" styles are only being
delivered to Grade A browsers; lesser ones (and those supporting
media=handheld) are getting the "Lite / Mobile" design or POSH.

And finally, for those who are thinking this is a crazy amount of
trouble to go to just to avoid a few underscore or star hacks - you're
right! I usually code so that my design degrades gracefully, but for
those customers that want (and are willing to pay for the extra work
of) pretty-pixel cross-browser consistency, I want my toolset to
enable me to manage my code in a way that is as standard-compliant and
scalable as possible. The beauty of Compass is that it allows me to
keep all my (admittedly bloated) source code in one place, tweak/
troubleshoot a given pattern once and for all, and then compile any
number of (potentially very streamlined) alternative versions without
any extra work on subsequent projects.

Kudos to Chris and the rest of the team for enabling the insanity! 8-)

Chris Eppstein

unread,
Jul 17, 2010, 6:36:54 PM7/17/10
to compas...@googlegroups.com
Sorry, but I have to say that I don't like this -- browser detection is fundamentally flawed. I can't stop you from using it and promoting it, of course, and I can tell that you've put a lot of thought into it. But I think it's genuinely misguided approach.

Honestly, I can't imagine why you even need this. We crank out lovely designs all the time with almost no hacks or conditional css except those used in the compass mixins.

A much better approach, in my opinion, is to use http://www.modernizr.com/ with sass to scope rules according to detected features..

Alas, it would be awesome if CSS itself provided a feature query syntax. I ask for just such a thing on my blog here: http://chriseppstein.github.com/blog/2009/10/19/css-unsupported-directive/

Chris



--
You received this message because you are subscribed to the Google Groups "Compass" group.
To post to this group, send email to compas...@googlegroups.com.
To unsubscribe from this group, send email to compass-user...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/compass-users?hl=en.


David Gregory

unread,
Jul 17, 2010, 11:38:16 PM7/17/10
to compas...@googlegroups.com
Agreed, Modernizr uses feature detection instead of browser detection.. This is even more important than ever because the latest browsers are constantly adding more HTML5 and CSS3 features.   These wont be found if we do browser detection..  however since Modernizr is testing for those features, it's far more accurate to use.    

Even the conference I was in today.. someone was showing that a certain browser didn't have an particular HTML5 capability, but one the audience happened to be one of the programmers and said "did you get the newest version?  It came out last nite".  

The current browser development pace is far to active to rely on browser detection anymore; and this is a good thing!  

Dave.

HansBKK

unread,
Jul 25, 2010, 2:15:34 PM7/25/10
to Compass
Sorry I've taken so long to reply, but I feel compelled to address
some of the issues raised. Of course in an ideal world we would never
need to have different rule sets for different browsers, but in
certain situations it is necessary. For those who want to minimize
http requests by serving a single alternative stylesheet rather than
traditional incremental overrides, Compass allows their rules to be
maintained all in one place much more effectively and in compliance
with standards than other approaches.

Of course using classes on body or html (as Modernizr does) is a great
alternative when the differences between the rulesets are minor.

Regarding "browser detection" in general, the term is very broad one,
and as usual, the devil's in the details. For example, most consider
MS conditional comments to be a solid method for browser detection. On
the other hand, the current mainstream consensus is that the UA-string-
based methods (AKA traditional server-side "browser sniffing") aren't
a good idea, and in fact I specifically stated that I'm not planning
on using these myself - but I did work the possibility into my
variable matrix in case someone else does want to.

As both you and David pointed out, the current mainstream best
practice recommendation is to use "feature detection", especially in
handling the new/unknown browser issue, and in fact (as I did mention)
this is the exact methodology used by enhance.js. References for those
that want to check out the details:
http://www.alistapart.com/articles/testdriven
http://www.filamentgroup.com/lab/delivering_the_right_experience_to_the_right_device
http://ejohn.org/blog/progressive-css-enhancement
http://www.filamentgroup.com/lab/introducing_enhancejs_smarter_safer_apply_progressive_enhancement

While Modernizr specifically addresses only the forward-looking
implementation of CSS3 decorative styling, I am using enhance.js to
handle more basic issues of cross-browser consistency in layout and
application functionality, particularly in the handheld arena.

My main point here is the fact that Compass makes it easy to maintain
a single-source code base to output full-alternative stylesheets, as
opposed to the traditional unwieldy maintenance of incremental
override files. This is IMO a powerful and exciting concept,
independent of the technology used to implement what sheet gets
delivered to the client.

Finally, keep in mind that there are a lot of major sites out there
that do in fact do browser detection, and many clients are willing to
pay for (close to) pixel-perfect design consistency. Regardless of the
political correctness of the different applications, I think we should
promote Sass/Compass' value as a general enabling tool - too many
designers don't see the need, and if this is one "hook" that might get
a few more to look at it IMO why not?

But thanks for the feedback, I do realize it's best to keep the use of
these techniques to a minimum.


On Jul 18, 5:36 am, Chris Eppstein <ch...@eppsteins.net> wrote:
> Sorry, but I have to say that I don't like this -- browser detection is
> fundamentally flawed. I can't stop you from using it and promoting it, of
> course, and I can tell that you've put a lot of thought into it. But I think
> it's genuinely misguided approach.
>
> Honestly, I can't imagine why you even need this. We crank out lovely
> designs all the time with almost no hacks or conditional css except those
> used in the compass mixins.
>
> A much better approach, in my opinion, is to usehttp://www.modernizr.com/with
> sass to scope rules according to detected features..
>
> Alas, it would be awesome if CSS itself provided a feature query syntax. I
> ask for just such a thing on my blog here:http://chriseppstein.github.com/blog/2009/10/19/css-unsupported-direc...
>
> Chris

HansBKK

unread,
Jul 25, 2010, 4:36:11 PM7/25/10
to Compass
In going back through my notes on enhance.js, I noticed that Paul
Irish (Modernizr's author) has helped with it's continued development:

http://www.filamentgroup.com/lab/using_internet_explorer_conditional_comments_with_enhancejs/

and I didn't realize that John Resig (blog post above endorsing this
approach) is the original author of jQuery.



A little bit of research into that frameworks browser detection
methods showed that jQuery's been moving in the feature-detection
direction:
http://docs.jquery.com/Release:jQuery_1.3#No_More_Browser_Sniffing

but MooTools has recently gone the other way:
http://ajaxian.com/archives/mootools-call-to-upgrade

Again, I'm not advocating using these other methods, but thought the
additional info might be useful for those googling in the list later
on.
Reply all
Reply to author
Forward
0 new messages