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

  1. 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".
  2. Copy the existing style.css and delete everything that is not relevant, then replace the colors (and anything else you want to override).
  3. Save your new stylesheet as High_Contrast.css and put it in your theme directory - the filename must match the corresponding profile option.
  4. 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

anonymouscowards’s picture

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?

anonymouscowards’s picture

Solved via much trial and error.

For Drupal 5, replace:

theme_add_style($style_sheet);

with

drupal_add_css($style_sheet, 'theme','all');

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.

anonymouscowards’s picture

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 ;)

anonymouscowards’s picture

Managed to do this as well but it all seems very hacky...

  1. First create a custom block with appropriate title.
  2. No need to put any content in it.
  3. Next check the page source to find the automatically generated id. Mine was block-block-12.
  4. Next open your theme's default block.tpl.php file and save it as block-block-12.tpl.php or whatever the name of your custom block is. Add the link code shown in the snippet in the appropriate place within the block (without the styling of course).
  5. 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.

lugburz’s picture

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... ;)