Welcome to the new HowToJoomla!

We've completely revamped the design to make the site easier to read and easier to navigate. We hope you like the changes!

How to Use Dynamic CSS in Your Joomla Extension

February 09, 2010 | by Brian Edgerton | 2 Comments

Something I have run into frequently during module development is the need to allow multiple instances of that module on a single page. Joomla!, of course, handles 99% of the work involved, but there are a few tricky aspects to making this work. One is the need to eliminate styling conflicts, especially in themed modules. If you only use generic classes and then load multiple theme/color stylesheets, the end result can be unpredictable to say the least.

  # Very simple module output from modules/mod_mymod/mymod.php
  $color = $params->get('color', 'gray');
  $css_file = $color.'css';
 
  $document = JFactory::getDocument();
  $document->addStylesheet('modules/mod_mymod/css/base.css');
  $document->addStylesheet('modules/mod_mymod/css/'.$css_file);
 
  echo "<div class='mymod_class'>";
  echo "<p class='mymod_sub_class'>Here is some text that will go in this module.</p>";
  echo "</div>";
 

The included stylesheets may contain declarations like:

  /* base.css */
  div.mymod_class {
    position:relative;
    width:100%;
    height:300px;
    border:1px solid #000000;
  }
  p.mymod_sub_class {
    font-style:italic;
  }
 
  /* gray.css */
  div.mymod_class {
    border-color:#dedede;
    color:#7f7f7f;
  }
  p.mymod_sub_class {
    color:#7f7f7f;
  }
 

The above example code will work nicely for a single instance. The problem, however, shows up when you create a copy of the module and choose "red" as the color. When red.css is loaded, it will be identical to gray.css except for the color choices. The stylesheet loaded second (we'll say red) will override the first (gray) and both modules will inherit its styles. So, how do we solve this problem? The answer is with a dynamic stylesheet. We are going to use some simple PHP to differentiate between the module instances.

  # Very simple module output from modules/mod_mymod/mymod.php
 
  # $module contains data about current module -- available automatically
  $module_id = $module->id;
 
  $color = $params->get('color', 'gray');
  $css_file = $color.'css.php';
 
  $document = JFactory::getDocument();
  $document->addStylesheet('modules/mod_mymod/css/base.css.php?id='.$module_id);
  $document->addStylesheet('modules/mod_mymod/css/'.$css_file.'?id='.$module_id);
 
  echo "<div id='mymod_id_".$module_id."' class='mymod_class'>";
  echo "<p class='mymod_sub_class'>Here is some text that will go in this module.</p>";
  echo "</div>";
 
  /* base.css.php */
  <?php 
    # Explicitly declare the type of content
    header("Content-type: text/css");
    # Grab module id from the request
    $module_id = $_GET['id']; 
  ?>
  div#mymod_id_.mymod_class {
    position:relative;
    width:100%;
    height:300px;
    border:1px solid #000000;
  }
  #mymod_id_ p.mymod_sub_class {
    font-style:italic;
  }
 
  /* gray.css */
  div#mymod_id_.mymod_class {
    border-color:#dedede;
    color:#7f7f7f;
  }
  #mymod_id_  {
    color:#7f7f7f;
  }
 

If you are a little confused don't worry. First of all, we need a way to uniquely identify our module. Our module already has a unique database ID that can be accessed from the $module object. We can use that to generate a unique div ID. The trick is that we have renamed our CSS files to PHP files and passed them our unique ID through the URL.

The css.php files now contain a couple of lines that declare the content type and pull the unique ID from the URL. That value is then used throughout the stylesheet to construct the names of the unique div ID's. Let's say our $module->id is 47. Then, if you view your source code, some of the out put will look like this:

  <link rel="stylesheet" type="text/css" href="modules/mod_mymod/css/gray.css.php?id=47" />
  ...
  <div id='mymod_id_47' class='mymod_class'>
    <p class='mymod_sub_class'>Here is some text that will go in this module.</p>
  </div>
  ...
  /* From gray.css.php */
  div#mymod_id_47.mymod_class {
    border-color:#dedede;
    color:#7f7f7f;
  }
  #mymod_id_47  {
    color:#7f7f7f;
  }
 

If you create a second instance of the module, it may have a $module->id of 52. In this case, all the above code will be output again, except all 47's will be replaced with 52. If we choose the red theme for the second module, all the red styles will be specific to #mymod_id_52 just like all the gray styles were specific to #mymod_id_47. You can see that we were able to prevent the styles from conflicting by ensuring that each set of stylesheets applied to only a single instance of a module.

This technique is obviously not limited to Joomla! development. It can be used in many different situations, but I have found it quite helpful in Joomla! module development. This approach will also work for producing dynamic Javascript files, but we will save that for another day. The idea is basically the same. Have fun with this little tip. I hope you've found it helpful.

About the Author

Brian EdgertonBrian Edgerton is a full time web developer born, raised, and currently residing in Burlington, North Carolina. A Computer Science major in college, he developed a curiosity for all things electronic at a young age. When he is not furiously coding away in front of his computer, Brian enjoys sports, movies, books, and falling asleep in his recliner. Brian is a Zend Certified PHP5 Engineer. He is also currently working on a Master's of Software Engineering degree through Auburn University. In addition to PHP, Brian is also proficient in Javascript and CSS/XHTML and likes to pretend he knows a few things about Linux server administration as well.

You can check out Brian's website at EdgeWebWorks.com or follow him on Twitter @brian_edgerton.

Read More

Trackback(0)

Comments (2)Add Comment

1524
Small addition...
written by Joseph LeBlanc, February 10, 2010
Great article! That's a good solution for getting around multiple module instances using the same resources. The only change I would make would be to filter that input coming from $_GET. Anyone in the world can put any value for 'id'; potentially hijacking your CSS file to do their bidding. While header("Content-type: text/css"); should appropriately limit how a browser will interpret your file, it's better to be safe than sorry. I would do this:

$module_id = (int) $_GET['id'];
1335
Thanks
written by Brian Edgerton, February 10, 2010
Thanks for the suggestion and that is definitely a good idea.

Write comment

You must be logged in to post a comment. Please register if you do not have an account yet.

busy