06 Jan 2012In a pure OOCSS style of writing CSS, let's imagine you created a css class of .button
that visually turns a simple link into a button.
<a href="#" class="button">I'm a button</a>
Now, if you want to define a custom version of your button, let's say a button that will trigger a very dangerous action, you might want to style it differently, so our user will think twice before hitting it.
You got two ways of achieving this, depending if you still support IE6 or not.
Simple way for non-IE6
If you don't care about IE6 (and hell, it's 2012, you shouldn't), you just have to add a second class to your button/link :
<a href="#" class="button dangerous">I'm a dangerous button</a>
And in your CSS file, just define some special styles (like a red background
) to your dangerous button.
.button.dangerous { ... }
Actually, that's the path followed by Bootstrap(among others). But it will not correctly work in IE6, because it does not understand multiple classes rules. Instead, IE6 will read .button.dangerous {}
the same as .dangerous {}
.
This will cause problems as soon as you'll use the .important
class on something else than a .button
: IE will apply the .button.dangerous
rules to anything with the .dangerous
class.
Other way, for IE6
The solution I personnaly use to fix IE6 is to use more explicit classes instead of using multiple ones. For example, instead of .button.dangerous {}
I'll use .buttonDangerous {}
and write my html like this :
<a href="#" class="button buttonDangerous">I'm a dangerous button, even on IE6</a>
That way, the link will have both the styles of .button
and .buttonDangerous
. This will assure cross compatibility with IE6, at the expense of a (arguably) less readable markup.
As of today, I hope that I'll never have to code for IE6 websites again, but if you ever need to, that's a little trick that can really help.
05 Jan 2012This post will be the first of what I hope will be a long serie of posts. I'll blog about some of the little tricks I've learn in the past years that make me go faster on my daily job.
I'll start with something I can no longer work without : my global hotkeys.
The concept is pretty simple, I've binded some keys combinations to launch specific applications or directories. It might not seem very important, but it does make you gain a tremendous amount of time for those apps you launch pretty often like browser, IDE, or project directory.
I used to work on Windows, and I then used a little script named AutoHotKey to bind my keys. The script even comes packaged with its own language if you ever want to script complicated stuff.
I'm now working under Ubuntu, and the global hotkeys can be defined directly from the System Settings (in 11.10 it's System Settings > Keyboard > Shortcuts > Custom Shortcuts
)
Opening apps
I choose a key combination hard enough to type so I won't type it by mistake, but easy enough to remember that I could type it whenever I want.
For example, I binded all the app I use the most to a Ctrl+Win+{Letter}
combination. Ctrl+Win+C
opens Chromium, Ctrl+Win+F
opens Firefox, Ctrl+Win+T
opens Trillian, etc.
Opening folders
I used a close combination for opening directories : Ctrl+Win+Alt+{Letter}
. Those three keys are side by side on most keyboards so pressing them is easy.
This time I used the letter H
for my home folder, D
for the Dropbox folder, W
for /var/www
, etc, etc.
I've tweaked my keyboard in a few other ways, but this will be the subject of another post. Hope this one gave you some ideas.
04 Jan 2012Yesterday, I've tried to install nodejs and the jshint package to add automatic jshint parsing to my vim.
Well, it wasn't so simple due to a bug in the npm version shipped with node.
Here are the complete commands to run to make it work, in case I had to do it again :
# Download and extract node
cd ~/local/src
wget http://nodejs.org/dist/v0.6.6/node-v0.6.6.tar.gz
tar xvzf node-v0.6.6.tar.gz
rm node-v0.6.6.tar.gz
# Compile and install
cd node-v0.6.6
./configure
make
sudo make install
# Update npm
sudo npm install npm@alpha -g
# (Optional) Clear npm cache
npm cache clean jshint
# Install jshint
sudo npm install jshint -g
Source : https://github.com/isaacs/npm/issues/1888
04 Jan 2012When browsing the web, you might have seen a "mixed content warning" popup show in your browser. They are most of the time poorly worded and their meaning is quite obscure.
What it means is that your are currently browsing a page with both http
and https
content. Typically, if your page is https
but one of the css, js or image file it contains is requested through http
, the warning will pop.
(It's interesting to note here that not all assets are treated equal. Loading a flash movie through http
does not trigger the warning).
The IE special case
Now, what's special about IE is that it also trigger the mixed content warning when content is the other way around. If you're serving a page through http
and load assets through https
, it will consider it a mixed content too.
In a sense, that's logical, but it needlessly prompt the user with a dialog that block downloading of all https
assets until confirmed.
The solution is to make sure that all your assets are loaded with the same protocol as the host page. An easy way to do so is to use the //
relative protocol url. This will use http
or https
automatically based on the page protocol.
And adding Facebook to the mix
A few months ago, Facebook forced all apps to serve content through https
. In the meantime, they suggested that all their users browse their website using https
too.
Unfortunatly for us, some of our own users had bookmarks in their browsers and Facebook pages referencing our old http://apps.facebook.com/appname/ url. And following that link triggered the dreaded mixed content warning in IE.
When accessing this page, Facebook was loaded in classic http
but our inner iframe was loaded through https
. So far, so good.
The problem came from one of Facebook own javascript SDK included in our app. This script loaded other scripts based on what it needed.
Unfortunatly, it loaded the other scripts from an http
(not https
) server. The SDK has two distinct sets of urls, based on the current page protocol.
It was wrongly considering being in an http
page, not an https
one, and thus used the wrong set of urls. This confusing comes from the fact that it checks the top page protocol instead of checking the current page protocol.
After some googling, I found a solution that consisted in forcing the SDK to consider that we are in https
mode by calling : FB._https = true
before the call toFB.init()
Almost there
If correctly forced FB to use the correct set of urls, thus removing the mixed content warning. And I almost thought it would be that easy.
It was not.
This did not fixed the payment popup. All Facebook UI element loaded correctly (feeds, permissions, requests), but the payment popup.
I couldn't find a way to fix that, so I reverted to a more brutal approach.
Final and brutal solution
All my problems came from the fact that FB thought we were serving http
while in fact we were serving https
. So the solution, might be to force FB to serve https
from start to end.
I wanted to detect if the page was loaded through http://apps.facebook.com/appname/ or https://apps.facebook.com/appname/.
Unfortunatly, due to cross domain restrictions in Javascript, we are not able to read, from inside and iframe, the parent frame properties. So I couldn't read top.location.protocol
to easily check if I needed to redirect.
But, as I mentionned earlier, FB._https
incorrectly report that we are not in https
because it checks the top protocol. So I used this var, to know if the parent frame was in the correct protocol or not. Using this own FB bug to fix itself.
Now, for the redirect : even if I couldn't read thetop.location
, I could modify it. I just had to call top.location.url = 'https://apps.facebook.com/appname/'
to redirect the whole page.
I hardcoded the app url because there was no way to get it from js, and I took care of keeping any GET parameter passed before the redirect, and I ended up with this :
if (!FB._https) {
var appUrl = 'https://apps.facebook.com/appname/';
var iframeUrl = location.protocol+'//'+location.host+location.pathname;
var redirectUrl = location.href.replace(iframeUrl, appUrl);
top.location.href = redirectUrl;
return;
}
FB.init(options);
Conclusion
I'm not really proud of this solution, as it is mostly a hack and will force a useless loading of the http version before loading the https one, but that's the best I've found. If any of you have a better solution, feel free to comment.
02 Dec 2011Just found this weird little behavior of PHP today :
<?php
$a = false;
$b = true;
$c = $a OR $b;
$d = ($a OR $b);
var_dump(compact('a', 'b', 'c', 'd'));
?>
array(4) {
["a"]=> bool(false)
["b"]=> bool(true)
["c"]=> bool(false)
["d"]=> bool(true)
}
$a OR $b
in fact returns $a
, while ($a OR $b)
returns the result of the parenthesis. On the other hand, $a || $b
correctly returns the result of the expression.
It seems that AND
and OR
are weak compared to &&
and ||
.
Be aware of that, or it might backfire on you. Or just discard all AND
/ OR
in favor of &&
/||