Description
This snippet shows how to offer a link, effectively a switch, to allow users to turn-on additional styles via an additional stylesheet. In this example the additional sheet is called "High_Contrast.css" which brightens up fonts and darkens the backgrounds (effectively overriding certain styles in style.css
).
It works for anonymous users (via a cookie) and logged-in users (via a profile setting). My reason for doing this was because I wanted a dark design for it's visual effect, but it presented a problem for some users (one of the users being the site owner!).
The limitation of this script is that it is not able to replace style.css
, nor is it set up to allow more than one alternative.
Step 1 of 3 - Preparation
- Activate the profile module, and go to settings->profile and set up a new "list selection" field. Create two list options: "Default" and "High Contrast".
- Copy the existing
style.css
and delete everything that is not relevant, then replace the colors (and anything else you want to override). - Save your new stylesheet as
High_Contrast.css
and put it in your theme directory - the filename must match the corresponding profile option. - Save the new stylesheet in your theme folder.
Step 2 of 3 - template.php
Create a file called template.php
and add to it the code below. Save the file to your theme directory. Replace "MYTHEME" with the name of your theme.
<?php
/*
* Determine whether the 'high contrast' stylesheet should be added.
*/
function MYTHEME_page(&$content) {
if (isset($_COOKIE['theme_profile_changesheet'])) {
$style_sheet = drupal_get_path('theme','MYTHEME') .'/'.
$style_sheet .= _switcher_set_style($_COOKIE['theme_profile_changesheet']) .'.css';
setcookie('theme_profile_changesheet',FALSE);
}
else {
$style_sheet = drupal_get_path('theme','MYTHEME') .'/'. _switcher_get_style() .'.css';
}
if (file_exists($style_sheet)) {
theme_add_style($style_sheet);
}
//having overridden phptemplate_page(), we need to call it now.
return phptemplate_page($content);
}
/*
* Helper to SAVE the current selection to profile or cookie. */
*/
function _switcher_set_style($change_style) {
global $user;
// var_dump($user); die();
if (!$user->uid) {
setcookie('theme_profile_stylesheet', $change_style);
$_COOKIE['theme_profile_stylesheet']=$change_style;
}
else {
//hacked from user.module
$data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $user->uid)));
$data['profile_stylesheet'] = $change_style;
$query .= "data = '%s' ";
$v[] = serialize($data);
db_query("UPDATE {users} SET $query WHERE uid = %d", array_merge($v, array($user->uid)));
$user->profile_stylesheet = $change_style;
}
return $change_style;
}
/*
* Helper to LOAD the current selection from profile or cookie. */
*/
function _switcher_get_style() {
global $user;
if (!$user->uid) {
//check cookie for anonymous user
if (isset ($_COOKIE['theme_profile_stylesheet'])) {
$style_sheet = $_COOKIE['theme_profile_stylesheet'];
}
}
elseif (isset($user->profile_stylesheet)) {
//check profile setting for logged-in user
$style_sheet = str_replace(' ','_',$user->profile_stylesheet);
}
else {
//otherwise assume default (which will do nothing)
$style_sheet = 'Default';
}
return $style_sheet;
}
/*
* Create three variables for use in the template.
*/
function _phptemplate_variables($hook, $vars) {
$style_sheet = drupal_get_path('theme','MYTHEME') .'/'. _switcher_get_style() .'.css';
if (file_exists($style_sheet)) {
$change_sheet = 'Default';
$change_text = 'Normal'; //the 'turn-off' link will say "Normal"
}
else {
$change_sheet = 'High_Contrast';
$change_text = 'Bright'; //the 'turn-on' link will say "Bright"
}
//use javascript of the switch link that will set a change flag before the page is refreshed
$vars['style_switcher']['javascript'] = " onClick=\"document.cookie='theme_profile_changesheet=$change_sheet';\"";
$vars['style_switcher']['text'] = $change_text; //what the link will say
$vars['style_switcher']['self'] = $_SERVER['REQUEST_URI']; //link back to the current page.
return $vars;
}
?>
Step 3 of 3 - add bits to page.tpl.php
This piece of code is placed in your page.tpl.php
, or equivalent file. The style of the <div>
simply positions it in the top-right corner, but by stripping off the div tags, the output is just a link which can be placed anywhere.
<div style="position:absolute;top:0;right:0;z-index:10;"><a href="<?php print $style_switcher['self'] .'" '. $style_switcher['javascript'] .'>'. $style_switcher['text']; ?></a></div>
To conclude
On updating your files, you should be able to switch on your additional stylesheet by clicking the link. For an anonymous user, the setting persists while the browser is open. For a logged in user, the switch works the same, but the setting is recorded in their profile field and can be accessed via Account->Edit, and is therefore more persistent.
Comments
Drupal 5?
Thanks for this snippet, unfortunately I can't quite get it to work yet in Drupal 5.
First of all it seems that there are a few extra
*/
comments that are unwanted here:* Helper to SAVE the current selection to profile or cookie. */
and here:
* Helper to LOAD the current selection from profile or cookie. */
Secondly for Drupal 5 you have to replace theme_add_styles with drupal_add_css.
Now the basic functionality is working for me, unfortunately the cascading order is wrong. What I mean is that the High Contrast stylesheet is loading before the main style sheet and so cannot overide any of the styles.
Does anyone know how I can change this?
Hallelujah!
Solved via much trial and error.
For Drupal 5, replace:
with
Just having drupal_add_css($style_sheet) was adding the High contrast stylesheet before the main theme stylesheet.
I'm using this snippet to provide fixed and fluid width options.
Hope this helps someone.
New question!
Ok so my new question is how can I access this snippet from a block?
Instead of having the links that activate the snippet in page.tpl.php I want to use them in a specific block.
Anyone?!
I get the impression I'm talking to myself here... nevermind ;)
Done.
Managed to do this as well but it all seems very hacky...
Ugly but worked for me.
Correct me if I'm wrong but it seems the only way you can pass specific variables to a block is by setting them up in the template.php via _phptemplate_variables and then accessing them directly in a block.tpl.php file.
Any refinement of this/easier way would be great.
using a block
hello
I wanted to make something similar to add style on the fly, but I developped a module instead, thus providing a block for the switch link.
I'm using the profile module, too, but no cookies, so this is available only for registered users. But then I don't have to use javascript.
I've just requested a cvs account for this module today, so wait and see. As it seems that optional css is not a so weird idea after all, I may get my cvs access... ;)